Handler内存泄露原理及解决方法

本文详细解析了Android中由于Handler导致的内存泄漏问题,解释了其原理,即Handler通过消息队列与Activity形成的强引用链阻碍了GC回收。文章通过实例展示了内存泄漏的现象,并提出了两种解决方案:1) 使用弱引用的Handler,避免Activity被强引用;2) 在Activity销毁时清除消息队列,切断引用链。最后,强调了内存泄漏对应用性能的影响及防止措施的重要性。
摘要由CSDN通过智能技术生成

前言

因为Android采取了单线程UI模型,开发者无法在子线程中更新UI,为此Android为我们提供了Handler这个工具,可以开发者切换到主线程更新UI。Android最原始线程间通信都是基于Handler发送消息,来进行线程间通信方案的。

事例

首先看一段示例代码
 

public class LeakActivity extendsAppCompatActivity {   
        privateHandler mHandler;

    @Override
    protectedvoid onCreate(BundlesavedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler = new Handler() {
            @Override
            public void handleMessage(Messagemsg) {
                super.handleMessage(msg);
            }

        };
        Message message = Message.obtain();
        message.what = 1;
        mHandler.sendMessageDelayed(message,30 * 1000);
    }

}

这段代码的逻辑很简单,mHandler延时了10分钟发送消息,类似的代码在我们的项目中也经常出现,但是这样的代码会出现一个问题。

问题

我们首先打开 LeakActivity ,然后按返回键将这个Activity finish 掉。等待几秒logcat控制台就会看到内存泄漏现象。

原因

究竟是什么时候发生了内存泄露的问题呢?

我们知道在java中,非静态内部类会隐式地持有外部类的引用,静态内部类则不会。在上面的代码中,Message在小溪队列中延时了30秒钟,然后才处理该消息。而这个消息引用了Handler对象,Handler对象又隐式地持有了Activity对象,当发生GC是以为message - handler - activity 的引用链导致Activity无法被回收,所以发生了内存泄漏的问题。

危害

众所周知,内存泄露在 Android 开发中是一个比较严重的问题,系统给每一个应用分配的内存是固定的,一旦发生了内存泄露,就会导致该应用可用内存越来越小,严重时会发生OOM 导致 Crash。

解决

这个问题该如何解决呢?

1、使用弱引用。

概念:java对于强引用的对象,就绝不收回。对于软引用和弱引用的对象,是能不收回就不收回,这里的能不收回就是指内存足够的情况。但是内存不足,系统自动触发GC时,会回收弱引用和软引用修饰的对象。

很显然,出现内存泄漏问题的原因,就是Handler对Activity是强引用,导致GC在回收Activity时无法回收。为了解决这个问题,我们可以把Handler对Activity弱引用,这样GC就能把Activity及时的回收,从而杜绝内存泄漏的问题。

public class NoLeakActivity extends AppCompatActivity{

    privateNoLeakHandler mHandler;

 

    @Override

    protectedvoid onCreate(BundlesavedInstanceState) {

        super.onCreate(savedInstanceState);

        mHandler new NoLeakHandler(this);

        Message message = Message.obtain();

        mHandler.sendMessageDelayed(message,30 * 1000);

    }

 

    privatestatic class NoLeakHandler extends Handler {

        privateWeakReference<NoLeakActivity>mActivity;

 

        public NoLeakHandler(NoLeakActivity activity) {

            mActivity new WeakReference<>(activity);

        }

 

        @Override

        publicvoid handleMessage(Message msg){

            super.handleMessage(msg);

            final Activityactivity = mActivity.get();

            if (activity == null) {

                return;

            }

                ..............

        }

    }

 

    @Override

    protectedvoid onDestroy() {

        super.onDestroy();

        mHandler.removeCallbacksAndMessages(null);

    }

}

2、及时清除消息。

刚才我们说到,正是因为被延时处理的message持有Handler的引用,Hander持有对Activity的引用。形成了message- handler - activity 这样一条引用链,导致 Activity 的泄漏。因此我们可以尝试在当前界面结束时将消息队列中未被处理的消息清除。从源头上解除了这条引用链,是Activity能及时地被回收。

public class LeakActivity extendsAppCompatActivity {

    privateHandler mHandler;

    @Override
    protectedvoid onCreate(BundlesavedInstanceState) {
        super.onCreate(savedInstanceState);

        mHandler = new Handler() {

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

        Message message = Message.obtain();
        message.what = 1;
        mHandler.sendMessageDelayed(message,30 * 1000);
    }
    @Override
    protectedvoid onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }

}

运行 Ok。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值