Handler的内存泄露分析

  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 -----> Activitytoken

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

相关文章
相关标签/搜索