標籤:
如果您在Activity中定義了一個內部Handler類,如下代碼:
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(); }}
然後運行Android Lint工具會有一個記憶體泄露警告:
This Handler class should be static or leaks might occur (com.example.ta.MainActivity.1)
Issue: Ensures that Handler classes do not hold on to a reference to an outer class
Id: HandlerLeak
In Android, Handler classes should be static or leaks might occur. Messages enqueued on the application thread’s MessageQueue also retain their target Handler. If the Handler is an inner class, its outer class will be retained as well. To avoid leaking the outer class, declare the Handler as a static nested class with a WeakReference to its outer class.
原因是:
-
當Android應用啟動的時候,會先建立一個應用主線程的Looper對象,Looper實現了一個簡單的訊息佇列,一個一個的處理裡面的Message對象。主線程Looper對象在整個應用生命週期中存在。
-
當在主線程中初始化Handler時,該Handler和Looper的訊息佇列關聯。發送到訊息佇列的Message會引用發送該訊息的Handler對象,這樣系統可以調用 Handler#handleMessage(Message) 來分發處理該訊息。
-
在Java中,非靜態(匿名)內部類會引用外部類對象。而靜態內部類不會引用外部類對象。
-
如果外部類是Activity,則會引起Activity泄露 。
當Activity finish後,延時訊息會繼續存在主線程訊息佇列中1分鐘,然後處理訊息。而該訊息引用了Activity的Handler對象,然後這個Handler又引用了這個Activity。這些引用對象會保持到該訊息被處理完,這樣就導致該Activity對象無法被回收,從而導致了上面說的 Activity泄露。
要修改該問題,只需要按照Lint提示的那樣,把Handler類定義為靜態即可,然後通過WeakReference 來保持外部的Activity對象。
private Handler mHandler = new MyHandler(this);private static class MyHandler extends Handler{ private final WeakReference<Activity> mActivity; public MyHandler(Activity activity) { mActivity = new WeakReference<Activity>(activity); } @Override public void handleMessage(Message msg) { System.out.println(msg); if(mActivity.get() == null) { return; } }}
所以,當你在Activity中使用內部類的時候,需要時刻考慮您是否可以控制該內部類的生命週期,如果不可以,則最好定義為靜態內部類。
MyHandler ttsHandler = new MyHandler(this);
private void test() { ttsHandler.sendEmptyMessage(0); }
android This Handler class should be static or leaks might occur