Jetpack Compose结合ExoPlayer使用时屏幕旋转导致视频重复播放问题
问题1(屏幕旋转多实例同步播放)修复
你标记的代码行确实是问题根源,核心原因有两点:
- 你用Activity Context作为
remember的key,屏幕旋转时Activity实例重建,context发生变化,触发remember重新执行,每次旋转都会新建一个ExoPlayerState实例 - 没有对旧的ExoPlayer实例做释放操作,旧实例一直在后台持有音频焦点播放
修复步骤
- 使用Application Context创建ExoPlayer,避免配置变更导致context变化触发实例重建
val exoPlayerState by remember { mutableStateOf(ExoPlayerState(context.applicationContext)) }
- 添加
DisposableEffect监听组合生命周期,在组件销毁或重建前释放ExoPlayer实例
DisposableEffect(Unit) { onDispose { exoPlayerState.exoPlayer.release() } }
如果需要旋转后无缝续播,可以在释放前将当前播放位置、播放状态存入rememberSaveable,新实例创建后直接seek到对应位置恢复播放即可。
3. 更稳定的可选方案:将ExoPlayer实例放到ViewModel中持有,ViewModel天然支持配置变更时留存,不会因为页面重建销毁实例,从根源避免多实例问题。
隐性问题修复
状态不自动更新问题
你当前的ExoPlayerState里的duration、bufferedPosition、position三个状态只会在初始化时赋值一次,后续不会跟着播放器状态自动同步:
- 首先将两个只读状态改为可写:
// 原来的val改为var var duration by mutableStateOf(exoPlayer.duration) var bufferedPosition by mutableStateOf(exoPlayer.bufferedPosition) var position by mutableStateOf(exoPlayer.currentPosition)
- 在播放监听中主动更新状态值:
override fun onPlaybackStateChanged(playbackState: Int) { when (playbackState) { Player.STATE_READY -> { exoPlayerState.duration = exoPlayerState.exoPlayer.duration Log.d("Player", "STATE_READY- duration: ${exoPlayerState.duration}") } } } override fun onPositionDiscontinuity( oldPosition: Player.PositionInfo, newPosition: Player.PositionInfo, reason: Int ) { exoPlayerState.position = exoPlayerState.exoPlayer.currentPosition exoPlayerState.bufferedPosition = exoPlayerState.exoPlayer.bufferedPosition }
监听泄漏问题
你当前每次sourceUrl变化时都会新增一个Player.Listener,没有移除旧监听会造成内存泄漏,建议在LaunchedEffect的退出回调中移除监听:
LaunchedEffect(sourceUrl) { val listener = object : Player.Listener { // 你的监听逻辑 } exoPlayerState.exoPlayer.addListener(listener) // 退出时移除监听 onDispose { exoPlayerState.exoPlayer.removeListener(listener) } // 剩余媒体源设置、准备逻辑 }
内容的提问来源于stack exchange,提问作者Saehun Sean Oh
相关产品推荐
相关产品推荐

