一段很常見的代碼: java
public class MainActivity extends Activity { private Handler mHandler = newHandler() { @Override public void handleMessage(Message msg) { //TODO handle message... } }; @TargetApi(11) @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler.sendMessageDelayed(Message.obtain(), 60000); //just finish this activity finish(); } }
可是你運行lint會發現有一個內存泄露的警告。 ide
緣由是:
1.
當Android應用啓動的時候,會先建立一個應用主線程的Looper對象,Looper實現了一個簡單的消息隊列,一個一個的處理裏面的Message對象。主線程Looper對象在整個應用生命週期中存在。 oop
2.
當在主線程中初始化Handler時,該Handler和Looper的消息隊列關聯。發送到消息隊列的Message會引用發送該消息的Handler對象,這樣系統能夠調用 Handler#handleMessage(Message) 來分發處理該消息。 this
3.
在Java中,非靜態(匿名)內部類會引用外部類對象。而靜態內部類不會引用外部類對象。 線程
4.
若是外部類是Activity,則會引發Activity泄露 。 code
具體到這個例子裏邊,當Activity finish後,延時消息會繼續存在主線程消息隊列中1分鐘,而後處理消息。而該消息引用了Activity的Handler對象,而後這個Handler又引用了這個Activity。這些引用對象會保持到該消息被處理完,這樣就致使該Activity對象沒法被回收,從而致使了上面說的 Activity泄露。 對象
要修改該問題,只須要按照Lint提示的那樣,把Handler類定義爲靜態便可,而後經過WeakReference 來保持外部的Activity對象。 生命週期
private Handler mHandler = new MyHandler(this); private static class MyHandler extendsHandler{ private final WeakReference<Activity> mActivity; public MyHandler(Activity activity) { mActivity = newWeakReference<Activity>(activity); } @Override public void handleMessage(Message msg) { System.out.println(msg); if(mActivity.get() == null) { return; } } }