你试过弱引用弱爆了吗?原因竟然是 ... ...

简介: ###Android WeakReference 带来的问题 ####背景 ------------------------------ #####其实开始的时候本人也像很多人一样,因为Handler出现的内存泄露问题,因此开始使用起weakReference的,还信心满满的以为,从此我和我的小伙伴再也不担心内存泄露。 --------------------------------

Android WeakReference 带来的问题


背景


其实开始的时候本人也像很多人一样,因为Handler出现的内存泄露问题,因此开始使用起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当初也是这样想的,直到一天我手贱的时候。 大家都知道,Java垃圾回收机制对吧。知道的话应该知道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;
         }
}
目录
相关文章
|
Java
强、软、弱、虚引用
强、软、弱、虚引用
65 0
|
存储 监控 安全
ThreadLocal之强、弱、软、虚引用(下)
ThreadLocal之强、弱、软、虚引用
ThreadLocal之强、弱、软、虚引用(下)
|
缓存 安全 Java
ThreadLocal之强、弱、软、虚引用(上)
ThreadLocal之强、弱、软、虚引用
ThreadLocal之强、弱、软、虚引用(上)
|
缓存 算法 Java
谨防JDK8重复类定义造成的内存泄漏
谨防JDK8重复类定义造成的内存泄漏
谨防JDK8重复类定义造成的内存泄漏
ThreadLocal不好用?那是你没用对!(14)
ThreadLocal不好用?那是你没用对!(14)
83 0
ThreadLocal不好用?那是你没用对!(14)
ThreadLocal不好用?那是你没用对!(10)
ThreadLocal不好用?那是你没用对!(10)
74 0
ThreadLocal不好用?那是你没用对!(10)
|
存储 对象存储
ThreadLocal不好用?那是你没用对!(13)
ThreadLocal不好用?那是你没用对!(13)
106 0
ThreadLocal不好用?那是你没用对!(13)
|
安全 Java
ThreadLocal不好用?那是你没用对!(3)
ThreadLocal不好用?那是你没用对!(3)
84 0
ThreadLocal不好用?那是你没用对!(3)
|
安全
ThreadLocal不好用?那是你没用对!(5)
ThreadLocal不好用?那是你没用对!(5)
86 0
ThreadLocal不好用?那是你没用对!(5)
|
Java
ThreadLocal不好用?那是你没用对!(1)
ThreadLocal不好用?那是你没用对!(1)
105 0
ThreadLocal不好用?那是你没用对!(1)