用Lint工具對Android代碼進行掃描時,有這樣一個關于Handler的警告資訊:
This Handler class should be static or leaks might occur。
這個警告的産生是由于将Handler聲明為了非靜态内部類(匿名或非匿名),這種情況下可能會産生記憶體洩露,導緻Activity無法釋放。
我們使用Handler post一個Message時,Message會在主線程的MessageQueue中排隊。由于消息進行中需要調用Message對應Handler的回調,Message會持有Handler的引用。當Handler為非靜态内部類(匿名或非匿名)時,Handler就會持有外部類的引用,如果外部類是Activity,這個Activity對象有可能會洩露,尤其是通過調用Handler的postDelayed()方法發送消息,Message會長時間在MessageQueue中存在,洩露的可能性将更大。
要解決這個問題,需要做的就是想辦法切斷這個引用關系鍊(Message -> Handler -> Activity),要麼切斷Message -> Handler的引用,要麼切斷Handler -> Activity的引用。
針對第一個引用關系,處理方法是在使用Handler的元件生命周期結束前清除掉MessageQueue中的Message對象(比如,在Activity的onDestroy()中調用Handler的remove*方法)。Handler主要有下面一些方法來清楚Message對象:
removeCallbacks(Runnable r) ——清除r比對上的Message。
removeCallbacks(Runnable r, Object token) ——清除r比對且比對token(Message.obj)的Message,token為空時,隻比對r。
removeCallbacksAndMessages(Object token) ——清除token比對上的Message。
removeMessages(int what) ——按what來比對
removeMessages(int what, Object object) ——按what來比對
我們需要的是清除以該Handler為target的所有Message(包括Callback),那麼調用如下方法即可
handler.removeCallbacksAndMessages(null);
針對第二個引用關系,可以将Handler聲明為靜态内部類,避免對外部類的強引用,如果在Handler的内部方法中需要引用外部類,可以在其内部聲明一個WeakReference引用外部類的執行個體。
具體的實作代碼如下:
public class MyActivity extends Activity{
MyHandler myHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onDestroy() {
super.onDestroy();
myHandler.removeCallbacksAndMessages(null);
}
private static class MyHandler extends Handler{
private WeakReference<MyActivity> activity;
MyHandler(MyActivity ac) {
activity = new WeakReference<MyActivity>(ac);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//do something
if (activity != null) {
MyActivity myActivity = activity.get();
//......
}
}
};
}
歡迎關注我的公衆号一起交流學習