今天在看谷歌Android公众号的文档时看到了handler关于内存泄漏方面的文章,感觉可以转载归纳一下,做一下记录。 官方公众号链接:一次性讲清楚 Handler 可能导致的内存泄漏和解决办法 | 开发者说·DTalk
首先,先说下常用的会造成泄漏的用法,直接使用内部类或者匿名内部类的方式,创建、使用Handler:
// 匿名内部类
override fun onCreate(savedInstanceState: Bundle?) {
...
val innerHandler: Handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
...
}
}
}
// 内部类
override fun onCreate(savedInstanceState: Bundle?) {
...
val innerHandler: Handler = MyHandler(Looper.getMainLooper())
}
inner class MyHandler(looper: Looper): Handler(looper) {
override fun handleMessage(msg: Message) {
...
}
}
这样创建的话,当页面退出的时候, 1、对应的线程仍在处理中、活跃
2、线程(Thread)结束,但是消息(Message)仍存在队列中,或者正在处理中,比如在handlerMessage中, 在这样的两种情况下,会造成内存泄漏。
具体大篇幅的原因可以在给出的文章中查看,总的来说,是因为使用匿名内部类调用Handler,在Activity 销毁的时候,Activity的引用仍然存在,因此造成了内存泄漏。 无论是线程(Thread >handler>activity)还是Looper(looper>messageQueue>message>handler>activity),或者是其他的方式,解决的方法,其实就是阻断这个引用链,可以采用弱引用的方式来处理,即这里推荐的使用handler的方式。 1、将Handler定义为静态内部类:
private class MainHandler(looper: Looper?, referencedObject: MainActivity?) :
WeakReferenceHandler<MainActivity?>(looper, referencedObject) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
val activity:MainActivity? = referencedObject
if (activity != null){}
}
}
2、弱引用外部类的实例:
open class WeakReferenceHandler<T>(looper: Looper?, referencedObject: T) : Handler(looper!!) {
private val mReference: WeakReference<T> = WeakReference(referencedObject)
protected val referencedObject: T?
get() = mReference.get()
}
3、使用 ?
private val mainHandler:MainHandler = MainHandler(mainLooper,this)
4、onDestroy的时候切断引用链,纠正生命周期
override fun onDestroy() {
super.onDestroy()
//清空主线程Handler中未处理的消息
mainHandler.removeCallbacksAndMessages(null)
}
如果子线程未结束,需要中断:thread.interrupt(),如果子线程创建的looper并成为Looper线程,需手动quit:handlerThread.quitSafely()
完毕!!!
虽然感觉目前Handler的使用目前在减少,但是Handler的机制在面试中还是热门话题,以及有时候仍然会使用到Handler,或者是在修改一些老代码的时候更不可避免,因此感觉还是一个必备要学习的东西。所以在这里总结记录下。
|