Kotlin中对象表达式扩展CountDownTimer抽象类后新增方法无法访问的问题
问题原因与解决方案
你遇到的这个“未解析引用”错误,核心原因是Kotlin对象表达式的类型推断规则:当你用var sequencetimer = object : CountDownTimer(...) { ... }声明变量时,编译器会自动将sequencetimer的静态类型推断为父类CountDownTimer,而非你创建的匿名子类。尽管这个匿名子类确实包含了你新增的pauseTimer()、resumeTimer()和timeremaining,但由于变量的静态类型是父类,编译器只能识别父类中存在的方法和属性,因此会抛出未解析引用的错误。
另外,你的代码还有一个隐藏bug:CountDownTimer调用cancel()后,再次调用start()会重新从初始时长(30秒)开始,而非剩余时间,所以原有的resumeTimer()逻辑是不生效的。
下面给出两种可行的解决方案:
方案1:定义接口+交集类型(推荐)
这种方式既规范,又能同时保留父类方法和自定义方法的访问权限:
- 首先在Activity中定义一个包含自定义方法和属性的接口:
interface TimerControls { var timeremaining: Long fun pauseTimer() fun resumeTimer() }
- 修改
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() } }
- 现在你可以正常在
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
相关产品推荐
相关产品推荐

