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詳解》,我這裏只是將視頻中的內容加上本身的理解紀錄下來,但願對你們有所幫助。線程

相關文章
相關標籤/搜索