Android中Handler使用不当引起的内存泄露

通常我们在Android编程中,常常会用到它自己提供的一种异步回调机制Handler,通过它,我们可以在进行异步操作后处理返回结果,通常我们的代码是这么实现的:在主线程中,new一个Handler对象实现其handleMessage方法,在handleMessage中提供收到消息后的相应处理的方法即可,示例代码如下:

package com.tb.demo.utils.hangview;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

/**
 * Created by tb
 */
public class DemoHandlerActivity extends Activity {
    private final int LOADDBDATA = 0x1;

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

    /**
     * 获取本地数据
     */
    private void getLocalData() {
        //start get data from db
        //do something
        //...
        //...
        //end get data from db
        handler.sendEmptyMessage(LOADDBDATA);
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case LOADDBDATA:
                    // do something when msg.what=0x01
                    // ...
                    // ...
                    break;
                default:
                    break;
            }
        }
    };
}
然而写完这个Handler之后Android Studio报了一个警告,如下图:


解释如下:

1.当这个App启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper负责管理MessageQueue和Message对象,读取到MessageQueue中的Message之后就会采用sendMessage的方式把消息发送给对应的Handler来处理,Looper接收到一条一条的消息后逐一进行处理,所以主线程中的Looper和App的生命周期一样长。

2.当一个Handler在主线程进行了初始化之后,我们发送一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息包含了一个Handler实例的引用,只有这样Looper在处理到这条消息时才可以调用 Handler#handleMessage(Message)完成消息的正确处理。

3.在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。

解决思路:

不使用非静态内部类,继承Handler时,或者放在单独的类文件中,或者使用静态内部类。因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。注意:一个静态的匿名内部类实例不会持有外部类的引用。

调整代码如下:

package com.tb.demo.utils.hangview;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import java.lang.ref.WeakReference;

/**
 * Created by tangbin on 15/9/5.
 */
public class DemoHandlerActivity extends Activity {

    private MyHandler myHandler;

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

        setContentView(R.layout.activity_main);
        myHandler = new MyHandler(this);
        getLocalData();

    }

    /**
     * 获取本地数据
     */
    private void getLocalData() {
        // start get data from db
        // do something
        // ...
        // ...
        // end get data from db
        myHandler.sendEmptyMessage(myHandler.LOADDBDATA);
    }

    public void logOut() {
        System.out.println("data is ok");
    }

    /**
     * Instances of static inner classes do not hold an implicit reference to
     * their outer class.
     */
    static class MyHandler extends Handler {
        public static final int LOADDBDATA = 0x1;
        WeakReference<DemoHandlerActivity> activity;

        MyHandler(DemoHandlerActivity mActivity) {
            activity = new WeakReference<DemoHandlerActivity>(mActivity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            DemoHandlerActivity ac = activity.get();
            switch (msg.what) {
            case LOADDBDATA:
                // do something when msg.what=0x01
                // ...
                // ...
                ac.logOut();
                break;
            default:
                break;
            }
        }
    }
}


好了,终于不报警告了。 在Android中很多的内存泄露都是由于在Activity中使用了非静态内部类导致的,所以当我们使用时要非静态内部类时要格外注意,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值