Java ve Android geliştirmede WeakReference nasıl kullanılır?


Yanıtlar:


229

Bir Kullanarak WeakReferenceAndroid'de düz eski Java birini kullanarak daha farklı değildir. Ayrıntılı bir açıklama veren harika bir kılavuz: Zayıf Referansları Anlama .

Bir nesneye başvurmak istediğinizde bir tane kullanmayı düşünmelisiniz, ancak nesneyi çöp toplayıcıdan korumak için bu başvuruyu istemezsiniz. Klasik bir örnek, bellek kullanımı çok yükseldiğinde (genellikle uygulandığında WeakHashMap) çöp toplanmasını istediğiniz bir önbellektir .

Kontrol etmeyi unutmayın SoftReferenceve PhantomReferencede.

EDIT: Tom ile önbellek uygulama konusunda bazı endişeler dile getirdi WeakHashMap. Sorunları ortaya koyan bir makale: WeakHashMap bir önbellek değil!

Tom, önbellekleme nedeniyle zayıf Netbeans performansı hakkında şikayetler olduğu konusunda haklı WeakHashMap.

Hala bir önbellek uygulamak WeakHashMapve daha sonra kendi el ile haddelenmiş önbellek ile karşılaştırıldığında karşılaştırmak için iyi bir öğrenme deneyimi olacağını düşünüyorum SoftReference. Gerçek dünyada, muhtemelen bu çözümlerden hiçbirini kullanmazsınız, çünkü Apache JCS gibi bir üçüncü taraf kütüphanesi kullanmak daha mantıklıdır .


15
Hayır! Hayır! Hayır! WeakHashMapönbellek olarak kullanılan ölümcül. Girişler oluşturulur oluşturulmaz kaldırılabilir. Bu muhtemelen test ederken gerçekleşmez, ancak kullanımda iyi olabilir. NetBeans bununla% 100 etkili bir CPU durağına getirilebilir.
Tom Hawtin - tackline

3
@Tom Cevabımı güncelledim. Adil olmak gerekirse, ben teknik WeakHashMapkötü bir seçim olduğunu doğru olsa bile önbellekleri sık sık uygulanan doğruydu;)
dbyrne

1
Dbyrne tarafından mükemmel cevap. Bunun için teşekkürler. Chris'in bu cevabı kabul etmemesi için hiçbir neden göremiyorum.
san

@dbyrne Etkinliğimde GridView, ImageView veya BaseAdapter gibi nesneler kullanıyorum. OnDestroy yönteminde, etkinliği bitirdiğimde, Weak / SoftReferences kullanarak bu nesnelerle bir şey yapmam gerekir mi? Veya sistem bu nesnenin bu belleğini otomatik olarak temizler mi?
beni

4
java.net kırık bağlantısı
Suragch

64

[EDIT2] için iyi bir örnek daha buldum WeakReference. Bitmap'leri İşleme Bitmap'leri Görüntüleme eğitim kılavuzundaki UI İş Parçacığı sayfasından Kapalı,WeakReference AsyncTask'te bir kullanımını gösterir .

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

Diyor ki,

ImageView'e yapılan WeakReference, AsyncTask'in ImageView ve referans aldığı herhangi bir şeyin çöp toplanmasını engellememesini sağlar . Görev bittiğinde ImageView'in hala orada olduğuna dair bir garanti yoktur, bu nedenle onPostExecute () içindeki referansı da kontrol etmeniz gerekir. Örneğin, kullanıcı etkinlikten uzaklaşırsa veya görev tamamlanmadan bir yapılandırma değişikliği olursa ImageView artık mevcut olmayabilir.

Mutlu kodlama!


[EDIT] Ben gerçekten iyi bir örnek buldum WeakReferencedan facebook-android-sdk . ToolTipPopup sınıfı, çapa görünümünün üzerinde araç ipucunu gösteren basit bir widget sınıfından başka bir şey değildir. Bir ekran görüntüsü yakaladım.

scrumptious ekran görüntüsü

Sınıf gerçekten basit (yaklaşık 200 satır) ve bakmak için layık. Bu sınıfta, WeakReferencesınıf, çapa görünümüne referans tutmak için kullanılır, bu da mantıklıdır, çünkü bir araç ipucu örneği, çapa görünümünden daha uzun sürse bile çapa görünümünün çöp toplanmasını mümkün kılar.

Mutlu kodlama! :)


WeakReferenceSınıfın çalışan bir örneğini paylaşayım. Android çerçeve widget denilen küçük bir kod snippet AutoCompleteTextView.

Kısacası, WeakReference sınıf bu örnekte bellek sızıntısını önlemek için nesneyi tutmak için kullanılır .View

Ben sadece iç içe bir sınıf olan PopupDataSetObserver sınıfını kopyalayıp yapıştıracağım AutoCompleteTextView. Gerçekten basit ve yorumlar sınıfı iyi açıklıyor. Mutlu kodlama! :)

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

Ve PopupDataSetObserveradaptörün ayarlanmasında kullanılır.

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

Son bir şey. Ayrıca WeakReferenceAndroid uygulamasında çalışan bir örnek bilmek istedim ve resmi örnek uygulamalarında bazı örnekler bulabilirim. Ama bazılarının kullanımını gerçekten anlayamadım. Örneğin, ThreadSample ve DisplayingBitmaps uygulamaları WeakReferencekodunda kullanır, ancak birkaç test çalıştırdıktan sonra null, referans (get) nesnesi, toplanan çöp yerine adaptörlerde geri dönüştürüldüğü için get () yönteminin hiçbir zaman geri dönmediğini öğrendim .


1
Harika örnekler için teşekkürler - bunun soru için kabul edilen cevap olması gerektiğini hissediyorum. Şerefe!
Ackshaey Singh

@AckshaeySingh Teşekkürler! :)
김준호

16

Diğer cevapların bazıları eksik veya aşırı uzun görünüyor. İşte genel bir cevap.

Java ve Android'de WeakReference nasıl kullanılır?

Aşağıdaki adımları uygulayabilirsiniz:

  1. WeakReferenceDeğişken oluşturma
  2. Zayıf referansı ayarlayın
  3. Zayıf referansı kullanın

kod

MyClasszayıf bir referansı var 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
    }

}

AnotherClassgüçlü bir referansı var 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);
    }
}

notlar

  • Zayıf bir referansa ihtiyacınızın nedeni, Çöp Toplayıcı'nın nesneleri artık ihtiyaç duyulmadığında bertaraf edebilmesidir. İki nesne birbirine güçlü bir referans tutarsa, çöp toplanamazlar. Bu bir bellek sızıntısı.
  • İki objenin birbirine nesne A (genellikle daha kısa ömürlü nesne) referans gerekirse B Yukarıdaki örnekte A'ya kuvvetli referans sahipken, nesne B zayıf bir referans (genellikle daha uzun ömürlü bir amacı) sahip olmalıdır, MyClassA, ve AnotherClassB idi.
  • A kullanmanın bir alternatifi WeakReference, başka bir sınıfın arabirim uygulamasıdır. Bu, Dinleyici / Gözlemci Düzeninde yapılır .

Pratik örnek


kafa karıştırıcı açıklama. nedir // allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }??
likejudo

@likejudo, Haklısın. Bazı değişken ve yöntem adlandırma geliştirdim. Şimdi nasıl?
Suragch

fonksiyon çağrılmadan önce weakreferencenesnenin kendisini doSomethingfonksiyonda kontrol etmeniz gerekir . nullget
Behrouz.M

7

"Standartlaştırılmış" eşleme, söz konusu nesnenin bir örneğini bellekte tuttuğunuz yerdir ve diğerlerinin tümü bu örneği işaretçiler veya somesuch mekanizması aracılığıyla arar. Burada zayıflar referansları yardımcı olabilir. Kısa yanıt, WeakReference nesnelerinin sisteminizdeki nesnelere işaretçiler oluşturmak için kullanılabilmeleri ve bu nesnelerin kapsam dışına çıktıklarında çöp toplayıcı tarafından geri kazanılmalarına izin vermesidir . Örneğin böyle bir kod vardı:

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

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

Kaydettiğim herhangi bir nesne, GC tarafından geri alınmayacaktır, çünkü kümesinde saklanan bir referans vardır registeredObjects. Öte yandan bunu yaparsam:

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

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

Daha sonra GC, Set'teki nesneleri geri almak istediğinde bunu yapabilir. Bu tekniği önbellekleme, kataloglama vb. İçin kullanabilirsiniz. GC ve önbelleğe alma hakkında daha ayrıntılı tartışmalara başvurmak için aşağıya bakın.

Ref: Çöp toplayıcı ve WeakReference

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.