您的位置:首页 > 移动开发 > Android开发

14.Android 控制Handler内存泄露 技巧

2015-09-21 13:47 387 查看

14.Android 控制Handler内存泄露 技巧

Android 控制Handler内存泄露 技巧
Handler 警告

Handler 内存泄露缘由

解决思路

Handler 通用模板

Handler 警告

In Android, Handler classes should be static or leaks might occur, Messages enqueued on the application thread’s MessageQueue also retain their target Handler. If the Handler is an inner class, its outer class will be retained as well. To avoid leaking the outer class, declare the Handler as a static nested class with a WeakReference to its outer class

这是在用Handler不加
static
都会出现的一个警告。

Handler 内存泄露缘由

一个Android应用启动的后,都会创建一个主UI线程,再为这个主UI线程提供一个Looper对象,这样所有的Android框架的事件(Activity的生命周期方法调用和事件)都是放入消息中,再加入Looper处理的MessageQueue中。也就是说主线程的Looper生命周期是与Android应用一样长的。

每次在
Handler.sendMessage(message)
的时候,实际已经发送的message已经包含了改Handler的引用。因为在只有这样Looper才能调用处理改message的handler,进而走到
handler.handleMessage(Message msg)
中,不然,你想,我发一个message,Looper怎么知道message处理过后告诉哪个Handler执行
handler.handleMessage(Message msg)


非静态的内部类和匿名的内部类都会隐式地持有了它的对应外部类的引用。静态的内部类不会持有外部类的引用。

出现泄漏的场景:假如我的Handler里做了很多耗时的工作,在
Activity.finish()
后Handler还在忙碌的话,就一直持有该Activity的引用,Activity无法回收,进行导致Activity持有的很多资源都无法回收,就会出现Handler的内存泄漏

解决思路

解决思路基本上是:不用非静态的Handler,继承Handler的时候,可以选择

独立出一个Handler类

静态Handler

以上,这两种方法。因为静态的内部类不会持有外部类(Activity)的引用,所以不会导致外部类实例的内存泄露。

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

Handler 通用模板

private TextView handlerTV;
private static final int HANDLER_SUCCESS = 206;
private static class RefreshHandler extends Handler {
private final WeakReference<RefreshUIActivity> mActivity;

public RefreshHandler(RefreshUIActivity activity) {
mActivity = new WeakReference<>(activity);
}

/**
* Subclasses must implement this to receive messages.
*
* @param msg
*/
@Override
public void handleMessage(Message msg) {
RefreshUIActivity activity = this.mActivity.get();
if (activity != null) {
switch (msg.what) {
case HANDLER_SUCCESS: {
activity.handlerTV.setText("success");
break;
}
}
}
}
}

private final RefreshHandler refreshHandler = new RefreshHandler(RefreshUIActivity.this);
private final Runnable mRunnable = new Runnable() {
@Override
public void run() {
Message message = RefreshUIActivity.this.refreshHandler.obtainMessage();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
message.what = HANDLER_SUCCESS;
refreshHandler.sendMessageDelayed(message, 2000);
}
};
private final Thread mThread = new Thread(mRunnable);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息