Handler做爲Android中一個消息傳遞的工具,使用很是頻繁。不管是應用層開發,仍是系統庫件如AsyncTask的封裝,都或多或少地使用了它。然而,Handler的危險性也是很是大的,使用起來稍有不慎就會引發內存泄露。ide
泄露來源分析:工具
常見錯誤用法: post
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mLeakyHandler.postDelayed(new Runnable() { @Override public void run() { /* ... */ } }, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } }
這個用法的錯誤在於,它創造了一條很是長的引用鏈。Handler做爲Activity的內部類,會自動持有Activity的引用,而後Handler經過postDelay發出一個Message,等待着它的迴音,由於Message也會持有Handler的引用。Message會被放入MessageQueue中,等待被執行。概括一下,咱們能夠看到以上的代碼實現了以下一條引用鏈: this
MessageQueue -----> Message -----> Handler -----> Activityspa
這條引用鏈很是長,而且MessageQueue的生命週期是Application級的。若是這條引用鏈不斷,裏面的任何一個對象,都將沒法被回收。code
解決方法:對象
在此提供兩種解決思路blog
1、弱化Handler -----> Activity:token
public class SampleActivity extends Activity { /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ private static class MyHandler extends Handler { private final WeakReference<SampleActivity> mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference<SampleActivity>(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } } private final MyHandler mHandler = new MyHandler(this); /** * Instances of anonymous classes do not hold an implicit * reference to their outer class when they are "static". */ private static final Runnable sRunnable = new Runnable() { @Override public void run() { /* ... */ } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mHandler.postDelayed(sRunnable, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } }
這個思路的核心便是經過靜態類和弱引用,來弱化Handler -----> Activity。Handler變成靜態類,這樣它就只屬於Activity的類,不屬於Activity的對象。而後使Handler中以弱引用握持Activity,這樣兩個類之間的聯繫就能夠弱化,Handle即便被Message引用,Activity也能夠照常回收。生命週期
這個思路的好處就是方法比較明確,比較穩定。而且在Activity的狀況下,也不會有什麼問題。可是若是個人Handle是存在於一個View。而每一個View都須要一個Handler來控制它,此時用static類就是不適合的。那麼咱們只能另尋辦法。
2、切斷MessageQueue -----> Message:
MessageQueue -----> Message -----> Handler -----> Activity
咱們能夠從MessageQueue -----> Message下手,考慮切斷它們的引用聯繫。
所幸Handler爲咱們提供了方法
/** * Remove any pending posts of callbacks and sent messages whose * <var>obj</var> is <var>token</var>. If <var>token</var> is null, * all callbacks and messages will be removed. */ public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); }
使用這個方法,咱們能夠將此Handler在MessageQueue中的全部Message清除。同時,咱們還要將Activity中全部的Runnable中止。也就是說,如今是咱們須要手動清除Activity的全部強引用。這樣也能夠防止內存泄露。這個方法對結構的破懷性小,好處顯而易見。但壞處也一樣明顯,若是咱們在各類引用中漏掉了某一項沒有清除,那前面的全部動做都前功盡棄了。所以,這個方法難度比較大,難以保證其正確性。
理解有限,歡迎拍磚。
Done