项目中使用到了Handler,按照如下方式编写:
handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 参数:
//此处处理UI状态
break;
default:
break;
}
}
};
Android Studio会发出警告:
This Handler class should be static or leaks might occur
- 问题原因:在ADT 20 Changes我们可以找到这样一个变化:“New Lint Checks: Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its outer class.” 就是说在ADT20以后加入了一条新的检查规则:确保类内部的handler不含有对外部类的隐式引用 。
1. 当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。
2. 当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。
3. 在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。
4. 如果外部类是Activity,则会引起Activity泄露 。
当Activity finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。
要修改该问题,只需要按照Lint提示的那样,把Handler类定义为静态即可,然后通过WeakReference 来保持外部的Activity对象。
代码如下:
private static class MyHandler extends Handler{
private final WeakReference<Class> mTarget;
public MyHandler(Class class){
mTarget= new WeakReference<>(class);
}
@Override
public void handleMessage(@NonNull Message msg) {
Class class=mTarget.get();
if (class!=null){
switch (msg.what) {
case 参数:
//此处处理UI状态
//因为该Handler为static,所以我们通过调用方法来获取外部类属性
class.属性;
class.方法;
break;
default:
break;
}
}
}
}
使用:
private MyHandler handler=new MyHandler(this);
handler.sendEmptyMessage(消息);