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

CountDownTimer暂停恢复导致进度条负数问题求助

解决CountDownTimer暂停恢复后进度条负数问题

问题根源

  1. 回调延迟导致误差累积:系统调度延迟会让onTick回调不精准,暂停时直接cancel并记录理论剩余时间,恢复后累计误差会让剩余时间计算出现负数。
  2. 剩余时间记录不精准:暂停时未基于最新onTick回调值更新剩余时间,而是用初始计算值,导致恢复后倒计时逻辑偏离实际时长。
  3. 无数值边界校验:更新进度条时未判断数值是否小于0,直接赋值导致负数显示。

修复方案

自定义可暂停恢复的倒计时器,精准维护剩余时间,同时给进度条数值加边界校验:

自定义可暂停倒计时器代码

class PausableCountDownTimer(
    private val totalMillis: Long,
    private val intervalMillis: Long,
    private val onTickAction: (remaining: Long) -> Unit,
    private val onFinishAction: () -> Unit
) {
    private var remainingMillis = totalMillis
    private var isPaused = false
    private var internalTimer: CountDownTimer? = null

    // 启动/重启倒计时
    fun start() {
        isPaused = false
        internalTimer?.cancel()
        internalTimer = object : CountDownTimer(remainingMillis, intervalMillis) {
            override fun onTick(millisUntilFinished: Long) {
                if (!isPaused) {
                    remainingMillis = millisUntilFinished
                    onTickAction.invoke(remainingMillis)
                }
            }

            override fun onFinish() {
                remainingMillis = 0
                onFinishAction.invoke()
            }
        }.start()
    }

    // 暂停倒计时
    fun pause() {
        isPaused = true
        internalTimer?.cancel()
    }

    // 恢复倒计时
    fun resume() {
        if (isPaused && remainingMillis > 0) {
            start()
        }
    }

    // 重置倒计时
    fun reset() {
        internalTimer?.cancel()
        remainingMillis = totalMillis
        isPaused = false
    }
}

页面使用示例

class TimerActivity : AppCompatActivity() {
    private lateinit var timerProgress: ProgressBar
    private lateinit var pausableTimer: PausableCountDownTimer
    // 总时长60秒,间隔1秒更新
    private val TOTAL_TIME = 60000L
    private val UPDATE_INTERVAL = 1000L

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_timer)
        timerProgress = findViewById(R.id.timer_progress)
        timerProgress.max = (TOTAL_TIME / 1000).toInt()

        // 初始化自定义倒计时器
        pausableTimer = PausableCountDownTimer(TOTAL_TIME, UPDATE_INTERVAL,
            onTickAction = { remaining ->
                val progress = (remaining / 1000).toInt()
                // 强制进度不小于0,避免负数显示
                timerProgress.progress = maxOf(progress, 0)
            },
            onFinishAction = {
                timerProgress.progress = 0
                Toast.makeText(this, "倒计时结束", Toast.LENGTH_SHORT).show()
            }
        )

        // 绑定按钮事件
        findViewById<Button>(R.id.btn_start).setOnClickListener { pausableTimer.start() }
        findViewById<Button>(R.id.btn_pause).setOnClickListener { pausableTimer.pause() }
        findViewById<Button>(R.id.btn_resume).setOnClickListener { pausableTimer.resume() }
        findViewById<Button>(R.id.btn_reset).setOnClickListener { pausableTimer.reset() }
    }

    override fun onDestroy() {
        super.onDestroy()
        pausableTimer.reset()
    }
}

关键优化点

  • 精准维护剩余时间:每次onTick回调时更新remainingMillis,确保暂停时记录的是最新剩余时长。
  • 暂停时终止计时器:暂停时cancel内部的CountDownTimer,避免后台回调干扰剩余时间计算。
  • 边界校验:更新进度条时用maxOf(progress, 0)强制数值不小于0,彻底解决负数显示问题。

内容的提问来源于stack exchange,提问作者Chayan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 20:22:36