Handler内存泄漏

先看一组简单的代码

1
2
3
4
5
6
7
8
9
public class SampleActivity extends Activity {

  private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ... 
    }
  }
}

当我们这样写在一个Activity中时,Android Lint会提示我们这样一个 warning:In Android, Handler classes should be static or leaks might occur.
意思说:在Android中,Handler 类应该是静态的否则可能发生泄漏。

为什么会是这样呢?

了解一下Handler

  1. 当Android程序第一次创建的时候,在主线程同时会创建一个Looper对象。Looper实现了一个简单的消息队列,一个接着一个处理Message对象。程序框架所有主要的事件(例如:屏幕上的点击时间,Activity生命周期的方法等等)都包含在Message对象中,然后添加到Looper的消息队列中,一个一个处理。主线程的Looper存在整个应用程序的生命周期内。
  2. 当一个Handler对象在主线程中创建的时候,它会关联到Loopermessage queueMessage添加到消息队列中的时候Message会持有当前Handler引用,当Looper处理到当前消息的时候,会调用Handler#handleMessage(Message).
  3. java中,no-static的内部类会 隐式的 持有当前类的一个引用。static的类则没有。

在什么地方引起了内存的泄露呢?再看看下面一段代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class SampleActivity extends Activity {

  private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
  }

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

    // 发送一个10分钟后执行的一个消息
    mHandler.postDelayed(new Runnable() {
      @Override
      public void run() { }
    }, 600000);

    // 结束当前的Activity
    finish();
  }
}

Activity结束后,在 Message queue 处理这个Message之前,它会持续存活着。这个Message持有Handler的引用,而Handler有持有Activity(SampleActivity)的引用,这个Activity所有的资源,在这个消息处理之前都不能也不会被回收,所以发生了内存泄露。

解决办法,看下面一段代码

 /**
   * 使用静态的内部类,不会持有当前对象的引用
   */

public class MainActivity extends AppCompatActivity {

    private static final String tag = "MainActivity";

    private TextView mTvShow;

    private MyHandler mHandler;

    private static final int DELAY_TIME = 10000; // set to 5s and 10s to check result.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mHandler = new MyHandler(MainActivity.this);

        Log.e(tag, "onCreate");

        mTvShow = (TextView)findViewById(R.id.tv_show);

        new Thread() {
            @Override
            public void run() {

                mHandler.sendEmptyMessageDelayed(1, DELAY_TIME);
                Log.e(tag, "msg send");
            }
        }.start();

    }

    @Override
    protected void onDestroy() {
        Log.e(tag, "onDestroy");
        super.onDestroy();
    }


    static class MyHandler extends Handler {

        //WeakReference弱引用,在内存不足时,垃圾回收器会回收此对象,所以在每次使用此对象时,要检查其是否被回收
        WeakReference mWeakActivity;

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

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            MainActivity activity = (MainActivity) mWeakActivity.get();

            Log.e(tag, "handleMessage," + msg.what);
            // 5s is not null, 10s is null, tell that activity is recycled.
            if(null == activity){
                Log.e(tag, "null");
            }else{
                Log.e(tag, "not null");
                activity.mTvShow.setText("delay show");
            }
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值