在我们写代码的时候,为了实现在子线程更新UI的需要,我们会定义一个Handler属性,并声明一个匿名内部类,重写handleMessage方法,就像下面这样。
public class MainActivity extends AppCompatActivity {
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
}
}
那如果细心看下,其实Android Studio会给我一个提示信息。
意思就是我们应该定义一个静态的类,这样可能会导致内存泄漏。
OK,那这里为什么会引起内存泄漏?首先我们要明白其实匿名内部类或者内部类都会隐形持有外部类的引用,其实这里Handler就持有MainActivity的引用,在Handler中我们可以随意调用MainActivity的方法。在我们发送消息时handler会被复制给message.target,并放入消息队列。但是主线的消息队列并不会随着Activity的销毁而销毁,因此导致Activity的泄漏。那知道了泄漏的原因我们就知道该怎解决了。
1、定义静态内部类
private static class MyHandler extends Handler{
private WeakReference<MainActivity> mActivity;
public MyHandler(MainActivity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
在静态内部类中持有Activity的弱连接这样就不会引发内存泄漏了。但是这样的话消息队列中还是有为处理完的消息,其实Activity销毁后,再处理这个消息已经没有意义了,因此有了第二种方法。
2、onDestory时清理消息
既然内存泄漏是因为Activity销毁而消息还在,那我在OnDestory时把它清理掉不就行了,幸运的是Handler提供了这样的方法:
我们可以直接调用removeCallbacksAndMessages()方法清理message。
注意:这个方法并不是清空消息栈中所有的message,而是清理message.target等于这个handler的message,因此不会影响到无关的message和Handler。
参看下面的MessageQueue.removeCallbacksAndMessages
void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}