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