在我們寫代碼的時(shí)候,為了實(shí)現(xiàn)在子線程更新UI的需要,我們會(huì)定義一個(gè)Handler屬性,并聲明一個(gè)匿名內(nèi)部類,重寫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);
}
}
那如果細(xì)心看下,其實(shí)Android Studio會(huì)給我一個(gè)提示信息。
意思就是我們應(yīng)該定義一個(gè)靜態(tài)的類,這樣可能會(huì)導(dǎo)致內(nèi)存泄漏。
OK,那這里為什么會(huì)引起內(nèi)存泄漏?首先我們要明白其實(shí)匿名內(nèi)部類或者內(nèi)部類都會(huì)隱形持有外部類的引用,其實(shí)這里Handler就持有MainActivity的引用,在Handler中我們可以隨意調(diào)用MainActivity的方法。在我們發(fā)送消息時(shí)handler會(huì)被復(fù)制給message.target,并放入消息隊(duì)列。但是主線的消息隊(duì)列并不會(huì)隨著Activity的銷毀而銷毀,因此導(dǎo)致Activity的泄漏。那知道了泄漏的原因我們就知道該怎解決了。
1、定義靜態(tài)內(nèi)部類
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);
}
}
在靜態(tài)內(nèi)部類中持有Activity的弱連接這樣就不會(huì)引發(fā)內(nèi)存泄漏了。但是這樣的話消息隊(duì)列中還是有為處理完的消息,其實(shí)Activity銷毀后,再處理這個(gè)消息已經(jīng)沒有意義了,因此有了第二種方法。
2、onDestory時(shí)清理消息
既然內(nèi)存泄漏是因?yàn)锳ctivity銷毀而消息還在,那我在OnDestory時(shí)把它清理掉不就行了,幸運(yùn)的是Handler提供了這樣的方法:
我們可以直接調(diào)用removeCallbacksAndMessages()方法清理message。
注意:這個(gè)方法并不是清空消息棧中所有的message,而是清理message.target等于這個(gè)handler的message,因此不會(huì)影響到無(wú)關(guān)的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;
}
}
}