diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 8133765530..f2f22ab519 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -85,6 +85,8 @@ Composable UI elements to `demo-compose` utilizing `PlayPauseButtonState`, `NextButtonState`, `PreviousButtonState`, `RepeatButtonState`, `ShuffleButtonState`. + * Resolve the memory leaks in demo short-form app + ([#1839](https://github.com/androidx/media/issues/1839)). * Remove deprecated symbols: * Remove deprecated `AudioMixer.create()` method. Use `DefaultAudioMixer.Factory().create()` instead. 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 8ac71dddd7..b3990e6057 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( + } + + override fun onStart() { + super.onStart() + val adapter = ViewPagerMediaAdapter(mediaItemDatabase, numberOfPlayers, applicationContext) + viewPagerView.adapter = adapter + onPageChangeCallback = object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { adapter.onPageSelected(position) } } - ) - } - - override fun onStart() { - super.onStart() - adapter = ViewPagerMediaAdapter(mediaItemDatabase, numberOfPlayers, this) - viewPagerView.adapter = adapter + 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 b3c252cb6d..2a641a9701 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)