如果在Activity中定义了一个内部Handler类,会出现一个内存泄露警告:
This Handler class should be static or leaks might occur…
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.
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
}
}
public void onCreate(Bundle savedInstanceState) {
……
mHandler.sendMessageDelayed(Message.obtain(), 60000);
finish();
}
原因是:
-
当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。
-
当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。
-
在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。
-
如果外部类是Activity,则Activity会一直被Handler引用,而无法释放,造成内存泄露 。
各个对象的引用关系:
MainThread -> Looper -> MessageQueue -> Message -> Handler -> Activity
主线程在整个应用的生命周期中,是一直存在的,所以如果Message一直在MessageQueue中存在的话(如延迟发送消息等),则Handler对象会一直被引用,而如果Handler是非静态内部类,则其会一直引用Activity。
最佳方式,采用WeakReference:
static class MyHandler extends Handler {
WeakReference<Activity> mWeakReferenceActivity;
public MyHandler(SplashActivity activity) {
mWeakReferenceActivity = new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
SplashActivity activity = mWeakReferenceActivity.get();
if(activity == null) {
return;
}
}
}
private MyHandler mMyHandler = new MyHandler(this);