You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android VideoView搭配自定义SeekBar跳转后播放位置回退时间显示异常

问题根因
  • 原生VideoView依赖的MediaPlayer seekTo 方法是异步执行,且默认仅支持seek到视频关键帧:你调用seekTo后立即读取currentPosition,返回的是你传入的目标进度值,但底层解码模块会自动将进度对齐到目标位置之前的最近关键帧,等seek操作真正完成后,currentPosition就会被更新为对齐后的关键帧位置,就出现了你日志里进度回退的现象。
  • 现有代码逻辑顺序错误:onProgressChanged中你先读取currentPosition更新时间显示,再执行seekTo操作,此时读取的进度本身就是seek之前的旧值,进一步加大了显示误差。
修复方案

方案1:适配原生VideoView的seek逻辑(修改最小)

  1. 调整onProgressChanged执行顺序,优先执行seek,且用SeekBar的进度直接计算显示时间,不要读取未完成seek的currentPosition
  2. 给VideoView添加OnSeekCompleteListener,等seek操作完成后再同步更新进度和时间显示
  3. 定时更新任务增加进度合法性校验,仅更新不小于上一次进度的合法值(正常播放场景进度只会递增)

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 12:30:00