Handler 内存泄漏
在 Activity 内部 new 一个 handler 对象,则该 handler 对象持有 Activity 的引用。 当 Activity 完成了职责需要 finish 时,如果 handler 的 MessageQueue 里还存在 message(比如 postDelay 了一个延时很大的 message), 那么直到消息队列清空前,message 会一直持有 handler 的引用,而 handler 又持有 Activity 的引用,于是就出现了 Activity 销毁了却无法被回收的现象。 这就是 Handler 使用不当导致的内存泄漏,修复的方法也比较简单,那就是重写 Activity 的 onDestroy 生命周期、清空 handler 的消息队列:
class FooActivity : AppCompatActivity() {
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
}
}
无需擦屁股的 Handler
Handler 的内存泄漏虽然有了解决办法,但算不上一个完美的方案,一方面容易忘记,另一方面写起来略不爽。人们往往热衷于一项伟大工程脚手架的搭建,但没人喜欢在结束时清扫战场。 有点像上厕所,我们享受拉屎带来的快感,却讨厌擦屁股,但出于某些原因又不得不擦。那么问题来了,有没有一种办法保证无论怎么拉、拉完都无需自己擦?
回到 Handler 上来说,答案是肯定的,我们可以将 Handler 和 Jetpack Lifecycle 结合起来,利用 lifecycle 生命周期的回调自动清理 Handler。
fun LifecycleOwner.lifecycleHandler(looper: Looper = Looper.getMainLooper()): Handler = LifecycleHandler(this, looper)
private class LifecycleHandler(
private val owner: LifecycleOwner,
looper: Looper = Looper.getMainLooper()
) : Handler(looper), LifecycleObserver {
init {
owner.lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private fun onDestroy() {
owner.lifecycle.removeObserver(this)
removeCallbacksAndMessages(null)
}
}
我们定义了一种 继承自 Handler 的 LifecycleHandler,监听 Lifecycle ON_DESTROY 事件,在回调里自动 removeCallbacksAndMessages。
由于 Lifecycle 是官方出品,日常的 Activity 和 Fragment 都已经自带 LifecycleOwner 属性,所以又对 LifecycleOwner 进行了 lifecycleHandler 扩展,使用起来相当方便。
函数类型的顶层属性
上面使用的 LifecycleOwner 的扩展函数,其本质上是一个函数。接下来我们看另一种扩展方案:
val lifecycleHandler: LifecycleOwner.(Looper) -> Handler = {
LifecycleHandler(this, it)
}
这里定义的是一个函数类型的顶层属性,其调用方式比之前的扩展函数更加灵活,不仅可以这样 LifecycleOwner.lifecycleHandler(Looper),还可以这样 lifecycleHandler(LifecycleOwner,Looper)。 作为对比,前文的扩展函数只能这样调用 LifecycleOwner.lifecycleHandler(Looper)。
当然顶层属性的方案也是有缺点的,由于其入参无法赋默认值,也就导致了无论何种调用方式 参数皆不可缺省。
多参的函数类型属性
熟悉 Handler 的盆友应该知道,Handler 的构造参数其实有三个,但对外开放到了两个,所以上面一个参数(Looper)的方案并不能覆盖所有的应用场景,我们应该把 Handler.Callback 加入进来。 对于函数类型的顶层属性,多个参数又该如何书写呢?
实际上 lambda 的 it 仅仅是在只有一个入参时的隐式代指,我们知道 lambda 的参数是可以显式命名的,所以上面的顶层属性又等同于如下写法:
val lifecycleHandler: LifecycleOwner.(Looper) -> Handler = { looper ->
LifecycleHandler(this, looper)
}
到这里,我们就不难推导出多个参数的 lambda 写法(只需将多个入参按顺序显式化即可):
val lifecycleHandler: LifecycleOwner.(Looper, Handler.Callback?) -> Handler = { looper, callback ->
LifecycleHandler(this, looper, callback)
}
最后,不太推荐函数类型顶层属性的方案,可以作为学习了解之用。原因嘛主要是其入参不可缺省,参数一旦多起来,你懂的..