你試過弱引用弱爆了嗎?原因竟然是 ... ...
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