閱讀66 返回首頁    go 阿裏雲 go 技術社區[雲棲]


你試過弱引用弱爆了嗎?原因竟然是 ... ...

Android WeakReference 帶來的問題


背景


其實開始的時候本人也像很多人一樣,因為出現的內存泄露問題,因此開始使用起weakReference的,還信心滿滿的以為,從此我和我的小夥伴再也不擔心內存泄露。

然而,其實weakReference真的那麼好?來看代碼吧,我們常規時候定義一個自定義的Handler來異步請求處理代碼,當然LZ表示自己是個很懶得人,因此自己寫了個BaseHandler通過反射直接執行回調方法,這個先不說。


public static class MyHandler extends Handler{
         private WeakReference<MyActivity> wActivity;

         public MyHandler(MyActivity activity){
               wActivity = new WeakReference(activity);
         }    

         void handleMessage(Message msg){
               //do something
               MyActivity myActivity = wActivity .get();
               if(myActivity !=null){
                      myActivity.doSomething();
               }
         }
}

這是我們常規寫的,那麼有啥問題?這似乎木有問題啊,恩,LZ當初也是這樣想的,直到一天我手賤的時候。 大家都知道,。知道的話應該知道LZ接下來說的問題,對當內存不足的時候WeakReference會被回收的,但是有個問題是當前Activity還在活動的時候WeakReference是否還是會被回收? ...答案肯定的 。因此你想過木有突然出發內存回收,那麼你本來要回調的方法,嗬嗬嗬嗬嗬嗬.....那麼怎麼會觸發他回收,我做的很簡單,那時因為Activity前麵已經有很長的Activity棧,而且LZ很無恥的不停來回切換一個不是singleTask或者singleTop的Activity。然後某一次,有個回調方法沒調用....看如下測試代碼(這個是我之前寫一篇文章 Android MVVM使用經驗篇中一段代碼):

public class AdapterModule<T> {
    // not use onClick
    public static final int BINDVAIABLE_NONE = 0;

    public ObservableArrayList<T> list = new ObservableArrayList<>();
    // bindingVaiable id
    public ObservableInt bindingVaiable;
    // bind PositionId
    public ObservableInt bindPositionVaiableId;
    // the key is the resourceId!
    public WeakReference<SparseArray<OnClickListener>> listeners;
    // manual notify
    public boolean manualNotify = false;

    //代碼省略
}


 @Override
    public BindingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (inflater == null) {
            inflater = LayoutInflater.from(parent.getContext());
        }

        ViewDataBinding binding = DataBindingUtil.inflate(inflater, layoutId.get(), null, false);
        final BindingHolder holder = new BindingHolder(binding, (SparseArray<OnClickListener>) adapterModule.listeners.get());

       ///代碼省略
        return holder;
    }

public static class BindingHolder<T> extends RecyclerView.ViewHolder {

        ViewDataBinding binding;
        private SparseArray<OnClickListener> listeners;

        public BindingHolder(ViewDataBinding binding, SparseArray<OnClickListener> listeners) {
            super(binding.getRoot());
            this.binding = binding;
            this.listeners = listeners;
            Log.e("textListener is null?", (listeners == null) + "");
            onBindListeners();
        }

        public void onBindListeners() {
            if (listeners != null && listeners.size() > 0) {
                for (int i = 0; i < listeners.size(); i++) {
                    binding.setVariable(listeners.keyAt(i), listeners.get(listeners.keyAt(i)));
                }
            }
        }
    }




最後在我來回切換頁麵時候有以下輸出:
....前麵省略N個。
09-28 21:48:39.859 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:39.866 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:39.873 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:40.925 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:40.932 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:40.940 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:41.975 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:41.983 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:41.990 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:42.958 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:42.964 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:42.970 14872-14872/com.ykse.ticket E/textListener is null?: false
09-28 21:48:44.074 14872-14872/com.ykse.ticket E/textListener is null?: true
09-28 21:48:44.081 14872-14872/com.ykse.ticket E/textListener is null?: true
09-28 21:48:44.091 14872-14872/com.ykse.ticket E/textListener is null?: true

看到木有-。-或許前麵有N個沒事,但是某一個時刻,哼哼,說了那麼多怎麼解決,其實也很簡單。。。不用WeakReference唄,然後在相關Activity或者Fragment或者View detach時候將Activity引用去掉就行了唄~當然如果你非要說道線程不安全-。-要加同步鎖,我不反對~~看代碼


public static class MyHandler extends Handler{
         private MyActivity activity;

         public MyHandler(MyActivity activity){
               this.activity= activity;
         }    

         void handleMessage(Message msg){
               //do something
               if(myActivity !=null){
                      myActivity.doSomething();
               }
         }

         public synchronized void destory(){
                   myActivity = null;
         }
}

最後更新:2017-04-08 12:27:56

  上一篇:go Android MVVM(使用經驗篇)
  下一篇:go 代碼生成利器:IDEA 強大的 Live Templates