Handler内存泄露分析与解决方案

一、内存泄露分析

内部类会有一个指向外部类的引用。

垃圾回收机制中约定,当内存中的一个对象的引用计数为0时,将会被回收。

Handler 作为 Android 上的异步消息处理机制(好吧,我大多用来进行 worker thread 与 UI 线程同步),它的工作是需要 Looper 和 MessageQueue 配合的。简单的说,要维护一个循环体(Looper)处理消息队列(MessageQueue)。每循环一次就从 MessageQueue 中取出一个 Message,然后回调相应的消息处理函数。

如果,我是说如果,循环体中有消息未处理(Message 排队中),那么 Handler 会一直存在,那么 Handler 的外部类(通常是 Activity)的引用计数一直不会是0,所以那个外部类就不能被垃圾回收。很多人会遇到 activity的onDestroy方法一直不执行就是这个原因。

一旦 Handler 被声明为内部类,那么可能导致它的外部类不能够被垃圾回收。如果 Handler 是在其他线程(我们通常成为 worker thread)使用 Looper 或 MessageQueue(消息队列),而不是 main 线程(UI 线程),那么就没有这个问题。如果 Handler 使用 Looper 或 MessageQueue 在主线程(main thread),你需要对 Handler 的声明做如下修改:
声明 Handler 为 static 类;在外部类中实例化一个外部类的 WeakReference(弱引用)并且在 Handler 初始化时传入这个对象给你的 Handler;将所有引用的外部类成员使用 WeakReference 对象。

二、解决方案

解决方法(一)

声明 Handler 为 static 类;在外部类中实例化一个外部类的 WeakReference(弱引用)并且在 Handler 初始化时传入这个对象给你的 Handler;将所有引用的外部类成员使用 WeakReference 对象。

public class MethodSolveOne extends AppCompatActivity {

    private static final String TAG = "MethodSolveOne";


    private CopyFileHandler mHandler;
    private TextView mDisplayTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.method_solve_one);
        mDisplayTextView = (TextView)findViewById(R.id.display_text_view);
        mHandler = new CopyFileHandler(this);
        startCopyFileThread();
    }

    private void startCopyFileThread() {
        Log.d(TAG, "startCopyFileThread");
        new Thread(new Runnable() {
            @Override
            public void run() {
                //DO SOMETHING LIKE: copyDBFile();
                Message msg = mHandler.obtainMessage();
                msg.what = 1;
                mHandler.sendMessage(msg);
            }
        }).start();
    }

    private void changeDisplayTextView(String str){
        mDisplayTextView.setText(str);
    }
    private static class CopyFileHandler extends Handler {
        WeakReference<MethodSolveOne> mActivity;

        public CopyFileHandler(MethodSolveOne activity) {
            mActivity = new WeakReference<>(activity);
        }

        public void handleMessage(Message msg) {
            final MethodSolveOne activity = mActivity.get();
            switch (msg.what){
                case 1:
                    activity.changeDisplayTextView("I have changed!!!");
            }
        }
    }
}

解决方法(二)

在worker thread 中使用 Looper 或 MessageQueue

private Handler testHandler;
private Thread mThread = new Thread() {
    public void run() {
        Log.d(TAG, "mThread run");
        Looper.prepare();
        testHandler = new Handler() {
            public void handleMessage(Message msg) {
                Log.d("TAG", "worker thread:" + Thread.currentThread().getName());
                switch (msg.what) {
                    //handle message here
                }
            }
        };
        Looper.loop();
    }
};
//start thread here
if(Thread.State.NEW==mThread.getState())

{
    Log.d(TAG, "mThread name: " + mThread.getName());
    mThread.start();
}
//send message here
testHandler.sendEmptyMessage(1);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值