引言
在Android中如果错误的使用Handler也会引起内存泄漏的。所以在我们实际开发中还是需要多多注意,并尽量去避免它。
原例
Android代码中涉及线程通信的地方,我们基本都会选择使用Handler。比如:
public class HandlerActivity extends Activity{
//可能引起内存泄漏的方法
private final Handler mHandler = new Handler(){
@Override
public void handlerMessage(Message msg){
//...
}
}
}
如果使用Android Lint分析这段代码的话,会发现提示:
This Handler class should be static or leaks might occur.
这就是在提醒开发者,这里的写法有可能会引起内存泄漏,需要开发者去处理。那为什么会可能产生内存泄漏呢?这个要从Handler的机制来说,我们都知道Handler是和Looper以及MessageQueue一起使用的。在Android中一个应用启动后,系统会默认创建一个为主线程服务的Looper对象,该对象用于处理主线程的所有Message对象,它的生命周期贯穿于整个应用的生命周期。在主线程中使用的Handler都会默认绑定到这个Looper对象。在主线程中创建Handler对象时,它会立即关联主线程Looper对象的MessageQueue,这时发送到MessageQueue中的Message对象都会持有这个Handler对象的引用,这样在Looper处理消息时才能回调到Handler的handleMessage方法。因此如果Message还没有被处理完成,那么Handler也就不会被垃圾回收。
在上段代码中,我们将Handler的实例声明为了HandlerActivity的内部类。而在Java中非静态内部匿名类会持有外部类的一个隐式的引用,这样就又能能会导致外部类无法被垃圾回收。因此,最终由于MessageQueue中的Message对象还没有处理完成,就会持有Handler对象的引用,而非静态的Handler对象会持有外部类HandlerActivity的引用,这个Activity无法被垃圾回收,从而导致了内存泄漏。
比如下面这种写法:
public class HandlerActivity extends Activity{
//可能引起内存泄漏的方法
private final Handler mHandler = new Handler(){
@Override
public void handlerMessage(Message msg){
//...
}
}
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//延迟5分钟发送消息
mHandler.postDelayed(new Runnable(){
@Override
public void run(){
...
}
},1000*60*5)
}
}
由于消息要延后5分钟发送,因此,当用户进入这个Activity并在5分钟内退出后,在消息发送并处理完成之前,这个Activity是不会被系统回收的。
那么要怎么解决呢?有两个方案:
- 在子线程中使用Handler,这时需要开发者自己创建一个Looper对象,这个Looper对象的生命周期同一般的Java对象,因此这种用法没有问题。
- 将Handler声明为静态的内部类,前面说过,静态内部类不会持有外部类的引用,因此,也不会引起内存泄漏。
正确用法
所以,下面我们看下经典的用法:
public class HandlerActivity extends Activity{
//声明一个静态的Handler内部类,并持有外部类的弱引用
private static class InnerHandler extends Handler{
private final WeakReference<HandlerActivity> mActivity;
public InnerHandler(HandlerActivity activity){
mActivity = new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg){
HandlerActivity activity = mActivity.get();
if(activity != null){
//...
}
}
}
private final InnerHandler mHandler = new InnerHandler(this);
//静态的匿名内部类不会持有外部类的引用
private static final Runnable sRunnable = new Runnable(){
@Override
public void run(){
//...
}
}
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//延迟5分钟发送消息
mHandler.postDelayed(sRunnable,1000*60*5);
}
}