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

Kotlin中对象表达式扩展CountDownTimer抽象类后新增方法无法访问的问题

问题原因与解决方案

你遇到的这个“未解析引用”错误,核心原因是Kotlin对象表达式的类型推断规则:当你用var sequencetimer = object : CountDownTimer(...) { ... }声明变量时,编译器会自动将sequencetimer的静态类型推断为父类CountDownTimer,而非你创建的匿名子类。尽管这个匿名子类确实包含了你新增的pauseTimer()、resumeTimer()和timeremaining,但由于变量的静态类型是父类,编译器只能识别父类中存在的方法和属性,因此会抛出未解析引用的错误。

另外,你的代码还有一个隐藏bug:CountDownTimer调用cancel()后,再次调用start()会重新从初始时长(30秒)开始,而非剩余时间,所以原有的resumeTimer()逻辑是不生效的。

下面给出两种可行的解决方案:

方案1:定义接口+交集类型(推荐)

这种方式既规范,又能同时保留父类方法和自定义方法的访问权限:

  1. 首先在Activity中定义一个包含自定义方法和属性的接口:
interface TimerControls {
    var timeremaining: Long
    fun pauseTimer()
    fun resumeTimer()
}
  1. 修改sequencetimer的声明,让对象表达式同时继承CountDownTimer并实现TimerControls,同时显式指定变量类型为CountDownTimer & TimerControls(交集类型,代表变量同时拥有两个类型的所有成员):
public var sequencetimer: CountDownTimer & TimerControls = object : CountDownTimer(30000, 1000), TimerControls {
    override var timeremaining: Long = 0

    override fun onTick(millisUntilFinished: Long) {
        findViewById<TextView>(R.id.textView8).apply {
            text = "seconds remaining: ${millisUntilFinished / 1000}"
        }
        // 实时更新剩余时间,避免从TextView解析字符串的风险
        timeremaining = millisUntilFinished
    }

    override fun onFinish() {
        findViewById<TextView>(R.id.textView8).text = "done"
    }

    override fun pauseTimer() {
        cancel()
    }

    override fun resumeTimer() {
        // 由于CountDownTimer不可复用,resume时需要用剩余时间创建新实例
        sequencetimer = object : CountDownTimer(timeremaining, 1000), TimerControls {
            override var timeremaining: Long = this@sequencetimer.timeremaining

            override fun onTick(millisUntilFinished: Long) {
                findViewById<TextView>(R.id.textView8).apply {
                    text = "seconds remaining: ${millisUntilFinished / 1000}"
                }
                timeremaining = millisUntilFinished
            }

            override fun onFinish() {
                findViewById<TextView>(R.id.textView8).text = "done"
            }

            override fun pauseTimer() {
                cancel()
            }

            override fun resumeTimer() {
                // 复用相同的resume逻辑
                sequencetimer = object : CountDownTimer(timeremaining, 1000), TimerControls by this {
                    override var timeremaining: Long = this@sequencetimer.timeremaining
                    override fun onTick(millisUntilFinished: Long) {
                        findViewById<TextView>(R.id.textView8).apply {
                            text = "seconds remaining: ${millisUntilFinished / 1000}"
                        }
                        timeremaining = millisUntilFinished
                    }
                }
                sequencetimer.start()
            }
        }
        sequencetimer.start()
    }
}
  1. 现在你可以正常在onPause和onResume中调用自定义方法了:
override fun onPause() {
    super.onPause()
    sequencetimer.pauseTimer()
}

override fun onResume() {
    super.onResume()
    sequencetimer.resumeTimer()
}

方案2:提取自定义子类(更直观)

如果觉得接口+交集类型有点复杂,也可以直接定义一个继承自CountDownTimer的自定义子类,这样变量类型就是这个子类,自然能访问所有自定义成员:

class ResumableCountDownTimer(
    millisInFuture: Long,
    countDownInterval: Long,
    private val textView: TextView
) : CountDownTimer(millisInFuture, countDownInterval) {
    var timeremaining: Long = millisInFuture

    override fun onTick(millisUntilFinished: Long) {
        textView.text = "seconds remaining: ${millisUntilFinished / 1000}"
        timeremaining = millisUntilFinished
    }

    override fun onFinish() {
        textView.text = "done"
    }

    fun pauseTimer() {
        cancel()
    }

    fun resumeTimer(): ResumableCountDownTimer {
        return ResumableCountDownTimer(timeremaining, 1000, textView).apply { start() }
    }
}

然后在Activity中使用这个子类:

private lateinit var sequencetimer: ResumableCountDownTimer

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.your_layout)
    val textView = findViewById<TextView>(R.id.textView8)
    sequencetimer = ResumableCountDownTimer(30000, 1000, textView).apply { start() }
}

override fun onPause() {
    super.onPause()
    sequencetimer.pauseTimer()
}

override fun onResume() {
    super.onResume()
    sequencetimer = sequencetimer.resumeTimer()
}

这个方案代码更清晰,也更容易维护,适合需要多次复用的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 16:52:46