非静态内部类Handler类引起内存泄露

最近在项目中使用延时Handler做Splish页面的跳转。


new Handler().postDelayed(new Runnable() {
       @Override
       public void run() {
       Intent intent = new Intent(SplishActivity.this,MainActivity.class);
       startActivity(intent);
       finish();
    }
},100);

谁知道产生如下内存泄露。

static android.app.Instrumentation.mRecommendActivity

referencs android.app.Instrumentation$RecommendActivity.mTarget

leaks XXX.SplishActivity instance
非静态内部类Handler类引起内存泄露_第1张图片
8D922718668811AB9F21445AB0017F90.jpg

仔细一想确实是这么回事,因为可能延时Handler还没处理消息,页面就finish了,但是因为Handler是非静态内部内,会持有外部Activity的引用,所以导致外部Activity不能被销毁,故而产生内存泄露。

所以为了安全起见,把Handler改为静态内部类,并且持有弱引用。

 private Handler mHandler = new MyHandler(this);
    private static class MyHandler extends Handler{
        private final WeakReference mActivity;
        public MyHandler(Activity activity) {
            mActivity = new WeakReference(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            System.out.println(msg);
            if(mActivity.get() == null) {
                return;
            }
        }
    }
    private Runnable mRunable = new Runnable() {
        @Override
        public void run() {
            Intent intent = new Intent(SplishActivity.this,MainActivity.class);
            startActivity(intent);
            finish();
        }
    };

mHandler.postDelayed(mRunable,100);
  @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacks(mRunable);
    }

总结内部Handler类引起内存泄露的原因

1、当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。

2、当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。

3、在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。
如果外部类是Activity,则会引起Activity泄露 。

4、当Activity finish后,延时消息会继续存在主线程消息队列中,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。

5、要修改该问题,只需要按照Lint提示的那样,把Handler类定义为静态即可,然后通过WeakReference 来保持外部的Activity对象。

更正一下

上面

mHandler.postDelayed(mRunable,100);

上面用mRunable还是提示内存泄露。

改成sendMessageDelayed

 mHandler.sendMessageDelayed(Message.obtain(), 100);

你可能感兴趣的:(非静态内部类Handler类引起内存泄露)