Handler系列之內存泄漏


  本篇簡單的講一下平常使用Handler時造成內存泄漏的問題。

  什么是內存泄漏?大白話講就是分配出去的內存,回收不回來。嚴重會導致內存不足OOM。下面來看一下造成內存泄漏的代碼:

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或其他邏輯???或者我們知道內部類持有外部類引用也行。那么怎么解決那?

  解決辦法:將內部類改為靜態內部類,因為靜態內部類不持有外部類引用。由於Handler不再持有外部類引用,導致程序不允許你在Handler中操作Activity中的對象了。所以你還需要在Handler中增加一個對Activity的弱引用(使用弱引用的好處在於:activity一旦被置為null,他就會被立刻回收)。上面持有的引用屬於強引用,強引用的特點就是當當前類被回收的時候,如果它被強引用所持有,那么當前類是不會被回收的!!!所以我們改成軟引用持有當前類對象,這樣在GC回收時會忽略掉弱引用,即就算有弱引用指向某對象,該對象也會在被GC檢查到時回收掉。

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的時候繼承這個基類就好。

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對象時,都不會造成內存泄漏了。

  至此,Handelr系列講解到此結束,大多數都是參數慕課網的《Android面試常客Handler詳解》,我這里只是將視頻中的內容加上自己的理解紀錄下來,希望對大家有所幫助。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM