Android Handler leak分析及解决办法详解
AndroidHandlerleak分析及解决办法
InAndroid,Handlerclassesshouldbestaticorleaksmightoccur,Messagesenqueuedontheapplicationthread'sMessageQueuealsoretaintheirtargetHandler.IftheHandlerisaninnerclass,itsouterclasswillberetainedaswell.Toavoidleakingtheouterclass,declaretheHandlerasastaticnestedclasswithaWeakReferencetoitsouterclass.
在Android中,Handler类应该是静态的,否则,可能发生泄漏。在应用程序线程的MessageQueue中排队的Message对象还保留他们的目标Handler。如果Handler是一个内部类(注:无论是匿名还是非匿名,匿名是比较常见用法),它的外部类将被保留(至于为什么,请参考Java嵌套类相关说明)。为了避免泄漏外部类,声明一个Handler子类为静态内部类(注:这样就避免了Handler对象对外部类实例的自动引用),其内部持有一个对外部类对象的WeakReference。
上面是HandlerLeak的详细解释,同时下划线部分也提供了解决方案的思路。我们需要再分析一下几个泄漏问题:(1)排队中的Message对象对Handler的持有导致泄漏;(2)Handler对象对外部类(如Activity或Service)实例的强引用持有。是由于这两个原因同时作用导致出现泄漏的可能。我们的解决方案可以从原因出发,清除这两个原因,就会比较完整的解决这个问题。
方案:(1)针对第1个原因,在使用Handler的组件生命周期结束前清除掉MessageQueue中的发送给Handler的Message对象(例如在Activity或Service的onDestroy()中调用Handler的remove*方法);(2)针对第2个原因,Handler的实现类采用静态内部类的方式,避免对外部类的强引用,在其内部声明一个WeakReference引用到外部类的实例。
关于Handler的remove*方法,这儿介绍一下(可以参考源码或文档)
removeCallbacks(Runnabler)——清除r匹配上的Message。
removeCallbacks(Runnabler,Objecttoken)——清除r匹配且匹配token(Message.obj)的Message,token为空时,只匹配r。
removeCallbacksAndMessages(Objecttoken)——清除token匹配上的Message。
removeMessages(intwhat)——按what来匹配
removeMessages(intwhat,Objectobject)——按what来匹配
我们更多需要的是清除以该Handler为target的所有Message(包括Callback),那么调用如下方法即可
handler.removeCallbacksAndMessages(null);
最终代码像下面这样
packageorg.dragonboy.example;
importjava.lang.ref.WeakReference;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Message;
/**
*@authordragonboyorg@qq.com
*/
publicclassMyActivityextendsActivity{
privateMyHandlermHandler;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
mHandler=newMyHandler(this);
}
@Override
protectedvoidonDestroy(){
//RemoveallRunnableandMessage.
mHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
staticclassMyHandlerextendsHandler{
//WeakReferencetotheouterclass'sinstance.
privateWeakReferencemOuter;
publicMyHandler(MyActivityactivity){
mOuter=newWeakReference(activity);
}
@Override
publicvoidhandleMessage(Messagemsg){
MyActivityouter=mOuter.get();
if(outer!=null){
//Dosomethingwithouterasyourwish.
}
}
}
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!