非静态Handler可能引起的内存泄漏的原因
Looper、MessageQueue、Message介绍:
当一个Android应用启动的时候,会自动创建一个供应用主线程使用的Looper(其中包含MessageQueue)实例。
Looper的主要工作就是一个一个处理消息队列MessageQueue中的消息对象。
在Android中,所有Android框架的事件(比如Activity的生命周期方法调用和按钮点击等)都是放入到消息Message中,然后加入到 Looper要处理的消息队列MessageQueue中,由Looper负责一条一条地进行处理。
主线程中的Looper(包含Looper中的MessageQueue)生命周期和当前应用一样长。
Handler的持久引用分析
Message发送及执行过程
1、Handler在主线程进行了初始化
2、Handler发送Message
3、Message进入MessageQueue
4、Looper从Handler中取出Message
5、Message使用Handler中handleMessage方法执行
Handler、Message、MessageQueue、Looper引用关系
对应以上Message发送及执行过程
1、Handler在主线程进行了初始化:Handler持有主线程中Looper,并获取Looper对应MessageQueue
2、Handler发送Message:Message的target成员变量持有Handler(不考虑Message的setTarget方法)
3、Message进入MessageQueue:MessageQueue持有Message
Looper从Handler中取出Message:MessageQueue释放Message
4、Message使用Handler中handleMessage方法执行:执行完成后Message不再被引用、同样的Message持有的Handler不再被引用
Handler持久引用结论
由以上分析可知:
当Handler发送Message后,在Message被处理前,Handler会一直被强引用
静态/非静态Handler区别 及 内存泄漏的原因
【静态Handler】:创建实例时,不持有创建时所处对象的实例(Activity、View、Dialog等)
【非静态Handler】:创建实例时,持有创建时所处对象的实例(Activity、View、Dialog等)
所以,非静态Handler发送的Message被执行前,创建Handler的实例对象(Activity、View、Dialog等)会被一直引用。
尤其当Handler发送的Message为延时消息时,创建Handler的实例对象可能会被长时间无效引用,导致内存泄漏。
无效引用:当实例对象的生命周期完成时,比如Activity的onDestroy()完成,之前发送的Message被执行已经无意义,对实例对象的引用即为无效引用。
解决方案: WeakReference解决可能的内存泄漏
官方解决方案
以下代码来自Android源码,api-24,android.app.Dialog
private static final class ListenersHandler extends Handler {
private final WeakReference<DialogInterface> mDialog;
public ListenersHandler(Dialog dialog) {
mDialog = new WeakReference<>(dialog);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DISMISS:
((OnDismissListener) msg.obj).onDismiss(mDialog.get());
break;
case CANCEL:
((OnCancelListener) msg.obj).onCancel(mDialog.get());
break;
case SHOW:
((OnShowListener) msg.obj).onShow(mDialog.get());
break;
}
}
}
扩展的解决方案:(以下代码可直接复制使用)
【第一步】:创建公共Handler
package com.love;
import android.os.Handler;
import android.os.Message;
import java.lang.ref.WeakReference;
/**
* Handler,防止内存泄露
* 使用方式:声明静态内部类继承此类
* Date: 2018/3/21
*/
public abstract class StaticHandler<T> extends Handler {
private WeakReference<T> mTargets;
public StaticHandler(T target) {
mTargets = new WeakReference<>(target);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
T target = mTargets.get();
if (target != null) {
handle(target, msg);
}
}
public abstract void handle(T target, Message msg);
}
【第二步】:创建静态内部Handler继承公共Handler,并使用(示例)
package com.love;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
/**
* 演示静态Handler使用
* <p>
* Date: 2018/3/21
*/
public class TestActivity extends Activity {
static final int WHAT_TOAST = 1;
public static class MyHandler extends StaticHandler<TestActivity> {
public MyHandler(TestActivity target) {
super(target);
}
@Override
public void handle(TestActivity target, Message msg) {
switch (msg.what) {
case WHAT_TOAST:
target.showToast();
break;
}
}
}
private Handler mHandler = new MyHandler(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler.sendEmptyMessageDelayed(WHAT_TOAST, 1000);
}
public void showToast() {
//do what you want
}
}