2017-08-02 10 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(); 
    } 

は、メモリリークの脅威に応じて代わりに安全なgetActivity()この方法getActivityFromWeakReference()を呼び出していますか?

安全でない場合は、activityWeakReferenceを返信し、その代わりにget()メソッドを呼び出して安全にしてください。

私はこれを複数のフラグメントで使用していますが、これまでのところ問題はありませんでした。私はこの(here)を読んでいるので、私は質問をする:

限りヘルパーの寿命が Activityの寿命の範囲内であるとして、その後、WeakReferenceを使用する必要はありません。ヘルパー がActivityよりも長く存続できる場合は、が破壊されたときにActivityをオブジェクトグラフに保持しないように、WeakReference を使用する必要があります。

これまでのところ、参照された要素がアクティビティよりも古くなったケースはありませんでした。もしあなたがエラーを見つけたら、あるいは可能な人がコメントにそれを書いてください。

+1

'activityWeakReference'がnullではなく、' activityWeakReference.get() 'がnullの場合、メソッドは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によって保持されているため、古いアクティビティは破棄されません。 1つのアクティビティー・インスタンスがリークします。そう、新しいMainActivityが作成されたとき

この場合
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(); 
     } 
    } 
} 

、古いものがDownloadTask(弱い参照属性に)で開催されていません。

はこれを固定するために、あなたはに上記のコード変更する必要があります将来はAndroidガベージコレクタによって古いものが破棄されます。弱参照オブジェクトを使用するたびに、GCがそれらのオブジェクトを破壊する時期を正確に把握していないので、チェックする必要があります。

メモリリークの別の状況についての私のブログです。 Memory leak when using static inner class

このヘルプが必要です。

+0

上記のメソッド(getActivityFromWeakReference())を使用すると、今説明したような場合でも問題ありません。 –

+2

@MaximeClaudeはい本当はそうです。あなたはあなたの活動のWeakReferenceを「ある場所」に保ちます。そして、あなたの方法としてそれを取得するべきです(なぜなら、場合によっては、GCがそれをきれいにするためにnullになるからです)。 「いくつかの場所」は多くの状況に左右され、私の例はただ一つです。 – hqt

+0

私はいくつかのコードを更新しました。この助けを願っています。 – hqt

0

フラグメントがインスタンスを保持するように設定されている場合、アクティビティよりも長くなるか、フラグメントがリークされる場合があります。

関連する問題