handler可能引發內存泄露問題的處理

一般我們在使用handler時,直接回書寫匿名內部類或者如下方式,原則上講是不對的。可能會造成內存泄露,發生OOM異常。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // handler拿到消息調用分發消息和處理消息
        mHandler    = new Handler() {
            @Override
            public void handleMessage(Message msg) {

                Toast.makeText(MainActivity.this,"我是主線程的吐司",Toast.LENGTH_SHORT).show();

            }
        };
        downloadPicture();

    }

在主線程中

  Toast.makeText(MainActivity.this,"我是主線程的吐司",Toast.LENGTH_SHORT).show();

引起內存泄露的原因:
當應用啓動時,系統自動創建主線程Looper和LooperQueue,所以一旦消息隊列中有消息,與消息綁定的主線程handler就一直處於執行過程中,那麼在hanldeMessage中所引用的MainActivity就不能被回收掉掉,那麼MainActivity中的資源一直被佔用,由此可引發內存泄露問題。

解決第一步,把MainActivity作爲context引用傳遞過來,修改代碼如下:
自定義MyHandler把Context作爲構造函數傳遞進來

static class MyHandler extends Handler{

        private Context mContext;

        public  MyHandler(Context context){
            this.mContext = context;
        }
    }
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // handler拿到消息調用分發消息和處理消息
        mHandler = new MyHandler(this){
            @Override
            public void handleMessage(Message msg) {

                Toast.makeText(this.mContext,"我是主線程的吐司",Toast.LENGTH_SHORT).show();

            }
        };

        downloadPicture();

    }

但是仍然存在上述問題,修改兩點,一是改爲靜態內部類,不持有外部類的引用;二是將mContext對象設爲軟引用對象,當內存不足時可以被回收,從而避免了內存大量被佔用,造成內存泄露,甚至oom問題。

//靜態內部類不持有外部類的引用
   static class MyHandler extends Handler{

        //將對象mContext作爲軟引用對象,mContext當內存不足時就會被回收。
      SoftReference<Context> mContext ;
        public  MyHandler(Context context){
            if(context!=null) {
                mContext = new SoftReference<Context>(context);
            }

        }
    }

觀看詳細信息,請看鏈接
http://www.jb51.net/article/120627.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章