如何在Compose的VerticalPager中用AndroidView的onReset复用ExoPlayer并解决OOM
在Jetpack Compose VerticalPager中复用ExoPlayer解决内存溢出问题
你的代码出现内存溢出主要是因为播放器资源未正确释放、重复创建不必要的对象、PlayerView与ExoPlayer的绑定逻辑混乱这几个问题,结合VerticalPager的回收机制,调整方案如下:
核心问题分析
- ExoPlayer实例管理混乱:多个PlayerView绑定同一个
exoPlayer实例,且未在视图回收时解绑释放,导致播放器资源一直占用内存。 - 重复创建对象:
onReset中每次都新建DataSourceFactory,大量重复对象堆积引发内存问题。 - onRelease未做实质释放:仅打印日志,未处理PlayerView与播放器的解绑及资源回收。
调整后的实现代码
// 在Compose组件中,用remember持有复用的DataSourceFactory,避免重复创建 val dataSourceFactory = remember { val defaultDataSourceFactory = DefaultDataSource.Factory(LocalContext.current) DefaultDataSource.Factory(LocalContext.current, defaultDataSourceFactory) } // 为VerticalPager的每个item设置唯一key,确保AndroidView的onReset正确触发 VerticalPager( count = videoList.size, key = { videoList[it].id } // 替换为你的视频唯一标识 ) { index -> val video = videoList[index] AndroidView( factory = { context -> Logger.d { "PlayerView factory created" } // 为每个PlayerView创建独立的ExoPlayer实例 val player = ExoPlayer.Builder(context).build().apply { repeatMode = REPEAT_MODE_ONE } PlayerView(context).apply { hideController() useController = false this.player = player resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) clipToOutline = true // 把Player和View绑定存储,方便后续reset和release tag = player } }, onReset = { playerView -> Logger.d { "PlayerView reset for video: ${video.url}" } val player = playerView.tag as ExoPlayer // 先清理之前的播放状态 player.stop() player.clearMediaItems() // 设置新的媒体源 val source = ProgressiveMediaSource.Factory(dataSourceFactory) .createMediaSource(MediaItem.fromUri(video.url)) player.setMediaSource(source) player.prepare() }, onRelease = { playerView -> Logger.d { "PlayerView factory released" } val player = playerView.tag as ExoPlayer // 彻底释放播放器资源 player.stop() player.release() playerView.player = null } ) }
关键调整点说明
- 复用DataSourceFactory:用
remember持有工厂实例,避免每次onReset都创建新对象,减少内存开销。 - 独立ExoPlayer实例:每个PlayerView绑定独立的ExoPlayer,避免多个视图共享实例导致的资源冲突,同时在onRelease中彻底释放。
- 设置Pager的item唯一key:确保VerticalPager回收视图时,触发AndroidView的onReset而非重新创建factory,真正实现视图复用。
- 完善资源释放逻辑:onRelease中解绑PlayerView与播放器,调用
release()释放播放器的所有资源,避免内存泄漏。 - 重置播放状态:onReset中先停止播放、清空媒体项,再设置新的媒体源,避免状态混乱。
内容的提问来源于stack exchange,提问作者Amal
相关产品推荐
相关产品推荐

