Android Handler机制的几个疑问点验证

前提场景:Activity中new一个Handler并重写handleMessage方法

public class SingleTopActivity extends Activity {
@SuppressLint("HandlerLeak")
Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        LogUtil.i("name ====== " + SingleTopActivity.this.getClass().getSimpleName());
    }
};

...

}

疑问点1、在Activity finish的时候执行handler = null 是否真正销毁了Handler?

答:并不会,这个取决于通过handler发送的消息是否都处理完成,因为message 的target字段就是指向了当前的Handler,就是说每一个message都持有了一份当前Handler的引用,所以执行handler = null,只是当前的引用变成了 null,在message中可能还有其他的应用,因此new Handler时 在堆中开辟的内存不会被系统回收。

验证现象:执行handler = null以后,之前发送的延时任务仍然会被执行,handleMessage方法仍然会被正常回调。

疑问点2、在前提场景中,handler默认持有了Activity的应用,有内存泄漏的风险,那在关闭页面时,主动执行Activity的 onDestroy方法能解决可能出现的内存泄漏问题吗?

答:不能解决问题,其实没有必要主动执行onDestroy方法 因为你执行了finish后 过一会系统就会自动执行onDestroy ,此时通过命令adb shell dumpsys activity | grep  com.xxx.xxx 查看Activity栈信息,发现activity也已经从栈中移除掉了,但是如果此时有未执行完的消息(引用关系:activity -- handler -- message),activity在堆中的”真身”还是存在的,并不会被系统回收。(引用位置在handler所在的栈的位置)

另:查看栈信息截图 图中不存在SingleTopActivity了

验证现象:执行handler = null以后,之前发送的延时任务仍然会被执行,LogUtil.i("name ====== " + SingleTopActivity.this.getClass().getSimpleName()); 打印信息正常显示,并不会报空指针。

验证现象2:当有未执行完成的message时,SingleTopActivity中的finalize方法没有被执行,message执行完后,过了一会执行了finalize方法(GC在回收一个对象前会执行此对象的finalize方法)

验证现象3:通过AS自带的Memory分析工程查看内存,发现内存一直在增长,SingleTopActivity在增加

从内存分析图的右下角 Allocation Call Stack 也能看到SingleTopActivity在栈中的被引用的位置 就在Handler里面

通过以上分析验证,我们就明白了为什么在Activity关闭时把handler置为null,然后主动执行onDestroy方法,并不能解决可能发生的内存泄漏问题。

推荐最佳解决方案:在Activity关闭时执行   handler.removeCallbacksAndMessages(null);  (静态+弱应用的方案 第一增加static对象,第二弱应用可能被回收影响业务,不推荐)


版权声明:本文为u013347784原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。