每日一道面試題(第1期)---自定義handler如何有效保證內存泄漏問題

零零碎碎的東西老是記不長久,僅僅學習別人的文章也只是他人咀嚼後留下的殘渣。無心中發現了這個每日一道面試題,想了想若是隻是簡單地去思考,那麼不只會收效甚微,甚至難一點的題目本身可能都懶得去想,堅持不下來。因此不如把每一次的思考、理解以及別人的看法記錄下來。不只加深本身的理解,更要激勵本身堅持下去。java

handler做用

SDK文檔是這麼說的。git

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.github

咱們通常就是用來更新UI線程的。具體點就是在子線程進行耗時操做,好比獲取網絡圖片,而後須要在主線程更新圖片,就須要handler+Message+Loop+MessageQueue來幫忙啦。面試

可是若是你直接建立一個handler對象,而後重寫內部handlerMessage方法,那麼AS必定會提醒你會有內存泄漏的可能。網絡

Handler

爲何會形成內存泄漏

Android內存泄漏:須要被GC回收的對象由於被其餘存活的對象所持有引用,而致使GC不能回收此對象。那麼這塊內存就會在程序運行期間長期被佔據,形成系統內存的浪費,使系統運行緩慢甚至崩潰。ide

那麼handler何時會形成內存泄漏呢?oop

發送延遲消息學習

衆所周知,匿名內部類持有外部類的引用,那麼handler對象就會持有activity對象的引用。handler發送message到MessageQueue,message持有handler的引用,而MessageQueue會持有message的引用,而MessageQueue是屬於TLS(ThreadLocalStorage)線程,是與Activity不一樣的生命週期。spa

因此當Activity的生命週期結束後,而MessageQueue中還存在未處理的消息,那麼上面一連串的引用關係就不容許Activity的對象被回收,就形成了內存泄漏。線程

解決辦法

知道了內存泄漏是由引用鍊形成的,那麼解決方法也就是破壞上面的引用鏈。

首先是引用的類型,有強引用、軟引用、弱引用、虛引用,上面的引用鏈都是強引用。

引用

因此第一種方法,自定義靜態內部類,若是想使用外部類的方法,那就經過弱引用的方法引入Activity對象。

public class BaseActivity extends Activity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    public void myHandleMessage(Message msg){}

    static class MyHandler extends Handler{
        WeakReference<BaseActivity> mActivityReference;
        public MyHandler(BaseActivity activity){
            mActivityReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            BaseActivity activity = mActivityReference.get();
            if(activity != null){
                activity.myHandleMessage(msg);
            }
        }
    }
}
複製代碼

你能夠自定義在BaseActivity中,在其餘Activity中建立Myahndler對象,經過重寫myHandleMessage方法進行消息處理。

這種方法就是處理了Activity與Handler之間的引用,這種引用能夠再GC時被回收。

第二種,就是處理後面的引用。既然是Activity要被回收時還有未被處理的消息,那麼在Activity要被回收時清除消息就能夠了。

@Override
    protected void onDestroy() {
        super.onDestroy();
        if(mHandler != null){
            mHandler.removeCallbacksAndMessages(null);
        }
    }

複製代碼
相關文章
相關標籤/搜索