Android VideoView搭配自定义SeekBar跳转后播放位置回退时间显示异常
问题根因
- 原生VideoView依赖的MediaPlayer
seekTo方法是异步执行,且默认仅支持seek到视频关键帧:你调用seekTo后立即读取currentPosition,返回的是你传入的目标进度值,但底层解码模块会自动将进度对齐到目标位置之前的最近关键帧,等seek操作真正完成后,currentPosition就会被更新为对齐后的关键帧位置,就出现了你日志里进度回退的现象。 - 现有代码逻辑顺序错误:
onProgressChanged中你先读取currentPosition更新时间显示,再执行seekTo操作,此时读取的进度本身就是seek之前的旧值,进一步加大了显示误差。
修复方案
方案1:适配原生VideoView的seek逻辑(修改最小)
- 调整
onProgressChanged执行顺序,优先执行seek,且用SeekBar的进度直接计算显示时间,不要读取未完成seek的currentPosition - 给VideoView添加
OnSeekCompleteListener,等seek操作完成后再同步更新进度和时间显示 - 定时更新任务增加进度合法性校验,仅更新不小于上一次进度的合法值(正常播放场景进度只会递增)
1. 添加全局变量记录上一次合法进度
private var lastValidPosition = 0
2. 调整SeekBar监听逻辑
binding.progressBarVideo.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { if (underSeek && fromUser) { // 直接用SeekBar的进度显示,不用此时未完成seek的VideoView位置 binding.textViewTime.text = durationToFormat(progress) binding.videoViewF.seekTo(progress) lastValidPosition = progress } } override fun onStartTrackingTouch(seekBar: SeekBar?) { mainHandler.removeCallbacks(updateTextTask) underSeek = true } override fun onStopTrackingTouch(seekBar: SeekBar?) { mainHandler.post(updateTextTask) underSeek = false hideTimer = 0 } })
3. 添加Seek完成监听
binding.videoViewF.setOnSeekCompleteListener { // seek完成后同步最新位置到UI val realPosition = binding.videoViewF.currentPosition binding.textViewTime.text = durationToFormat(realPosition) binding.progressBarVideo.progress = realPosition lastValidPosition = realPosition }
4. 调整定时更新任务逻辑
private val updateTextTask = object : Runnable { override fun run() { val currentPos = binding.videoViewF.currentPosition // 仅更新大于等于上一次合法值的进度,避免异常回退显示 if (currentPos >= lastValidPosition || binding.videoViewF.isPlaying.not()) { binding.textViewTime.text = durationToFormat(currentPos) binding.progressBarVideo.progress = currentPos lastValidPosition = currentPos } mainHandler.postDelayed(this, 1000) } }
方案2:替换为ExoPlayer(彻底解决seek精度问题)
原生VideoView的seek限制是系统底层实现导致的,如果需要支持精确到任意帧的seek,直接替换为Google官方ExoPlayer即可,ExoPlayer默认支持非关键帧精确seek,不会出现进度回退问题。
内容的提问来源于stack exchange,提问作者Dim
相关产品推荐
相关产品推荐

