私はJava開発者として2年間働いています。
しかし、コードにWeakReferenceを記述したことはありません。 WeakReferenceを使用してアプリケーション、特にAndroidアプリケーションをより効率的にする方法は?
AndroidでWeakReference
を使用することは、単純な古いJavaで使用することと変わりません。詳細な説明を提供する素晴らしいガイドがあります: nderstanding Weak References 。
オブジェクトへの参照が必要な場合はいつでも使用することを検討する必要がありますが、その参照がオブジェクトをガベージコレクターから保護することは望ましくありません。典型的な例は、メモリ使用量が高くなりすぎたときにガベージコレクションを行いたいキャッシュです(多くの場合、WeakHashMap
で実装されます)。
必ずSoftReference
とPhantomReference
もチェックアウトしてください。
EDIT:トムはWeakHashMap
を使用してキャッシュを実装することに関して懸念を表明しました。ここに問題を説明する記事があります: WeakHashMapはキャッシュではありません!
トムは、WeakHashMap
キャッシングによるNetbeansパフォーマンスの低下について 苦情 があったことは正しいです。
WeakHashMap
を使用してキャッシュを実装し、SoftReference
を使用して実装された独自の手動ロールキャッシュと比較することは、まだ良い学習経験になると思います。 Apache JCS のようなサードパーティのライブラリを使用する方が理にかなっているため、現実の世界ではこれらのソリューションのいずれも使用しないでしょう。
[EDIT2] WeakReference
の別の良い例を見つけました。 UIスレッドからのビットマップの処理 ページの ビットマップの効率的な表示 トレーニングガイドでは、AsyncTaskのWeakReference
の1つの使用法を示しています。
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(Integer... params) {
data = params[0];
return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
それは言います、
ImageViewへのWeakReferenceは、AsyncTaskがImageViewおよびそれが参照するものがガベージコレクションされることを妨げないことを保証します。タスクが終了してもImageViewがまだ存在しているという保証はないため、onPostExecute()で参照も確認する必要があります。たとえば、ユーザーがアクティビティから移動したり、タスクが完了する前に構成が変更されたりすると、ImageViewは存在しなくなる可能性があります。
ハッピーコーディング!
[EDIT] facebook-Android-sdk からWeakReference
の非常に良い例を見つけました。 ToolTipPopup クラスは、アンカービューの上にツールチップを表示する単純なウィジェットクラスにすぎません。スクリーンショットをキャプチャしました。
このクラスは本当にシンプル(約200行)で、見る価値があります。そのクラスでは、WeakReference
クラスを使用してアンカービューへの参照を保持します。これは、ツールチップインスタンスがアンカービューより長く存続している場合でもアンカービューをガベージコレクションできるため、完全に理にかなっています。
ハッピーコーディング! :)
WeakReference
クラスの実例を1つ紹介します。これは、 AutoCompleteTextView
と呼ばれるAndroidフレームワークウィジェットの小さなコードスニペットです。
要するに、WeakReference
クラスは、View
オブジェクトを保持するために使用され、 メモリリーク この例では。
AutoCompleteTextView
のネストされたクラスであるPopupDataSetObserverクラスをコピーして貼り付けます。それは本当にシンプルで、コメントはクラスをよく説明しています。ハッピーコーディング! :)
/**
* Static inner listener that keeps a WeakReference to the actual AutoCompleteTextView.
* <p>
* This way, if adapter has a longer life span than the View, we won't leak the View, instead
* we will just leak a small Observer with 1 field.
*/
private static class PopupDataSetObserver extends DataSetObserver {
private final WeakReference<AutoCompleteTextView> mViewReference;
private PopupDataSetObserver(AutoCompleteTextView view) {
mViewReference = new WeakReference<AutoCompleteTextView>(view);
}
@Override
public void onChanged() {
final AutoCompleteTextView textView = mViewReference.get();
if (textView != null && textView.mAdapter != null) {
// If the popup is not showing already, showing it will cause
// the list of data set observers attached to the adapter to
// change. We can't do it from here, because we are in the middle
// of iterating through the list of observers.
textView.post(updateRunnable);
}
}
private final Runnable updateRunnable = new Runnable() {
@Override
public void run() {
final AutoCompleteTextView textView = mViewReference.get();
if (textView == null) {
return;
}
final ListAdapter adapter = textView.mAdapter;
if (adapter == null) {
return;
}
textView.updateDropDownForFilter(adapter.getCount());
}
};
}
また、PopupDataSetObserver
はアダプターの設定に使用されます。
public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
if (mObserver == null) {
mObserver = new PopupDataSetObserver(this);
} else if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
}
mAdapter = adapter;
if (mAdapter != null) {
//noinspection unchecked
mFilter = ((Filterable) mAdapter).getFilter();
adapter.registerDataSetObserver(mObserver);
} else {
mFilter = null;
}
mPopup.setAdapter(mAdapter);
}
最後に一つだけ。また、AndroidアプリケーションでWeakReference
の動作例を知りたいと思っていました。公式サンプルアプリケーションでいくつかのサンプルを見つけることができました。しかし、私はそれらの使用法のいくつかを本当に理解できませんでした。たとえば、 ThreadSample および DisplayingBitmaps アプリケーションはコードでWeakReference
を使用しますが、いくつかのテストを実行した後、参照されたビューオブジェクトはガベージコレクションではなくアダプタでリサイクルされるため、get()メソッドがnull
を返すことはありません。
他の回答の中には、不完全または過度に長いものがあります。一般的な答えを次に示します。
次の手順を実行できます。
WeakReference
変数を作成しますMyClass
には、AnotherClass
への弱い参照があります。
public class MyClass {
// 1. Create a WeakReference variable
private WeakReference<AnotherClass> mAnotherClassReference;
// 2. Set the weak reference
void someMethod(AnotherClass object) {
mAnotherClassReference = new WeakReference<>(object);
}
// 3. Use the weak reference
void anotherMethod() {
AnotherClass object = mAnotherClassReference.get();
if (object == null) return;
// do something with the object
}
}
AnotherClass
には、MyClass
への強い参照があります。
public class AnotherClass {
// strong reference
MyClass mMyClass;
// allow MyClass to get a weak reference to this class
void someMethod() {
mMyClass = new MyClass();
mMyClass.someMethod(this);
}
}
MyClass
はAで、AnotherClass
はBでした。WeakReference
を使用する代わりに、別のクラスにインターフェースを実装させることができます。これは Listener/Observer Pattern で行われます。「正規化された」マッピングでは、問題のオブジェクトの1つのインスタンスをメモリに保持し、他のすべてのインスタンスはポインターまたは何らかのメカニズムを介してその特定のインスタンスを検索します。これは、弱参照が役立つ場所です。簡単な答えは、WeakReferenceオブジェクトを使用して、システム内のオブジェクトへのポインターを作成しながら、それらのオブジェクトをgarbage-collectorスコープ外に出ると。たとえば、次のようなコードがあった場合:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( object );
}
}
登録したオブジェクトは、registeredObjects
のセットに格納された参照があるため、GCによって回収されることはありません。一方、これを行う場合:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( new WeakReference(object) );
}
}
その後、GCがSet内のオブジェクトを回収したい場合、回収することができます。この手法は、キャッシュ、カタログ化などに使用できます。GCとキャッシュの詳細については、以下を参照してください。