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

来源:互联网 发布:淘宝上怎么买正规发票 编辑:程序博客网 时间:2024/05/14 23:43

通常我们在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 0
原创粉丝点击