零零碎碎的東西老是記不長久,僅僅學習別人的文章也只是他人咀嚼後留下的殘渣。無心中發現了這個每日一道面試題,想了想若是隻是簡單地去思考,那麼不只會收效甚微,甚至難一點的題目本身可能都懶得去想,堅持不下來。因此不如把每一次的思考、理解以及別人的看法記錄下來。不只加深本身的理解,更要激勵本身堅持下去。java
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必定會提醒你會有內存泄漏的可能。網絡
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);
}
}
複製代碼