防側漏之弱引用的使用
本文依然基於github上的開源框架為基礎,看過之前發的 最新Retrofit + RxJava + MVP 那篇blog的講述,應該明白框架裡面的大概,一步步兌現之前的承諾,會寫上十篇左右的帖子來講解裡面的要點和難點,今天主要講述的是baseActivity裡面的WeakReference< BaseActivity >。
最初入行的時候,使用handler一般都是如下方式:
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super .handleMessage(msg);
/**
* 各種操作
*/
}
};
先說下此處的問題,首先,系統會有警告,This Handler class should be static or leaks might occur,大致意思就是說:Handler類應該定義成靜態類,否則可能導致記憶體洩露,因為非靜態內部類隱式自動持有外部類的強引用,而靜態內部類不會引用外部類物件,目前只需要記住這句話,說到根本原因就牽扯到jvm,這塊日後會單獨拿出來寫一個模組。
再者,這樣寫的話,如果有一個超生命週期的邏輯,則會出現記憶體洩漏,百說不如貼上程式碼:
private void test() {
handler.sendMessageDelayed(Message.obtain(), 60000);
finish();
}
當Android應用啟動的時候,會先建立一個UI主執行緒的Looper物件,同時會建立一個MessageQueue,Looper迴圈遍歷,把MessageQueue中的message一個一個取出來處理,處理結束後並不會銷燬(這和java中訊息機制不同,java中處理完便會自動銷燬,等待回收),而是等待後續傳來的message,只要Handler傳送的Message尚未被處理,則該Message及傳送它的Handler物件將被執行緒MessageQueue一直持有,上述程式碼是activity在finish一分鐘後才收到資訊,此時的activity中的handler還在被強引用,當這個activity退出時訊息佇列中還有未處理的訊息或者正在處理訊息,而訊息佇列中的message持有handler例項的引用,handler又持有activity的引用,所以導致該activity的記憶體資源無法及時回收,引發記憶體洩漏,關於handler這塊,之前一篇
為何使用弱引用
對於強、軟、弱、虛四大引用,之前在簡述圖片載入框架有過講述並有程式碼例項,此處不重複貼程式碼,對於弱引用,指的是當垃圾回收器掃描到此處垃圾,無論記憶體是否充足,都會回收,功能上和軟引用如出一轍,和軟引用最大的不同就是軟引用是在記憶體不足的時候,gc掃描到才會回收此處記憶體。此處使用弱引用比軟引用更加合理,雖然軟引用同樣可以解決因為強引用導致記憶體無法回收的問題,但有個前提條件就是需要記憶體不足的時候才可以,這就沒有弱引用來得實在。
改進後的程式碼如下:
/**
* Created by Zero on 2017/7/20.
*/
public abstract class BaseActivity<Pre extends BasePresenter> extends AppCompatActivity implements OnClickListener {
private static final String DIALOG_LOADING = "DialogLoading";
private boolean mVisible;
private LoadingDialogFragment waitDialog = null;
protected Pre presenter;
protected final Handler mHandler = new MyHandler(this);
private BroadcastReceiver receiver;
private IntentFilter filter;
/*****************省略一些不相關程式碼*****************/
@Override
protected void onDestroy() {
super.onDestroy();
/**
* 移除mHandler
*/
mHandler.removeCallbacksAndMessages(null);
if (receiver != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
}
}
/**
* Created by zero on 2017/7/24.
*/
public class MyHandler extends Handler {
private final WeakReference<BaseActivity> mActivity;
/**
* 從BaseActivity中提取出來,原來是因為內部類會隱式強引用當前類,採用弱引用,避免長生命週期導致記憶體洩漏
*
* @param activity
*/
public MyHandler(BaseActivity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
if (mActivity.get() != null) {
mActivity.get().requestOver(msg);
}
}
}
為了避免一些handler拖泥帶水,onDestroy方法中對mHandler進行removeCallbacksAndMessages(null)處理,便於mHandler和activity及時被回收。
專案已上傳,戳此進入github。