2017-08-02 53 views
5

爲了避免內存泄漏,我編寫了以下用於活動並主要用於碎片(使用繼承)的方法。該方法應該允許我通過調用弱引用而不是getActivity()(Android避免內存泄漏)?

//this or getActivity() 

方法不會直接引用活動:

private WeakReference<BaseActivity> activityWeakReference = null; 

public BaseActivity getActivityFromWeakReference(){ 
     activityWeakReference = activityWeakReference == null ? 
       new WeakReference<BaseActivity>((BaseActivity)getActivity()) : 
       activityWeakReference; 
     return activityWeakReference.get(); 
    } 

調用此方法getActivityFromWeakReference()而不是getActivity()安全根據內存泄漏的威脅?

如果這樣做不安全,我應該退回activityWeakReference並改爲調用它的get()方法,以確保安全嗎?

我一直在使用它在多個片段,到目前爲止我還沒有任何問題。我問這個問題,因爲我讀這個(here):

只要幫手的壽命是 Activity的生命週期內,那麼就沒有必要使用WeakReference。如果助手 的壽命可能比Activity長,那麼當系統 銷燬它時,應該使用WeakReference 以避免將Activity保留在對象圖中。

到目前爲止,我還沒有面對一個被引用的元素超出了活動的情況。請大家如果你發現一個錯誤或可能的只是寫在評論中。

+1

請注意,當'activityWeakReference'不爲null,但activityWeakReference.get()'爲時,您的方法可能會返回null。 –

+0

@Mateus Gondim,感謝您的輸入,我在使用之前已經檢查過null。 –

回答

5

這是完全可行的。例如,你有這個僞代碼:

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     new DownloadTask().execute(); 
    } 

    public void showInfo() { 
    } 

    class DownloadTask extends AsyncTask<Void, Void, Void> { 
     @Override 
     protected Void doInBackground(Void... params) { 
      return null; 
     } 

     @Override 
     protected void onPostExecute(Void data) { 
      // we can call showInfo() activity because Asynctask hold an implicit reference to activity 
      showInfo(); 
     } 
    } 
} 

關於上面的代碼,有一種情況會導致內存泄漏。

這裏的解釋是:

當您創建DownloadTask爲例以上,java調用DownloadTaskinner class。內部類將隱含持有對外部類的引用,在這種情況下是MainActivity。而且,當你開始一個asynctask時,這個asynctask將被系統持有,直到它完成。例如,你下載需要30秒。在那30秒內,您旋轉您的設備。當你旋轉你的設備時,MainActivityre-created,往往舊的活動將被破壞。但在這種情況下,舊活動不會被破壞,因爲舊的MainActivity實例由DownloadTask保存,DownloadTask由系統保存。您將泄漏一個活動實例。

爲了解決這個,你應該上面的代碼更改爲:

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     new DownloadTask(this).execute(); 
    } 

    public void showInfo() { 
    } 
} 

class DownloadTask extends AsyncTask<Void, Void, Void> { 
    WeakReference<MainActivity> mainActivityWeakReference; 

    public DownloadTask(MainActivity activity) { 
     mainActivityWeakReference = new WeakReference<MainActivity>(activity); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void data) { 
     if (mainActivityWeakReference.get() != null) { 
      mainActivityWeakReference.get().showInfo(); 
     } 
    } 
} 

在這種情況下,創建新的MainActivity時,舊的沒有被DownloadTask(由於弱引用屬性)舉行,所以未來的舊垃圾將被Android垃圾收集器銷燬。您還應該檢查每次使用弱引用對象時,因爲您不知道GC何時會銷燬這些對象。

這是我自己的博客,關於內存泄漏的另一種情況。 Memory leak when using static inner class

希望得到這個幫助。

+0

我應該明白,如果您使用上述方法(getActivityFromWeakReference()),那麼您剛纔描述的情況就可以了。 –

+2

@MaximeClaude是的,基本上這是真的。你將你的活動的WeakReference保留在「某個地方」,你應該把它作爲你的方法來使用(因爲在某些情況下,它會是空的,因爲GC已經清理了它)。 「某個地方」取決於很多情況,我的例子只是一個。 – hqt

+0

我已經更新了一些代碼。希望這個幫助。 – hqt

0

有些情況下,如果你的片段被設置爲保留實例,它會比活動時間長,或者你的片段被泄漏。