还不清楚Handler为什么造成了内存泄漏?

541 阅读2分钟

对于Handler我们通常会像下边这样使用:

//非静态内部类的写法:
class MyHandler extends Handler{
    @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //do something
        }
}
//匿名内部类的写法:
    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //do something
        }
    };

分析上面的代码,看似没错。可是它内存泄漏了。首先来分析原因:
我们知道匿名内部类或者非静态内部类默认会持有外部类的引用,而且还是强引用,这就厉害了,如果我的内部类里面做一些耗时的操作,突然关闭Activity,但是这个时候内部类还持有Activity的引用的啊,纠缠一起,导致Activity无法回收。这样便造成了内存泄漏。为什么,因为生命周期长的跟生命周期短的纠缠在了一起。
解决办法:
既然已经知道了造成内存泄漏的原因,那就想办法让生命周期长的不要跟生命周期短的一起玩儿。怎么处理,静态啊,static,我们知道,静态的周期是跟Application的周期一样的,比较长,既然你内部类想要活得久,那么就跟生命周期长的static一起吧,于是就有了一种说法,使用静态内部类来解决Handler的内存泄漏。
这样真的就解决了吗?不。我们开发中在handler的内部类中的handleMessage方法中通常干嘛?更新ui啊,ui又属于Activity啊,什么?又跟Activity纠缠在一起了,得,什么静态啊,白干了。怎么处理?这个时候要想到java的引用,我们知道强引用,就算内存不足了,GC都没胆回收,软引用呢,内存不足了GC才会想到回收它,弱引用呢,不管内存足不足,只要扫描到了,就会尽快回收,至于虚引用,用不到(反正我没用过)
了解了几种引用后自然就会想到使用若引用来持有Activity的引用,这样这个引用链不会存活太久,页面退出的话GC扫描到后就会回收,这样跟Activity的引用断了,GC自然有胆回收Activity了 代码如下:

...
WeakRefrence<TestActivity> weakRefrence;

private static class MyHandler extends Handler{
    
    MyHandler(TestActivity activity){
        this.weakRefrence  = new WeakReference<TestActivity>(activity)
    }
    
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        weakReference.get().mText.setText("do someThing");

    }
    
}