在我們寫代碼的時候奄侠,為了實現(xiàn)在子線程更新UI的需要蓬痒,我們會定義一個Handler屬性丛肢,并聲明一個匿名內(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);
}
}
那如果細心看下,其實Android Studio會給我一個提示信息怕磨。
意思就是我們應(yīng)該定義一個靜態(tài)的類喂饥,這樣可能會導(dǎo)致內(nèi)存泄漏。
OK肠鲫,那這里為什么會引起內(nèi)存泄漏员帮?首先我們要明白其實匿名內(nèi)部類或者內(nèi)部類都會隱形持有外部類的引用,其實這里Handler就持有MainActivity的引用导饲,在Handler中我們可以隨意調(diào)用MainActivity的方法捞高。在我們發(fā)送消息時handler會被復(fù)制給message.target,并放入消息隊列。但是主線的消息隊列并不會隨著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的弱連接這樣就不會引發(fā)內(nèi)存泄漏了。但是這樣的話消息隊列中還是有為處理完的消息命浴,其實Activity銷毀后娄猫,再處理這個消息已經(jīng)沒有意義了,因此有了第二種方法生闲。
2媳溺、onDestory時清理消息
既然內(nèi)存泄漏是因為Activity銷毀而消息還在,那我在OnDestory時把它清理掉不就行了碍讯,幸運的是Handler提供了這樣的方法:
我們可以直接調(diào)用removeCallbacksAndMessages()方法清理message悬蔽。
注意:這個方法并不是清空消息棧中所有的message,而是清理message.target等于這個handler的message捉兴,因此不會影響到無關(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;
}
}
}