自定义 Handler 时如何有效地避免内存泄漏问题?

一般情况下,我们说到 Handler 内存泄漏,指的是 Handler 泄漏掉了所在的 Activity。

class MyActivity extends Activity{
    public Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);    
    }   
}

上面的代码就有可能导致内存泄漏。代码中的 Handler 使用了 MyActivity 内部类的写法,在 Java 中,非静态内部类和匿名内部类都会隐式的持有一个外部类的引用。所以,这个 Handler 就持有了 Activity 的引用。

由于 Handler 的特性问题,接下来有可能遇到几个问题。

  1. 用户关掉了 Activity,但是还有延迟消息没有发出或者发出去的消息还没被执行,由于 MessageQueue 持有这个 Message 的引用,Message 持有 Handler 的引用, Handler 又持有 Activity 的引用,这就导致这个已经关闭的 Activity 迟迟不能被内存回收;

  2. Handler 发出的消息在执行耗时任务,无法回收;

问题有了,只需要给出对应的解决办法就好了。

  1. Handler 经常被用来发延时消息,我们需要保证 Activity 被 finish() 的时候,该线程的消息队列中没有这个 Handler 发出的消息。一个补救的办法就是在该类需要回收的时候,手动地把消息队列中的消息清空:mHandler.removeCallbacksAndMessages(null);

  2. 不让 Handler 持有 Activity 的实例,可以让该Handler成为静态内部类,因为静态内部类是不持有外部类的实例的;同时弱引用外部 Activity。

    public class MyActivity extends Activity {
    private static class MyHandler extends Handler {
      private final WeakReference mActivity;
    
      public MyHandler(Activity activity) {
        mActivity = new WeakReference(activity);
      }
    
      @Override
      public void handleMessage(Message msg) {
        Activity activity = mActivity.get();
        if (activity != null) {}
      }
    }
    
    private MyHandler mHandler = new MyHandler();
    
    @Override
    protected void onDestroy() {
      mHandler.removeCallbacksAndMessages(null);
    }
    }
    
  3. 将 Handler 放到抽取出来放入一个单独的顶层类文件中,弱引用目标 Activity。

    public class WeakRefHandler extends Handler {
        private WeakReference mWeakReference;
        
        public WeakRefHandler(Callback callback) {
            mWeakReference = new WeakReference(callback);
        }
        
        public WeakRefHandler(Callback callback, Looper looper) {
            super(looper);
            mWeakReference = new WeakReference(callback);
        }
        
        @Override
        public void handleMessage(Message msg) {
            if (mWeakReference != null && mWeakReference.get() != null) {
                Callback callback = mWeakReference.get();
                callback.handleMessage(msg);
            }
        }
    }
    

你可能感兴趣的