2017-08-02 11 views
5

मेमोरी रिसाव से बचने के लिए मैंने निम्नलिखित विधि लिखी है जिसका उपयोग गतिविधियों में और मुख्य रूप से टुकड़ों (विरासत का उपयोग करके) में किया जाएगा। यही कारण है कि विधि के लिए मुझे कभी सीधेgetActivity() के बजाय कमजोर संदर्भ (एंड्रॉइड मेमोरी रिसाव से बचें)?

//this or getActivity() 

बुला विधि द्वारा गतिविधि को रेफ़र करने की अनुमति माना जाता है है:

private WeakReference<BaseActivity> activityWeakReference = null; 

public BaseActivity getActivityFromWeakReference(){ 
     activityWeakReference = activityWeakReference == null ? 
       new WeakReference<BaseActivity>((BaseActivity)getActivity()) : 
       activityWeakReference; 
     return activityWeakReference.get(); 
    } 

इस विधि getActivityFromWeakReference() बुला रहा है getActivity() सुरक्षित करने के बजाय स्मृति रिसाव खतरा के अनुसार?

यदि ऐसा करना सुरक्षित नहीं है, तो क्या मुझे activityWeakReference वापस कर देना चाहिए और इसे सुरक्षित बनाने के लिए get() विधि को कॉल करना चाहिए?

मैं इसे कई टुकड़ों में उपयोग कर रहा हूं और मुझे अब तक कोई समस्या नहीं है। क्योंकि मैं इस (here) को पढ़ने मैं सवाल पूछ:

जब तक सहायक के जीवनकाल Activity के जीवन भर के भीतर है, तो वहाँ एक WeakReference उपयोग करने की आवश्यकता है। यदि सहायक Activity से अधिक समय तक जीवित रह सकता है, तो आपको सिस्टम को नष्ट करने पर आपके ऑब्जेक्ट ग्राफ़ में Activity को बनाए रखने से बचने के लिए WeakReference का उपयोग करना चाहिए।

अब तक, मुझे ऐसे मामले का सामना नहीं करना पड़ा जहां एक निर्दिष्ट तत्व गतिविधि को पार कर गया। अगर आपको कोई त्रुटि मिलती है या संभव है तो कृपया इसे टिप्पणियों में लिखें।

+1

ध्यान दें कि आपकी विधि शून्य हो सकती है, जब 'गतिविधिवाइक रेफरेंस' शून्य नहीं है, लेकिन 'ActivityWeakReference.get() 'है। –

+0

@ मेटस गोंडिम, इनपुट के लिए धन्यवाद, मैं इसे पहले इस्तेमाल करने से पहले शून्य की जांच करता हूं। –

उत्तर

5

यह पूरी तरह से व्यवहार्य है। उदाहरण के लिए आपके पास यह छद्म कोड है:

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     new DownloadTask().execute(); 
    } 

    public void showInfo() { 
    } 

    class DownloadTask extends AsyncTask<Void, Void, Void> { 
     @Override 
     protected Void doInBackground(Void... params) { 
      return null; 
     } 

     @Override 
     protected void onPostExecute(Void data) { 
      // we can call showInfo() activity because Asynctask hold an implicit reference to activity 
      showInfo(); 
     } 
    } 
} 

उपरोक्त कोड पर, एक स्थिति मेमोरी रिसाव के कारण होगी।

जब आप DownloadTask उपरोक्त उदाहरण के रूप में बनाने के लिए, जावा कॉल DownloadTask एक inner class है:

यहाँ व्याख्या है। एक आंतरिक कक्षा निहित बाहरी वर्ग का संदर्भ रखती है, इस मामले में MainActivity है। इसके अलावा, जब आप एसिन्टास्क शुरू करते हैं, तो एसिंकक्टस्क सिस्टम द्वारा तब तक आयोजित किया जाएगा जब तक कि यह खत्म न हो जाए। उदाहरण के लिए, आप डाउनलोड 30 सेकंड लेता है। उस 30 सेकंड में, आप अपने डिवाइस को घुमाते हैं। जब आप अपने डिवाइस को घुमाते हैं, MainActivityre-created है और अक्सर पुरानी गतिविधि नष्ट हो जाएगी। लेकिन इस मामले में पुरानी गतिविधि नष्ट नहीं हुई है क्योंकि पुराना MainActivity उदाहरण DownloadTask और DownloadTask द्वारा आयोजित किया जाता है सिस्टम द्वारा धारण किया जाता है। आप एक गतिविधि उदाहरण रिसाव करेंगे।

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     new DownloadTask(this).execute(); 
    } 

    public void showInfo() { 
    } 
} 

class DownloadTask extends AsyncTask<Void, Void, Void> { 
    WeakReference<MainActivity> mainActivityWeakReference; 

    public DownloadTask(MainActivity activity) { 
     mainActivityWeakReference = new WeakReference<MainActivity>(activity); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void data) { 
     if (mainActivityWeakReference.get() != null) { 
      mainActivityWeakReference.get().showInfo(); 
     } 
    } 
} 

इस मामले में, जब नए MainActivity बनाया जाता है, एक पुरानी DownloadTask (कमजोर संदर्भ विशेषता की वजह से) द्वारा आयोजित नहीं है, इसलिए:

इस फिक्सिंग के लिए, आप कोड के ऊपर करने के लिए बदलना चाहिए भविष्य में एंड्रॉइड कचरा कलेक्टर द्वारा पुराना नष्ट हो जाएगा।जब भी आप एक कमजोर संदर्भ वस्तु का उपयोग करते हैं, तो आपको भी जांचना चाहिए, क्योंकि आप बिल्कुल नहीं जानते कि जीसी उन वस्तुओं को नष्ट कर देगा।

मेमोरी रिसाव की एक और स्थिति के बारे में मेरा ब्लॉग यहां है। Memory leak when using static inner class

इस सहायता की आशा करें।

+0

क्या मुझे यह समझना चाहिए कि, यदि आप उपरोक्त मेरी विधि का उपयोग करते हैं (getActivityFromWeakReference()) यह आपके द्वारा अभी वर्णित मामले में ठीक होगा। –

+2

@MaximeClaude हाँ मूल रूप से यह सच है। आप "कुछ जगह" पर अपनी गतिविधि के वीक रेफरेंस को रखते हैं, और आपको इसे अपनी विधि के रूप में प्राप्त करना चाहिए (क्योंकि किसी मामले में, यह शून्य हो जाएगा क्योंकि जीसी ने इसे साफ़ कर दिया है)। "कुछ जगह" कई स्थितियों पर निर्भर करती है, मेरा उदाहरण सिर्फ एक है। – hqt

+0

मैंने कुछ कोड अपडेट किया है। उममीद है कि इससे मदद मिलेगी। – hqt

0

कुछ मामला हैं, यदि आपका टुकड़ा उदाहरण बनाए रखने के लिए सेट है, तो यह गतिविधि से अधिक लंबा होगा, या यदि आपका टुकड़ा लीक हो गया है।

संबंधित मुद्दे