android Handler无法移除runnable。
比较老的解释就是因为messageQueue已经即将执行的不能被取消,这种我们很好理解它, 因为他已经在跑了,自然无法移掉。
但是在kotlin下有个大坑。
赶快来全局搜索检查你的removeCallbacks吧!
private val connectRunnable = {
//...
connect()
//...
}
mainHandler.removeCallbacks(connectRunnable)
if (status == 133) {
postMainHandler(500, connectRunnable)
return
}
if (xxxxx) {
if (xxxx) {
postMainHandler(15000, connectRunnable)
} else {
postMainHandler(8000, connectRunnable)
}
} else {
//....
}
看着挺正常对吧?这是因为kotlin认为,Runnable等价于 ()->Unit. 坑就这里。它会帮你把()->unit函数转成Runnable传过去。
接下来我们来看看是咋么回事:
Tools-》kotlin-》字节码-》decompile:
可以看到箭头函数会被编译成Function对象。然后就尴尬了:
不用我多解释了吧。明白了吧。
kotlin并非专为android设计。编译器把()->unit函数当做了Runnable,一般情况确实是可以通过function和lambda包裹转变。但是,Android Handler移除就要求的是同一个对象。removeCallbacks的Runnable并非你postDelay的runnable。而从IDEA上是看不出来差异的。
所以改成申明为Runnable:
private val connectRunnable = Runnable{
xxxx
}
我也会上报给google,让它加一个类似的提示: