जावा और Android विकास में WeakReference का उपयोग कैसे करें?


166

मैं 2 साल से जावा डेवलपर रहा हूं।

लेकिन मैंने अपने कोड में कभी भी WeakReference नहीं लिखा है। अपने एप्लिकेशन को विशेष रूप से Android एप्लिकेशन को अधिक कुशल बनाने के लिए WeakReference का उपयोग कैसे करें?


एंड्रॉइड के लिए एक अंतर हो सकता है: stackoverflow.com/questions/299659/…
Pacerier

जवाबों:


229

WeakReferenceएंड्रॉइड में उपयोग करना सादे पुराने जावा में एक का उपयोग करने से अलग नहीं है। यहां एक महान मार्गदर्शक है जो एक विस्तृत विवरण देता है: कमजोर संदर्भों को समझना

जब भी आपको किसी ऑब्जेक्ट के संदर्भ की आवश्यकता हो, तो आपको एक का उपयोग करने के बारे में सोचना चाहिए, लेकिन आप उस संदर्भ को कचरा कलेक्टर से बचाने के लिए नहीं चाहते हैं। एक क्लासिक उदाहरण एक कैश है जिसे आप कचरा एकत्र करना चाहते हैं जब मेमोरी उपयोग बहुत अधिक हो जाता है (अक्सर इसके साथ लागू किया जाता है WeakHashMap)।

बाहर SoftReferenceऔर PhantomReferenceसाथ ही जांच करना सुनिश्चित करें ।

EDIT: टॉम ने कैश को लागू करने को लेकर कुछ चिंताएं जताई हैं WeakHashMap। यहाँ समस्याओं को दूर करने वाला एक लेख है: WeakHashMap कैश नहीं है!

टॉम सही है कि कैशिंग के कारण खराब नेटबेंस के प्रदर्शन के बारे में शिकायतें आई हैं WeakHashMap

मुझे अभी भी लगता है कि कैश को लागू करना एक अच्छा सीखने का अनुभव होगा WeakHashMapऔर फिर इसे अपने हाथ से रोल किए गए कैश के साथ तुलना करें SoftReference। वास्तविक दुनिया में, आप शायद इनमें से किसी भी समाधान का उपयोग नहीं करेंगे, क्योंकि यह अपाचे जेसीएस जैसी 3 पार्टी लाइब्रेरी का उपयोग करने के लिए अधिक समझ में आता है ।


15
नहीं! नहीं! नहीं! WeakHashMapकैश के रूप में इस्तेमाल घातक है। जैसे ही वे बनाए जाते हैं, प्रविष्टियाँ निकाली जा सकती हैं। यह शायद तब नहीं होगा जब आप परीक्षण कर रहे हैं, लेकिन उपयोग में होने पर अच्छी तरह से हो सकता है। ध्यान से, नेटबीन्स को इसके द्वारा प्रभावी 100% सीपीयू स्टॉप पर लाया जा सकता है।
टॉम हॉन्टिन -

3
@ मैं अपना जवाब अपडेट कर चुका हूं। हालांकि निष्पक्ष होना, मैं तकनीकी रूप से सही था कि कैश को अक्सर लागू किया जाता है WeakHashMapभले ही आप सही हों कि यह एक बुरा विकल्प है;)
dbyrne

1
Dbyrne द्वारा उत्कृष्ट उत्तर। इसके लिए धन्यवाद। मैं इस जवाब को स्वीकार नहीं करने के लिए क्रिस के लिए कोई कारण नहीं देखता हूं।
सान

@dbyrne मैं अपनी गतिविधि में ऑब्जेक्ट्स का उपयोग कर रहा हूं, जैसे GridView, ImageView या BaseAdapter। OnDestroy विधि में, जब मैं गतिविधि समाप्त करता हूं, तो क्या मुझे इस ऑब्जेक्ट के साथ Weak / SoftReferences का उपयोग करके कुछ करने की आवश्यकता है? या सिस्टम स्वतः इस ऑब्जेक्ट की मेमोरी को साफ करता है?
बेनी

4
java.net का टूटा लिंक
सुरगछ

64

[EDIT2] मुझे इसका एक और अच्छा उदाहरण मिला WeakReference। Bitmaps को प्रदर्शित करने के लिए UI थ्रेड पृष्ठ से बिटमैप को संसाधित करना कुशल प्रशिक्षण मार्गदर्शिका, WeakReferenceAsyncTask में एक उपयोग दिखाता है।

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 अब मौजूद नहीं हो सकता है, उदाहरण के लिए, यदि उपयोगकर्ता गतिविधि से दूर हो जाता है या यदि कार्य समाप्त होने से पहले कॉन्फ़िगरेशन परिवर्तन होता है।

हैप्पी कोडिंग!


[संपादित करें] मुझे facebook-android-sdkWeakReference से एक बहुत अच्छा उदाहरण मिला । ToolTipPopup क्लास एक साधारण विजेट क्लास के अलावा और कुछ भी नहीं है जो एंकर व्यू के ऊपर टूलटिप दिखाता है। मैंने एक स्क्रीनशॉट कैप्चर किया।

शानदार स्क्रीनशॉट

कक्षा वास्तव में सरल है (लगभग 200 लाइनें) और देखने के योग्य है। उस वर्ग में, WeakReferenceएंकर दृश्य के संदर्भ को रखने के लिए क्लास का उपयोग किया जाता है, जो सही अर्थों में बनाता है, क्योंकि एंकर व्यू को कचरा एकत्र करने के लिए संभव बनाता है, जब टूलटिप का उदाहरण एंकर व्यू से अधिक समय तक रहता है।

हैप्पी कोडिंग! :)


मुझे WeakReferenceकक्षा के एक कामकाजी उदाहरण को साझा करने दें । यह एंड्रॉइड फ्रेमवर्क विजेट से थोड़ा कोड स्निपेट है जिसे कहा जाता है AutoCompleteTextView

संक्षेप में, इस उदाहरण में स्मृति रिसाव को रोकने के लिए ऑब्जेक्ट को WeakReference रखने के लिए क्लास का उपयोग किया जाता है View

मैं सिर्फ पॉपअपडॉटसैटऑब्जर्वर क्लास को कॉपी-एंड-पेस्ट करूंगा, जो कि एक नेस्टेड क्लास है 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);
}

एक अंतिम बात। मैं WeakReferenceएंड्रॉइड एप्लिकेशन में काम करने के उदाहरण को भी जानना चाहता था , और मुझे इसके आधिकारिक नमूना अनुप्रयोगों में कुछ नमूने मिल सकते थे। लेकिन मैं वास्तव में उनमें से कुछ के उपयोग को समझ नहीं पाया। उदाहरण के लिए, ThreadSample और DisplayingBitmaps अनुप्रयोगों का उपयोग WeakReferenceअपने कोड में, लेकिन कई परीक्षण चलाने के बाद, मुझे पता चला है कि प्राप्त () विधि देता है कभी नहीं null, क्योंकि संदर्भित दृश्य वस्तु एडेप्टर में कचरा एकत्र पुनर्नवीनीकरण है, बल्कि उसके बाद।


1
महान उदाहरणों के लिए धन्यवाद - मुझे वास्तव में लगता है कि यह प्रश्न के लिए स्वीकृत उत्तर होना चाहिए। चीयर्स!
आकाश सिंह

@AksshaeySingh धन्यवाद! :)

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

टिप्पणियाँ

  • आपको एक कमजोर संदर्भ की आवश्यकता है, ताकि गारबेज कलेक्टर उन वस्तुओं का निपटान कर सके जब उनकी आवश्यकता नहीं है। यदि दो वस्तुएं एक दूसरे के लिए एक मजबूत संदर्भ बनाए रखती हैं, तो वे कचरा एकत्र नहीं कर सकते हैं। यह एक मेमोरी लीक है।
  • यदि दो वस्तुओं को एक दूसरे को संदर्भित करने की आवश्यकता होती है, तो ऑब्जेक्ट A (आमतौर पर छोटी जीवित वस्तु) में ऑब्जेक्ट B (आमतौर पर लंबी जीवित वस्तु) के लिए एक कमजोर संदर्भ होना चाहिए, जबकि B का ए के लिए एक मजबूत संदर्भ है। उपरोक्त उदाहरण में, MyClassA था और AnotherClassबी।
  • एक का उपयोग करने का एक विकल्प एक WeakReferenceऔर वर्ग के लिए एक इंटरफ़ेस को लागू करना है। यह श्रोता / प्रेक्षक पैटर्न में किया जाता है ।

व्यावहारिक उदाहरण


भ्रामक व्याख्या। क्या है // allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }??
जैसे तैसे

@ लाइकजूडो, यू आर राइट। मैंने नामकरण और विधि के कुछ नामकरण में सुधार किया। अब यह कैसा है?
०१:२३ पर सर्ग

आपको फ़ंक्शन को कॉल करने से पहले नहीं होने के लिए फ़ंक्शन को weakreferenceस्वयं जांचना होगा । doSomethingnullget
बेहरोज़

7

एक "canonicalized" मानचित्रण वह जगह है जहाँ आप ऑब्जेक्ट के एक उदाहरण को स्मृति में रखते हैं और अन्य सभी उस विशेष उदाहरण को पॉइंटर्स या सोमेसच तंत्र के माध्यम से देखते हैं। यह वह जगह है जहां से संदर्भ संदर्भ में मदद कर सकता है। संक्षिप्त उत्तर यह है कि 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 सेट में वस्तुओं को पुनः प्राप्त करना चाहता है तो वह ऐसा करने में सक्षम होगा। आप कैशिंग, कैटलॉगिंग आदि के लिए इस तकनीक का उपयोग कर सकते हैं, जीसी और कैशिंग की अधिक गहन चर्चा के संदर्भ के लिए नीचे देखें।

रेफरी: कचरा कलेक्टर और कमजोर संदर्भ

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.