非静态内部类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

8D922718668811AB9F21445AB0017F90.jpg

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

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

 private Handler mHandler = new MyHandler(this);
    private static class MyHandler extends Handler{
        private final WeakReference<Activity> mActivity;
        public MyHandler(Activity activity) {
            mActivity = new WeakReference<Activity>(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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员学园

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值