Bootstrap

Android Handler、非静态、匿名内部类的内存泄漏,用静态内部类+弱引用或handler.removeCallbackAndMessages(null)解决

借鉴自:https://www.jianshu.com/p/63aead89f3b9


为啥要用内部类呢,很方便,可以直接访问外部类的东西。所以,非静态、匿名内部类会隐式持有外部类的引用。但是,仅仅持有引用并不会引起内存泄漏,但是如果有什么延时的操作,而且进行某个延时操作的对象还必须以持有外部类为基础才能进行的,这个时候就内存泄漏了。静态内部类可以解决这个问题,后面讲。


比如Handler,里面的message,仍然在消息队列中,而且是延时比如10分钟,这个时候这个Activity的内存泄漏就会维持10分钟以上。为什么呢,因为message的target就是handler,也就是message会持有handler的引用,而handler又持有activity的引用,所以,不光handler也释放不了,activity也释放不了了。(即使你在onDestory里让handler=null 也不行)


解决方式:静态内部类+弱引用。首先介绍下静态内部类。静态内部类,其实可以脱离外部类了,他们是没有联系的。可以称之为,静态嵌套类。只是为了封装或者什么原因,放在你这里罢了,他是一个独立的类。所以就不会隐式持有外部类的引用。但是你又必须得到这个引用,怎么办。采用弱引用即可,写一个Handler的静态方类,然后构造方法里 接受activity的实例,把它维护成弱引用即可。下面是改写后的Handler。

private final MyHandler mHandler = new MyHandler(this);

private static class MyHandler extends Handler {
    private final WeakReference<SampleActivity> mActivity;

    public MyHandler(SampleActivity activity) {
        mActivity = new WeakReference<SampleActivity>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        SampleActivity activity = mActivity.get();
        if (activity != null) {
            // ...
        }
    }
}

private static final Runnable sRunnable = new Runnable() {
    @Override
    public void run() { /* ... */ }
};

其实。。。如果非要用语法糖(匿名内部类)也可以,在Activity的onDestory()中调用handler.removeCallbackAndMessages(null),即可,如果是Thread,则中断线程即可, 总之你要想办法中断。(消息队列分为可退出队列和不可退出队列,activity中封装的那个的是可退出的)

;