Resolve the memory leaks in demo short-form app

Issue: androidx/media#1839
#cherrypick
PiperOrigin-RevId: 696080063
This commit is contained in:
tianyifeng 2024-11-13 04:38:14 -08:00 committed by Copybara-Service
parent 9db66d6c6b
commit c3d4722197
3 changed files with 28 additions and 19 deletions

View File

@ -85,6 +85,8 @@
Composable UI elements to `demo-compose` utilizing Composable UI elements to `demo-compose` utilizing
`PlayPauseButtonState`, `NextButtonState`, `PreviousButtonState`, `PlayPauseButtonState`, `NextButtonState`, `PreviousButtonState`,
`RepeatButtonState`, `ShuffleButtonState`. `RepeatButtonState`, `ShuffleButtonState`.
* Resolve the memory leaks in demo short-form app
([#1839](https://github.com/androidx/media/issues/1839)).
* Remove deprecated symbols: * Remove deprecated symbols:
* Remove deprecated `AudioMixer.create()` method. Use * Remove deprecated `AudioMixer.create()` method. Use
`DefaultAudioMixer.Factory().create()` instead. `DefaultAudioMixer.Factory().create()` instead.

View File

@ -25,7 +25,7 @@ import androidx.viewpager2.widget.ViewPager2
class ViewPagerActivity : AppCompatActivity() { class ViewPagerActivity : AppCompatActivity() {
private lateinit var viewPagerView: ViewPager2 private lateinit var viewPagerView: ViewPager2
private lateinit var adapter: ViewPagerMediaAdapter private lateinit var onPageChangeCallback: ViewPager2.OnPageChangeCallback
private var numberOfPlayers = 3 private var numberOfPlayers = 3
private var mediaItemDatabase = MediaItemDatabase() private var mediaItemDatabase = MediaItemDatabase()
@ -40,23 +40,24 @@ class ViewPagerActivity : AppCompatActivity() {
Log.d(TAG, "Using a pool of $numberOfPlayers players") Log.d(TAG, "Using a pool of $numberOfPlayers players")
viewPagerView = findViewById(R.id.viewPager) viewPagerView = findViewById(R.id.viewPager)
viewPagerView.offscreenPageLimit = 1 viewPagerView.offscreenPageLimit = 1
viewPagerView.registerOnPageChangeCallback( }
override fun onStart() {
super.onStart()
val adapter = ViewPagerMediaAdapter(mediaItemDatabase, numberOfPlayers, applicationContext)
viewPagerView.adapter = adapter
onPageChangeCallback =
object : ViewPager2.OnPageChangeCallback() { object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
adapter.onPageSelected(position) adapter.onPageSelected(position)
} }
} }
) viewPagerView.registerOnPageChangeCallback(onPageChangeCallback)
}
override fun onStart() {
super.onStart()
adapter = ViewPagerMediaAdapter(mediaItemDatabase, numberOfPlayers, this)
viewPagerView.adapter = adapter
} }
override fun onStop() { override fun onStop() {
adapter.onDestroy() viewPagerView.unregisterOnPageChangeCallback(onPageChangeCallback)
viewPagerView.adapter = null
super.onStop() super.onStop()
} }
} }

View File

@ -43,7 +43,7 @@ class ViewPagerMediaAdapter(
private val currentMediaItemsAndIndexes: ArrayDeque<Pair<MediaItem, Int>> = ArrayDeque() private val currentMediaItemsAndIndexes: ArrayDeque<Pair<MediaItem, Int>> = ArrayDeque()
private var playerPool: PlayerPool private var playerPool: PlayerPool
private val holderMap: MutableMap<Int, ViewPagerMediaHolder> private val holderMap: MutableMap<Int, ViewPagerMediaHolder>
private var currentPlayingIndex: Int = C.INDEX_UNSET private val preloadControl: DefaultPreloadControl
companion object { companion object {
private const val TAG = "ViewPagerMediaAdapter" private const val TAG = "ViewPagerMediaAdapter"
@ -65,8 +65,10 @@ class ViewPagerMediaAdapter(
) )
.setPrioritizeTimeOverSizeThresholds(true) .setPrioritizeTimeOverSizeThresholds(true)
.build() .build()
preloadControl = DefaultPreloadControl()
val preloadManagerBuilder = val preloadManagerBuilder =
DefaultPreloadManager.Builder(context, DefaultPreloadControl()).setLoadControl(loadControl) DefaultPreloadManager.Builder(context.applicationContext, preloadControl)
.setLoadControl(loadControl)
playerPool = PlayerPool(numberOfPlayers, preloadManagerBuilder) playerPool = PlayerPool(numberOfPlayers, preloadManagerBuilder)
holderMap = mutableMapOf() holderMap = mutableMapOf()
preloadManager = preloadManagerBuilder.build() preloadManager = preloadManagerBuilder.build()
@ -76,6 +78,13 @@ class ViewPagerMediaAdapter(
preloadManager.invalidate() preloadManager.invalidate()
} }
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
playerPool.destroyPlayers()
preloadManager.release()
holderMap.clear()
super.onDetachedFromRecyclerView(recyclerView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerMediaHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerMediaHolder {
val view = val view =
LayoutInflater.from(parent.context).inflate(R.layout.media_item_view_pager, parent, false) LayoutInflater.from(parent.context).inflate(R.layout.media_item_view_pager, parent, false)
@ -128,14 +137,9 @@ class ViewPagerMediaAdapter(
return Int.MAX_VALUE return Int.MAX_VALUE
} }
fun onDestroy() {
playerPool.destroyPlayers()
preloadManager.release()
}
fun onPageSelected(position: Int) { fun onPageSelected(position: Int) {
currentPlayingIndex = position
holderMap[position]?.playIfPossible() holderMap[position]?.playIfPossible()
preloadControl.currentPlayingIndex = position
preloadManager.setCurrentPlayingIndex(position) preloadManager.setCurrentPlayingIndex(position)
preloadManager.invalidate() preloadManager.invalidate()
} }
@ -168,7 +172,9 @@ class ViewPagerMediaAdapter(
preloadManager.remove(itemAndIndex.first) preloadManager.remove(itemAndIndex.first)
} }
inner class DefaultPreloadControl : TargetPreloadStatusControl<Int> { inner class DefaultPreloadControl(var currentPlayingIndex: Int = C.INDEX_UNSET) :
TargetPreloadStatusControl<Int> {
override fun getTargetPreloadStatus(rankingData: Int): DefaultPreloadManager.Status? { override fun getTargetPreloadStatus(rankingData: Int): DefaultPreloadManager.Status? {
if (abs(rankingData - currentPlayingIndex) == 2) { if (abs(rankingData - currentPlayingIndex) == 2) {
return DefaultPreloadManager.Status(STAGE_LOADED_FOR_DURATION_MS, 500L) return DefaultPreloadManager.Status(STAGE_LOADED_FOR_DURATION_MS, 500L)