問題描述:
使用普通內部類或匿名類開啓線程執行耗時任務,若任務沒有結束而Activity銷燬,那麼,因爲內部類或匿名類對外部類Activity持有強引用,會導致Activity對象一直無法釋放,從而無法回收,導致內存泄露。
於是,改成外部類或內部靜態類後,對Activity不產生強引用了,那麼,線程任務結束時,如何回調給Activity呢?
保存Activity的WeakReference,即弱引用。通過WeakReference.get()來判斷Activity對象是否存在,然後進行後續處理。在實踐時發現,Activity在onDestroy後,通過WeakReference.get()返回的並不是空。這就是C++與gc的差別。C++中,對象被銷燬後,內存立即釋放,弱引用爲空。但是,Android中,對象被銷燬後,其引用計數爲0,但gc並不一定立即回收,所以此時弱引用仍然有效。
問題解決:
第1步,普通內部類或匿名類放到外部,或改成靜態類。
第2步,存儲弱引用,以便回調時訪問。雖然弱引用不一定異常正確,但還是有必要的,比如內存吃緊時gc直接回收。
第3步,在回調中調用Activity方法時,先判斷isDestroyed(),如果是,那麼可以不必後續處理了。
示例:
public class MyActivity extends AppCompatActivity {
// 靜態內部類
private static class MyTask extends AsyncTask<Bundle, Integer, Bundle> {
// 持有弱引用
private final WeakReference<MyActivity> weak;
private MyTask(MyActivity activity) {
weak = new WeakReference<>(activity);
}
protected Bundle doInBackground(Bundle... bundles) {
Bundle bundle = new Bundle();
// 耗時操作
return bundle;
}
protected void onPostExecute(Bundle bundle) {
if (weak.get() == null)
return;
weak.get().handleResult(bundle);
}
}
private void doRequest() {
new MyTask(this).execute();
}
}