Handler系列以内存泄漏

  本篇简单的讲一下日常使用Handler时形成内存泄漏的问题。面试

  什么是内存泄漏?大白话讲就是分配出去的内存,回收不回来。严重会致使内存不足OOM。下面来看一下形成内存泄漏的代码:ide

public class MemoryLeakActivity extends Activity {

    private MyHandler mHandler;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);

        mHandler = new MyHandler();
        mHandler.sendEmptyMessage(1);
    }

    private class MyHandler extends Handler{
        
        public MyHandler(){
        }
        
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    }
}

上面的代码咱们不用管发送消息、接受消息,由于以前已经详细讲过了,不是本篇的重点。本篇我想说上面的代码会形成内存泄漏,什么意思?Handler持有MemoryLeakActivity引用,为何?若是不持有当前类的引用,我怎么更改当前类的ui或其余逻辑???或者咱们知道内部类持有外部类引用也行。那么怎么解决那?oop

  解决办法:将内部类改成静态内部类,由于静态内部类不持有外部类引用。因为Handler再也不持有外部类引用,致使程序不容许你在Handler中操做Activity中的对象了。因此你还须要在Handler中增长一个对Activity的弱引用(使用弱引用的好处在于:activity一旦被置为null,他就会被马上回收)。上面持有的引用属于强引用,强引用的特色就是当当前类被回收的时候,若是它被强引用所持有,那么当前类是不会被回收的!!!因此咱们改为软引用持有当前类对象,这样在GC回收时会忽略掉弱引用,即就算有弱引用指向某对象,该对象也会在被GC检查到时回收掉。ui

public class MemoryLeakActivity extends Activity {

    private MyHandler myHandler;

    private static final int ACTION_GOTO_MAIN = 1001;
    private static final int GOTO_MAIN_TIMER = 2 * 1000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        myHandler = new MyHandler(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (myHandler != null) {
            myHandler.sendEmptyMessageDelayed(ACTION_GOTO_MAIN, GOTO_MAIN_TIMER);
        }

    }

    @Override
    protected void onPause() {
        super.onPause();
        if (myHandler != null && myHandler.hasMessages(ACTION_GOTO_MAIN)) {
            myHandler.removeMessages(ACTION_GOTO_MAIN);
        }

    }

    protected static class MyHandler extends Handler {
        private WeakReference<MemoryLeakActivity> mActivity;

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

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            MemoryLeakActivity activity = mActivity.get();
            if (activity == null)
                return;
            if (msg.what == ACTION_GOTO_MAIN) {
                //处理逻辑
            }
        }
    }
}

上面代码很好的解决了内存泄漏的问题。可是这段代码可能会在不少界面都会遇到,难道每一个界面都须要这样写吗?重复的工做啊,因此干脆咱们抽取成一个基类,未来建立Handler的时候继承这个基类就好。this

public abstract class WeakHandler<T> extends Handler {

    protected WeakReference<T> reference;

    //建立子线程Handler使用的构造器
    public WeakHandler(Looper looper, T reference) {
        super(looper);
        this.reference = new WeakReference<>(reference);
    }

    //建立主线程Handler使用的构造器
    public WeakHandler(T reference) {
        this.reference = new WeakReference<>(reference);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        T t = reference.get();
        if (t == null)
            return;
        handleMessage(t, msg);
    }

    protected abstract void handleMessage(T t, Message message);

}

上述代码,咱们使用了泛型,这个泛型就是咱们以前说的当前类,同时提供了两种构造器,这样无论咱们是建立主线程仍是非主线程Handler对象时,都不会形成内存泄漏了。spa

  至此,Handelr系列讲解到此结束,大多数都是参数慕课网的《Android面试常客Handler详解》,我这里只是将视频中的内容加上本身的理解纪录下来,但愿对你们有所帮助。线程

相关文章
相关标签/搜索