From d921ffc95c8971c377a22ad66c6dd15ef0cc88b4 Mon Sep 17 00:00:00 2001 From: tianyifeng Date: Wed, 13 Nov 2024 04:38:14 -0800 Subject: [PATCH] Resolve the memory leaks in demo short-form app Issue: androidx/media#1839 PiperOrigin-RevId: 696080063 (cherry picked from commit c3d4722197fdc2b6f37e52d98c435e144b0262ab) --- RELEASENOTES.md | 3 +++ .../shortform/viewpager/ViewPagerActivity.kt | 21 ++++++++-------- .../viewpager/ViewPagerMediaAdapter.kt | 24 ++++++++++++------- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 687b08705f5..c7c2f1f3917 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -7,6 +7,9 @@ per sample. * Fix playback hanging on DASH multi-period streams when CEA-608 subtitles are enabled ([#1863](https://github.com/androidx/media/issues/1863)). +* Demo app + * Resolve the memory leaks in demo short-form app + ([#1839](https://github.com/androidx/media/issues/1839)). ## 1.5 diff --git a/demos/shortform/src/main/java/androidx/media3/demo/shortform/viewpager/ViewPagerActivity.kt b/demos/shortform/src/main/java/androidx/media3/demo/shortform/viewpager/ViewPagerActivity.kt index 8ac71dddd76..b3990e60574 100644 --- a/demos/shortform/src/main/java/androidx/media3/demo/shortform/viewpager/ViewPagerActivity.kt +++ b/demos/shortform/src/main/java/androidx/media3/demo/shortform/viewpager/ViewPagerActivity.kt @@ -25,7 +25,7 @@ import androidx.viewpager2.widget.ViewPager2 class ViewPagerActivity : AppCompatActivity() { private lateinit var viewPagerView: ViewPager2 - private lateinit var adapter: ViewPagerMediaAdapter + private lateinit var onPageChangeCallback: ViewPager2.OnPageChangeCallback private var numberOfPlayers = 3 private var mediaItemDatabase = MediaItemDatabase() @@ -40,23 +40,24 @@ class ViewPagerActivity : AppCompatActivity() { Log.d(TAG, "Using a pool of $numberOfPlayers players") viewPagerView = findViewById(R.id.viewPager) viewPagerView.offscreenPageLimit = 1 - viewPagerView.registerOnPageChangeCallback( - object : ViewPager2.OnPageChangeCallback() { - override fun onPageSelected(position: Int) { - adapter.onPageSelected(position) - } - } - ) } override fun onStart() { super.onStart() - adapter = ViewPagerMediaAdapter(mediaItemDatabase, numberOfPlayers, this) + val adapter = ViewPagerMediaAdapter(mediaItemDatabase, numberOfPlayers, applicationContext) viewPagerView.adapter = adapter + onPageChangeCallback = + object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + adapter.onPageSelected(position) + } + } + viewPagerView.registerOnPageChangeCallback(onPageChangeCallback) } override fun onStop() { - adapter.onDestroy() + viewPagerView.unregisterOnPageChangeCallback(onPageChangeCallback) + viewPagerView.adapter = null super.onStop() } } diff --git a/demos/shortform/src/main/java/androidx/media3/demo/shortform/viewpager/ViewPagerMediaAdapter.kt b/demos/shortform/src/main/java/androidx/media3/demo/shortform/viewpager/ViewPagerMediaAdapter.kt index b3c252cb6db..2a641a97019 100644 --- a/demos/shortform/src/main/java/androidx/media3/demo/shortform/viewpager/ViewPagerMediaAdapter.kt +++ b/demos/shortform/src/main/java/androidx/media3/demo/shortform/viewpager/ViewPagerMediaAdapter.kt @@ -43,7 +43,7 @@ class ViewPagerMediaAdapter( private val currentMediaItemsAndIndexes: ArrayDeque> = ArrayDeque() private var playerPool: PlayerPool private val holderMap: MutableMap - private var currentPlayingIndex: Int = C.INDEX_UNSET + private val preloadControl: DefaultPreloadControl companion object { private const val TAG = "ViewPagerMediaAdapter" @@ -65,8 +65,10 @@ class ViewPagerMediaAdapter( ) .setPrioritizeTimeOverSizeThresholds(true) .build() + preloadControl = DefaultPreloadControl() val preloadManagerBuilder = - DefaultPreloadManager.Builder(context, DefaultPreloadControl()).setLoadControl(loadControl) + DefaultPreloadManager.Builder(context.applicationContext, preloadControl) + .setLoadControl(loadControl) playerPool = PlayerPool(numberOfPlayers, preloadManagerBuilder) holderMap = mutableMapOf() preloadManager = preloadManagerBuilder.build() @@ -76,6 +78,13 @@ class ViewPagerMediaAdapter( preloadManager.invalidate() } + override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { + playerPool.destroyPlayers() + preloadManager.release() + holderMap.clear() + super.onDetachedFromRecyclerView(recyclerView) + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerMediaHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.media_item_view_pager, parent, false) @@ -128,14 +137,9 @@ class ViewPagerMediaAdapter( return Int.MAX_VALUE } - fun onDestroy() { - playerPool.destroyPlayers() - preloadManager.release() - } - fun onPageSelected(position: Int) { - currentPlayingIndex = position holderMap[position]?.playIfPossible() + preloadControl.currentPlayingIndex = position preloadManager.setCurrentPlayingIndex(position) preloadManager.invalidate() } @@ -168,7 +172,9 @@ class ViewPagerMediaAdapter( preloadManager.remove(itemAndIndex.first) } - inner class DefaultPreloadControl : TargetPreloadStatusControl { + inner class DefaultPreloadControl(var currentPlayingIndex: Int = C.INDEX_UNSET) : + TargetPreloadStatusControl { + override fun getTargetPreloadStatus(rankingData: Int): DefaultPreloadManager.Status? { if (abs(rankingData - currentPlayingIndex) == 2) { return DefaultPreloadManager.Status(STAGE_LOADED_FOR_DURATION_MS, 500L)