JavaおよびAndroid開発でWeakReferenceを使用する方法


166

私は2年間Java開発者をしてきました。

しかし、コードにWeakReferenceを記述したことはありません。WeakReferenceを使用して私のアプリケーション、特にAndroidアプリケーションをより効率的にする方法は?


:Android用の差分があるかもしれませんstackoverflow.com/questions/299659/...
Pacerier

回答:


229

WeakReferenceAndroidでのaの使用は、普通のJavaでの使用と何の違いもありません。これは、詳細な説明を提供する優れたガイドです:弱い参照の理解

オブジェクトへの参照が必要なときはいつでも使用することを検討する必要がありますが、その参照がオブジェクトをガベージコレクターから保護する必要はありません。古典的な例は、メモリ使用量が高くなりすぎた場合にガベージコレクションの対象とするキャッシュです(多くの場合で実装されますWeakHashMap)。

チェックアウトしてくださいSoftReferencePhantomReference同様。

編集:トムは、でキャッシュを実装することについていくつかの懸念を提起しましたWeakHashMap。ここに問題を説明する記事があります:WeakHashMapはキャッシュではありません!

トムは不満があったことは正しいWeakHashMapキャッシングによるNetbeansのパフォーマンスの低下について。

でキャッシュを実装しWeakHashMap、それをで実装した独自の手動ロールキャッシュと比較することは、良い学習経験になると思いますSoftReference。現実の世界では、Apache JCSのようなサードパーティのライブラリを使用する方が理にかなっているため、おそらくこれらのソリューションのどちらも使用しないでしょう。


15
番号!番号!番号!WeakHashMapキャッシュとして使用すると致命的です。エントリは、作成されるとすぐに削除できます。これは、テスト時にはおそらく発生しませんが、使用しているときには発生する可能性があります。注目すべきことに、これにより、NetBeansはCPUを効果的に100%停止させることができます。
トム・ホーティン-タックライン

3
@トム私は私の答えを更新しました。公平を期すために、私は技術的には正しかったが、キャッシュは多くのWeakHashMap場合、正しく選択されていてもキャッシュが実装されていることは正しい選択ではないことを
誤解し

1
dbyrneによる素晴らしい答え。これをありがとう。クリスがこの答えを受け入れない理由はないと思います。
さん

@dbyrne GridView、ImageView、BaseAdapterなどのアクティビティでオブジェクトを使用しています。onDestroyメソッドでは、アクティビティが終了したときに、Weak / SoftReferencesを使用してこのオブジェクトを処理する必要がありますか?または、システムはこのオブジェクトのこのメモリを自動的に消去しますか?

4
java.netへのリンク切れ
Suragch

64

[編集2]別の良い例を見つけましたWeakReferenceビットマップを効率的表示する」トレーニングガイドの「UIスレッド」ページからのビットマップの処理WeakReference、AsyncTaskでの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は存在しなくなる可能性があります。

幸せなコーディング!


[編集]WeakReferencefacebook-android-sdkからの本当に良い例を見つけました。ToolTipPopupクラスは、アンカービューの上にツールチップを表示する単純なウィジェットクラスにすぎません。スクリーンショットを撮りました。

素晴らしいスクリーンショット

クラスは本当にシンプル(約200行)で、見る価値があります。そのクラスでは、WeakReferenceクラスはアンカービューへの参照を保持するために使用されます。これは、ツールチップインスタンスがアンカービューよりも長く存続する場合でも、アンカービューがガベージコレクションされることを可能にするためです。

幸せなコーディング!:)


WeakReferenceクラスの実用的な例を1つ紹介しましょう。これはと呼ばれるAndroidフレームワークウィジェットの小さなコードスニペットAutoCompleteTextViewです。

つまり、 この例でWeakReference クラスを使用してオブジェクトを保持View し、メモリリークを防止しています

のネストされたクラスであるPopupDataSetObserverクラスをコピーして貼り付けAutoCompleteTextViewます。とてもシンプルで、コメントはクラスをよく説明しています。幸せなコーディング!:)

    /**
     * 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);
}

最後に一つだけ。WeakReferenceAndroidアプリケーションの実際の例も知りたかったのですが、公式のサンプルアプリケーションでいくつかのサンプルを見つけることができました。しかし、私はそれらの使用法のいくつかを本当に理解することができませんでした。たとえば、ThreadSampleおよびDisplayingBitmapsアプリケーションはWeakReferenceコードで使用しますが、いくつかのテストを実行した後null、参照されたビューオブジェクトがガベージコレクションではなくアダプターでリサイクルされるため、get()メソッドがを返さないことがわかりました。


1
素晴らしい例をありがとう-私はこれが質問の受け入れられた答えであるべきだと本当に感じています。乾杯!
Ackshaey Singh

@AckshaeySinghありがとう!:)
16 2016

16

他の回答の一部は、不完全または長すぎるようです。これが一般的な答えです。

JavaおよびAndroidでWeakReferenceを使用する方法

次の手順を実行できます。

  1. WeakReference変数を作成する
  2. 弱参照を設定する
  3. 弱参照を使用する

コード

MyClassへの弱い参照がありAnotherClassます。

public class MyClass {

    // 1. Create a WeakReference variable
    private WeakReference<AnotherClass> mAnotherClassReference;

    // 2. Set the weak reference (nothing special about the method name)
    void setWeakReference(AnotherClass anotherClass) {
        mAnotherClassReference = new WeakReference<>(anotherClass);
    }

    // 3. Use the weak reference
    void doSomething() {
        AnotherClass anotherClass = mAnotherClassReference.get();
        if (anotherClass == null) return;
        // do something with anotherClass
    }

}

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.setWeakReference(this);
    }
}

ノート

  • 弱い参照が必要な理由は、不要になったオブジェクトをガベージコレクターが破棄できるようにするためです。2つのオブジェクトが互いに強い参照を保持している場合、それらのオブジェクトをガベージコレクションすることはできません。これはメモリリークです。
  • 2つのオブジェクトが相互に参照する必要がある場合、オブジェクトA(通常は生存期間の短いオブジェクト)はオブジェクトB(通常は生存期間の長いオブジェクト)への弱い参照を持ち、BはAへの強い参照を持ちます。上記の例でMyClassは、Aでした。とAnotherClassBだった。
  • を使用する代わりに、WeakReference別のクラスにインターフェースを実装させることもできます。これは、リスナー/オブザーバーパターンで行われます。

実例


紛らわしい説明。何// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }ですか?
likejudo

@likejudo、その通りです。変数とメソッドの命名の一部を改善しました。今はどう?
Suragch

関数を呼び出す前にweakreferencedoSomething関数内のオブジェクト自体がないことを確認する必要があります。nullget
Behrouz.M

7

「正規化された」マッピングでは、問題のオブジェクトの1つのインスタンスをメモリに保持し、他のすべてのインスタンスは、ポインターまたはそのようなメカニズムを介してその特定のインスタンスを検索します。これは、弱点参照が役立つ場所です。簡単に言えば、WeakReferenceオブジェクトを使用して、システム内のオブジェクトへのポインターを作成し、スコープ外に出たガベージコレクターがそれらのオブジェクトを再利用できるようにします。たとえば、次のようなコードがあるとします。

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( object );
     }
 }

のセットに格納されている参照があるため、登録したオブジェクトがGCによって再利用されることはありませんregisteredObjects。一方、これを行うと:

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( new WeakReference(object) );
     }
 }

その後、GCがセット内のオブジェクトを再利用する場合、それを行うことができます。この手法は、キャッシング、カタログ作成などに使用できます。GCとキャッシングの詳細については、以下を参照してください。

参照:ガベージコレクターとWeakReference

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.