每日一道面试题(第1期)---自定义handler如何有效保证内存泄漏问题

零零碎碎的东西总是记不长久,仅仅学习别人的文章也只是他人咀嚼后留下的残渣。无意中发现了这个每日一道面试题,想了想如果只是简单地去思考,那么不仅会收效甚微,甚至难一点的题目自己可能都懒得去想,坚持不下来。所以不如把每一次的思考、理解以及别人的见解记录下来。不仅加深自己的理解,更要激励自己坚持下去。

handler作用

SDK文档是这么说的。

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

我们一般就是用来更新UI线程的。具体点就是在子线程进行耗时操作,比如获取网络图片,然后需要在主线程更新图片,就需要handler+Message+Loop+MessageQueue来帮忙啦。

但是如果你直接创建一个handler对象,然后重写内部handlerMessage方法,那么AS一定会提醒你会有内存泄漏的可能。

Handler

为什么会造成内存泄漏

Android内存泄漏:需要被GC回收的对象因为被其他存活的对象所持有引用,而导致GC不能回收此对象。那么这块内存就会在程序运行期间长期被占据,造成系统内存的浪费,使系统运行缓慢甚至崩溃。

那么handler什么时候会造成内存泄漏呢?

发送延迟消息

众所周知,匿名内部类持有外部类的引用,那么handler对象就会持有activity对象的引用。handler发送message到MessageQueue,message持有handler的引用,而MessageQueue会持有message的引用,而MessageQueue是属于TLS(ThreadLocalStorage)线程,是与Activity不同的生命周期。

所以当Activity的生命周期结束后,而MessageQueue中还存在未处理的消息,那么上面一连串的引用关系就不允许Activity的对象被回收,就造成了内存泄漏。

解决办法

知道了内存泄漏是由引用链造成的,那么解决方法也就是破坏上面的引用链。

首先是引用的类型,有强引用、软引用、弱引用、虚引用,上面的引用链都是强引用。

引用

所以第一种方法,自定义静态内部类,如果想使用外部类的方法,那就通过弱引用的方法引入Activity对象。

public class BaseActivity extends Activity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    public void myHandleMessage(Message msg){}

    static class MyHandler extends Handler{
        WeakReference<BaseActivity> mActivityReference;
        public MyHandler(BaseActivity activity){
            mActivityReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            BaseActivity activity = mActivityReference.get();
            if(activity != null){
                activity.myHandleMessage(msg);
            }
        }
    }
}

你可以自定义在BaseActivity中,在其他Activity中创建Myahndler对象,通过重写myHandleMessage方法进行消息处理。

这种方法就是处理了Activity与Handler之间的引用,这种引用可以再GC时被回收。

第二种,就是处理后面的引用。既然是Activity要被回收时还有未被处理的消息,那么在Activity要被回收时清除消息就可以了。

@Override
    protected void onDestroy() {
        super.onDestroy();
        if(mHandler != null){
            mHandler.removeCallbacksAndMessages(null);
        }
    }

   转载规则


《每日一道面试题(第1期)---自定义handler如何有效保证内存泄漏问题》 飞跃 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
每日一道面试题(第2期)---Activity 与 Fragment 之间常见的几种通信方式? 每日一道面试题(第2期)---Activity 与 Fragment 之间常见的几种通信方式?
零零碎碎的东西总是记不长久,仅仅学习别人的文章也只是他人咀嚼后留下的残渣。无意中发现了这个每日一道面试题,想了想如果只是简单地去思考,那么不仅会收效甚微,甚至难一点的题目自己可能都懒得去想,坚持不下来。所以不如把每一次的思考、理解以及别人
2020-03-31
下一篇 
Retrofit源码分析 Retrofit源码分析
在学习了Retrofit分析-漂亮的解耦套路(视频版)后,自己又仔细的钻研了一下Retrofit的源码,也大致清楚了Retrofit进行网络请求的步骤。好记性不如烂笔头,以文章的形式将对于Retrofit的思考记录下来,也加深理解。(如有错
2020-03-31
  目录