2017-01-19 5 views
4

私は少しジレンマに苦しんでいます。皆さんが私を助けてくれることを願っています。AsyncTaskにWeakReference <Context>またはApplication Contextを使用する必要がありますか?

ご覧のとおり、ギャラリーに.jpgファイルとしてBitmapオブジェクトを保存するコードがあるAsyncTaskがあります。 AsyncTask私はContextも使用していますが、この内部クラスのActivityのコンテキストを使用するとメモリリークが発生する可能性があるので、WeakReference<Context> weakContext;に変更してガベージコレクタで収集できます。

しかし、私は、コンストラクタから渡されたViewから取得Applicationコンテキストを使用することによって、私は弱いコンテキストの参照として

を同じ効果をアーカイブする必要があるので、この場合には他よりも使用するように任意の良いですか?

public class ViewToBitmap { 

private View view; 
private WeakReference<Context> weakContext; 

public ViewToBitmap(@NonNull View view) { 
    this.view = view; 
} 

// This? 
private WeakReference<Context> getContext() { 
    weakContext = new WeakReference<>(view.getContext()); 
    return weakContext; 
} 

// Or This? 
private Context getContext() { 
    return view.getContext().getApplicationContext(); 
} 

private class AsyncSaveBitmap 
       extends AsyncTask<Void, Void, Void> 
       implements MediaScannerConnection.OnScanCompletedListener { 

    @Override 
    protected Void doInBackground(Void... params) { 
     //TODO: Save bitmaps to gallery 
     //CONTEXT IS USED HERE 
     getContext().get() 
     return null; 
    } 
} 

答えて

4

Viewオブジェクトがビューの膨張時に使用されたContextへの明示的な参照を持っているので、あなたは効果的Viewへのハード参照を保つことによってViewToBitmapのインスタンスにContextに「推移」のハード参照を維持しています。

AsyncSaveBitmapstaticではないため、このクラスのインスタンスは、囲むインスタンスへの暗黙的な参照をViewToBitmapとしています。

AsyncSaveBitmapが存在する限り、Activityへのハード参照があり、そのActivityのGCが防止されます。

したがって、答えはありません。いずれのアプローチでも十分です。

アプローチは、何も実行時間の長いコードがContextへの参照を持っていないような方法でActivityをロジックをリファクタリングすることであろう最高のViewなど

これを達成する最も簡単な方法は、オブザーバーデザインパターンを使用することですPublish-Subscribeデザインパターンを使用して、ライフサイクルメソッド(例:onStop())で「登録解除」することができます。その結果、潜在的に危険な参照が削除され、メモリリークが防止されます。

EDIT:あなたは、必ずしも特定のContextを必要とし、アプリケーションのContextていないライブラリの目的のために、

で十分で、次のパターンは、(あなたのライブラリがシングルトンとして公開されているか否かに応じて)使用することができます:

// Use this approach if clients will use your library as Singleton 
private static Context sAppContext; 

public static void init(Context context) { 
    sAppContext = context.getApplicationContext(); 
} 

// Use this approach if clients will instantiate your library's object on each use 
private final Context mAppContext; 

public MyLibraryEntryClass(Context context) { 
    mAppContext = context.getApplicationContext(); 
} 
+0

私はあなたの提案を調べます。しかし、AsyncTaskクラスのインタフェースを介してContextを渡すのはどうでしょうか?それを静的にして、必要なすべての変数をコンストラクタ経由で渡しますか? – Muddz

+0

このコードは実際にはライブラリの一部なので、ユーザーがonStop()で余分なコードを手作業で書かなくても構わないようにしてください。私が実際にコンテキストを使用する唯一の場所は 'MediaScannerConnection.scanFile(context、new String [] {file.toString()}、null、this);'保存されたビットマップをスキャンするための行です。 – Muddz

+0

@Muddz、 「コンテキスト」を必要とする場合、有効なアプローチはアプリケーションのコンテキストを使用することです。これは、 'getApplicationContext()'を呼び出すことによって他の 'Context'から取得できます。アプリケーションのコンテキストはシングルトンとして扱うことができるため、メモリリークのリスクなしにローカル変数に格納することができます。しかし、このアプローチは最後の手段としてのみ使用すべきである。 – Vasiliy

関連する問題