ExoPlayer2使用playWhenReady启停音频时currentPosition延迟问题求助
解决ExoPlayer暂停重启后currentPosition跳变的问题
从你的描述和日志来看,这个问题的核心是暂停播放时没有捕获到真正的最终暂停位置,再加上重启时播放器内部的同步延迟,导致获取到的currentPosition出现跳变,进而让进度条无法平滑更新。
问题原因拆解
- 当你设置
player!!.playWhenReady = false时,ExoPlayer不会立刻终止播放流程,可能还会播放缓冲内的几帧内容,这时候立刻读取的currentPosition并不是最终的暂停位置。 - 重启播放时,直接读取
player!!.currentPosition可能拿到的是播放器内部的缓存值,还没和实际播放进度同步,导致数值跳变。
解决方案
我们需要两个关键操作来解决这个问题:
- 暂停时,等待播放器真正进入暂停状态后,再记录准确的位置
- 重启播放前,手动将播放器进度跳转到暂停时记录的准确位置,再启动播放
修改后的代码示例
首先,添加一个变量来存储暂停时的准确位置:
private var pausedPosition: Long = 0L
然后修改暂停/播放的核心逻辑:
if (activeHolder!! == holder) { when (player!!.playWhenReady) { true -> { // 先临时记录当前位置,再监听播放器状态确认真正暂停 pausedPosition = player!!.currentPosition player!!.playWhenReady = false // 添加状态监听,确保播放器完全暂停后再更新UI和记录最终位置 player!!.addListener(object : Player.Listener { override fun onPlaybackStateChanged(state: Int) { super.onPlaybackStateChanged(state) if (state == Player.STATE_READY && !player!!.playWhenReady) { // 此时播放器已完全暂停,更新准确的暂停位置 pausedPosition = player!!.currentPosition showLog("实际暂停位置: $pausedPosition") handlerChangeProgress.removeCallbacks(updateChangeProgressTask) showAudioStartButton(activeHolder!!) // 移除监听避免内存泄漏 player!!.removeListener(this) } } }) return } false -> { // 重启前先跳转到记录的暂停位置,再启动播放 player!!.seekTo(pausedPosition) player!!.playWhenReady = true showLog("重启播放位置: $pausedPosition") handlerChangeProgress.postDelayed(updateChangeProgressTask, delayChangeProgress) showAudioStopButton(activeHolder!!) return } } }
同时优化进度条更新逻辑,暂停状态下直接用我们记录的位置更新:
override fun onChangeProgressBar(progress: Float, currentPosition: Int, totalDuration: Int) { if(player!!.playWhenReady) { if (activeHolder?.adapterPosition == audioPosition) { activeHolder?.let { it.binding.progressBar.max = totalDuration it.binding.progressBar.progress = currentPosition showAudioStopButton(it) } } } else { // 暂停状态时,用记录的准确位置更新进度条 activeHolder?.let { it.binding.progressBar.max = player!!.duration.toInt() it.binding.progressBar.progress = pausedPosition.toInt() showAudioStartButton(it) } } }
额外优化建议
- 可以提前定义一个全局的
Player.Listener实例,避免每次暂停都创建新对象,减少内存开销 - 在页面销毁时,记得移除所有播放器监听、清空handler的回调,避免内存泄漏
修改后,你的日志应该会显示暂停和重启的位置完全一致,进度条也能实现平滑的暂停-重启过渡。
内容的提问来源于stack exchange,提问作者Charles
相关产品推荐
相关产品推荐

