原文地址內(nèi)存泄露
有關(guān)內(nèi)存泄露請猛戳內(nèi)存泄露
Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
// do something.
}
}
當(dāng)我們這樣創(chuàng)建Handler的時(shí)候Android Lint會(huì)提示我們這樣一個(gè)warning: In Android, Handler classes should be static or leaks might occur。一直以來沒有仔細(xì)的去分析泄露的原因,先把主要原因列一下:
Android程序第一次創(chuàng)建的時(shí)候琢蛤,默認(rèn)會(huì)創(chuàng)建一個(gè)Looper對象鹰晨,Looper去處理Message Queue中的每個(gè)Message,主線程的Looper存在整個(gè)應(yīng)用程序的生命周期。
Hanlder在主線程創(chuàng)建時(shí)會(huì)關(guān)聯(lián)到Looper的Message Queue,Message添加到消息隊(duì)列中的時(shí)候Message(排隊(duì)的Message)會(huì)持有當(dāng)前Handler引用闷畸, 當(dāng)Looper處理到當(dāng)前消息的時(shí)候尝盼,會(huì)調(diào)用Handler.handleMessage(Message).就是說在Looper處理這個(gè)Message之前, 會(huì)有一條鏈MessageQueue -> Message -> Handler -> Activity佑菩,由于它的引用導(dǎo)致你的Activity被持有引用而無法被回收盾沫。
在java中裁赠,no-static的內(nèi)部類會(huì)隱式的持有當(dāng)前類的一個(gè)引用。static的內(nèi)部類則沒有赴精。
具體分析
public class SampleActivity extends Activity {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// do something
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 發(fā)送一個(gè)10分鐘后執(zhí)行的一個(gè)消息
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
}
}, 600000); // 結(jié)束當(dāng)前的Activity finish();
}
在finish()的時(shí)候佩捞,該Message還沒有被處理,Message持有Handler,Handler持有Activity,這樣會(huì)導(dǎo)致該Activity不會(huì)被回收蕾哟,就發(fā)生了內(nèi)存泄露一忱。
解決方法
通過程序邏輯來進(jìn)行保護(hù)。
如果Handler中執(zhí)行的是耗時(shí)的操作谭确,在關(guān)閉Activity的時(shí)候停掉你的后臺(tái)線程帘营。線程停掉了,就相當(dāng)于切斷了Handler和外部連接的線逐哈, Activity自然會(huì)在合適的時(shí)候被回收芬迄。如果Handler是被delay的Message持有了引用,那么在Activity的onDestroy()方法要調(diào)用Handler的remove方法鞠眉,把消息對象從消息隊(duì)列移除就行了薯鼠。關(guān)于Handler.remove方法
removeCallbacks(Runnable r)——清除r匹配上的Message。
removeC4allbacks(Runnable r, Object token) ——清除r匹配且匹配token(Message.obj)的Message械蹋,token為空時(shí)出皇,只匹配r。
removeCallbacksAndMessages(Object token)——清除token匹配上的Message哗戈。
removeMessages(int what)——按what來匹配
removeMessages(int what, Object object)——按what來匹配我們更多需要的是清除以該Handler為target的所有Message(Callback)就調(diào)用如下方法即可handler.removeCallbacksAndMessages(null);將Handler聲明為靜態(tài)類郊艘。 靜態(tài)類不持有外部類的對象,所以你的Activity可以隨意被回收唯咬。但是不持有Activity的引用纱注,如何去操作Activity
中的一些對象? 這里要用到弱引用
public class MyActivity extends Activity {
private MyHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new MyHandler(this);
}
@Override
protected void onDestroy() {
// Remove all Runnable and Message.
mHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
static class MyHandler extends Handler {
// WeakReference to the outer class's instance.
private WeakReference<MyActivity> mOuter;
public MyHandler(MyActivity activity) {
mOuter = new WeakReference<MyActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MyActivity outer = mOuter.get();
if (outer != null) {
// Do something with outer as your wish.
}
}
}
}