源码探索系列1---Handler与HandlerLeak的那些事

开始学安卓的时候,我对一些异步操作都是用Handler和AsyncTask的。

现在那个Handler被挂上了泄漏的名字!
最近在设计一个功能的时候,像借鉴于handler的设计模式,所以顺便顺便写篇文章记录下。

一开始我调用Handler像下面这样,对这种,系统提示会导致泄漏,为人懒惰,
就直接加了这个@SuppressLint("HandlerLeak"),然后忽略掉它。

public class MainActivity extends Activity {

    private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 0x12345) {
                    Log.e(TAG, " log");
                }
            }
        };

     @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mHandler.postDelayed(new Runnable() {
          @Override
          public void run() { /* ... */ }
            }, 60 * 1000); //延迟一分钟发送这个消息

        finish();
      } 
}

后来遇到多了,就还是乖乖根据提示写成一个静态内部类的形式来

public class MainActivity extends Activity {


    static class MyHandler extends Handler {         
        private WeakReference<MainActivity> mOuter;

        public MyHandler(MainActivity activity) {
            mOuter = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity outer = mOuter.get();
            if (outer != null) {
                 TODO: 2015/12/8  
            }
        }
    }
}

那么问题来了,是什么导致写内部类就没事呢?

看下官方的解释:

Since this Handler is declared as an inner class,
it may prevent the outer class from being garbage collected.

If the Handler is using a Looper or MessageQueue for a thread other than the main thread,
then there is no issue.

If the Handler is using the Looper or MessageQueue of the main thread,
you need to fix your Handler declaration, as follows:
Declare the Handler as a static class; In the outer class,
instantiate a WeakReference to the outer class and pass this object to your Handler
when you instantiate the Handler;
Make all references to members of the outer class using the WeakReference object.

结合下面这个例子来说下原因

mHandler.postDelayed(new Runnable() {
              @Override
              public void run() { /* ... */ }
            }, 60 * 1000); 

            finish();

当finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。
而该消息引用了ActivityHandler对象,然后这个Handler又引用了这个Activity
这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收
从而导致了上面说的 Activity泄露。
所以他说如果Handler是使用主线程的Looper或者MessageQueue,那么就需要注意咯 。

嗯,主线程的Looper或MessageQueue,可我没看到有用到啊,怎么回事?

好了,还是让我们开始看下Handler的实现吧,肯定可以找到答案。

看下Hanlder的源码

让我们从调用的第一句,无参构造器看起吧

public Handler() {
    this(null, false);
}

//上面那个无参构造器调用了下面这个
public Handler(Callback callback, boolean async) {

         ....

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new 
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值