android 內部handler引發內存泄露

一段很常見的代碼: 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;
        }
    }
}
相關文章
相關標籤/搜索