用Lint工具对Android代码进行扫描时,有这样一个关于Handler的警告信息:
This Handler class should be static or leaks might occur。
这个警告的产生是由于将Handler声明为了非静态内部类(匿名或非匿名),这种情况下可能会产生内存泄露,导致Activity无法释放。
我们使用Handler post一个Message时,Message会在主线程的MessageQueue中排队。由于消息处理中需要调用Message对应Handler的回调,Message会持有Handler的引用。当Handler为非静态内部类(匿名或非匿名)时,Handler就会持有外部类的引用,如果外部类是Activity,这个Activity对象有可能会泄露,尤其是通过调用Handler的postDelayed()方法发送消息,Message会长时间在MessageQueue中存在,泄露的可能性将更大。
要解决这个问题,需要做的就是想办法切断这个引用关系链(Message -> Handler -> Activity),要么切断Message -> Handler的引用,要么切断Handler -> Activity的引用。
针对第一个引用关系,处理方法是在使用Handler的组件生命周期结束前清除掉MessageQueue中的Message对象(比如,在Activity的onDestroy()中调用Handler的remove*方法)。Handler主要有下面一些方法来清楚Message对象:
removeCallbacks(Runnable r) ——清除r匹配上的Message。
removeCallbacks(Runnable r, Object token) ——清除r匹配且匹配token(Message.obj)的Message,token为空时,只匹配r。
removeCallbacksAndMessages(Object token) ——清除token匹配上的Message。
removeMessages(int what) ——按what来匹配
removeMessages(int what, Object object) ——按what来匹配
我们需要的是清除以该Handler为target的所有Message(包括Callback),那么调用如下方法即可
handler.removeCallbacksAndMessages(null);
针对第二个引用关系,可以将Handler声明为静态内部类,避免对外部类的强引用,如果在Handler的内部方法中需要引用外部类,可以在其内部声明一个WeakReference引用外部类的实例。
具体的实现代码如下:
public class MyActivity extends Activity{
MyHandler myHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onDestroy() {
super.onDestroy();
myHandler.removeCallbacksAndMessages(null);
}
private static class MyHandler extends Handler{
private WeakReference<MyActivity> activity;
MyHandler(MyActivity ac) {
activity = new WeakReference<MyActivity>(ac);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//do something
if (activity != null) {
MyActivity myActivity = activity.get();
//......
}
}
};
}
欢迎关注我的公众号一起交流学习