2013-08-18 6 views
44

मेरे पास एंड्रॉइड में इस साधारण अक्सर होने वाली स्थिति के बारे में कोई प्रश्न है।एंड्रॉइड में WeakReference/AsyncTask पैटर्न

हमारे पास एक मुख्य गतिविधि है, हम मुख्य एक्टिविटी के संदर्भ के साथ एक AsyncTask का आह्वान करते हैं, ताकि AsyncTask मुख्य क्रियाशीलता पर विचार अपडेट कर सके।

मैं चरणों में घटना नीचे टूट जाएगा

  • MainActivity एक AyncTask बनाता है, जिसे करने के लिए अपने संदर्भ से गुजरता है।
  • ऐन्सकटास्क, यह काम शुरू करता है, उदाहरण के लिए दस फाइलें डाउनलोड करना
  • उपयोगकर्ता ने डिवाइस का अभिविन्यास बदल दिया। इसके परिणामस्वरूप AsyncTask
  • में अनाथ पॉइंटर में परिणाम होता है जब AsyncTask पूर्ण हो जाता है, और स्थिति को अद्यतन करने के लिए गतिविधि तक पहुंचने का प्रयास करता है, तो यह शून्य सूचक के कारण क्रैश हो जाता है।

ऊपर के लिए समाधान के रूप में किताब "प्रो एंड्रॉयड 4"

WeakReference<Activity> weakActivity; 

in method onPostExecute 

Activity activity = weakActivity.get(); 
if (activity != null) { 
    // do your stuff with activity here 
} 

कैसे इस समस्या का समाधान करता है द्वारा सिफारिश की AsyncTask में एक WeakReference रखने के लिए है?

मेरा सवाल यह है कि, यदि मेरा एसिंक्टास्क दस फाइलें डाउनलोड कर रहा है, और 5 के पूरा होने पर गतिविधि को पुनरारंभ किया जाता है (अभिविन्यास परिवर्तन की वजह से) तो क्या मेरा फ़ाइलडाउनलोडिंग टास्क एक बार फिर से बुलाया जाएगा?

पिछली AsyncTask का क्या होगा जो शुरू में शुरू किया गया था?

धन्यवाद, और मैं प्रश्न की लंबाई के लिए क्षमा चाहता हूं।

+5

इस तरह के एक अच्छी तरह से गठित और शब्दबद्ध प्रश्न पोस्ट करने के लिए धन्यवाद। – Travis

उत्तर

32

यह स्थिति को कैसे हल करता है?

WeakReference की अनुमति देता है Activity कचरा, एकत्र होने के लिए तो आप एक स्मृति रिसाव नहीं है।

एक अशक्त संदर्भ मतलब यह है कि AsyncTaskआँख बंद करके एक उपयोगकर्ता इंटरफ़ेस है कि अब और नहीं जुड़ा हुआ है, जो अपवाद फेंक (जैसे विंडो प्रबंधक से जुड़ी नहीं देखें) अद्यतन करने के लिए नहीं कोशिश कर सकते हैं। बेशक आपको एनपीई से बचने के लिए शून्य की जांच करनी है।

यदि मेरा एसिंक्टास्क दस फाइलें डाउनलोड कर रहा है, और 5 के पूरा होने पर गतिविधि को पुनरारंभ किया जाता है (अभिविन्यास परिवर्तन की वजह से) तो क्या मेरा फ़ाइलडाउनलोडिंग टास्क एक बार फिर से बुलाया जाएगा?

आपके कार्यान्वयन पर निर्भर करता है, लेकिन शायद हां - यदि आप जानबूझकर दोहराना डाउनलोड करने के लिए कुछ नहीं करते हैं, जैसे परिणाम कहीं भी कैशिंग करना।

पिछली AsyncTask का क्या होगा जो शुरू में शुरू किया गया था?

एंड्रॉइड के पुराने संस्करणों में यह पूरा करने के लिए चला जाएगा, सभी फ़ाइलों को केवल उन्हें फेंकने के लिए डाउनलोड करना होगा (या शायद उन्हें कार्यान्वित करने के आधार पर उन्हें कैश करें)।

नए Android के दशक में मैं कर रहा हूँ संदिग्ध AsyncTask के Activity है कि उन्हें शुरू कर दिया के साथ मार डाला जा रहा है कि है, लेकिन संदेह के लिए मेरे आधार ही नहीं स्मृति रिसाव डेमो के RoboSpice के लिए (नीचे देखें) वास्तव में पर रिसाव नहीं है मेरी जेलीबीन डिवाइस।

यदि मैं कुछ सलाह दे सकता हूं: AsyncTask नेटवर्किंग जैसे संभावित लंबे समय तक चलने वाले कार्यों को करने के लिए उपयुक्त नहीं है।

IntentService एक बेहतर (और अभी भी अपेक्षाकृत सरल) दृष्टिकोण है, यदि एक एकल कार्यकर्ता धागा आपको स्वीकार्य है। यदि आप थ्रेड-पूल पर नियंत्रण चाहते हैं तो एक (स्थानीय) Service का उपयोग करें - और सावधान रहें कि मुख्य धागे पर काम न करें!

RoboSpice अच्छा लगता है अगर आप पृष्ठभूमि में विश्वसनीय रूप से नेटवर्किंग करने का कोई तरीका ढूंढ रहे हैं (अस्वीकरण: मैंने कोशिश नहीं की है; मैं संबद्ध नहीं हूं)। Play store में RoboSpice Motivations demo app है जो क्यों बताता है आपको AsyncTask के साथ गलत हो सकता है - वीक रेफरेंस वर्कअराउंड सहित सभी चीजों को डेमो-इन करके इसका उपयोग करना चाहिए।

भी इस सूत्र देखें: Is AsyncTask really conceptually flawed or am I just missing something?

अद्यतन:

मैं एक और तो सवाल (How to fix android.os.NetworkOnMainThreadException?) के लिए IntentService का उपयोग कर डाउनलोड करने का एक उदाहरण के साथ एक github project बनाया है, लेकिन इसे यहाँ भी प्रासंगिक है, मुझे लगता है। इसमें अतिरिक्त लाभ है कि, परिणाम onActivityResult के माध्यम से परिणाम लौटकर, जब आप डिवाइस को घुमाते हैं तो उड़ान में डाउनलोड होने पर डाउनलोड Activity को पुनरारंभ किया जाएगा।

+2

छोटे अद्यतन का उपयोग कर रहे हैं, तो WeakReference उपयोगी नहीं है: अब तक RxJava पृष्ठभूमि में कार्यों को चलाने के लिए एक मुख्य तरीका है, मुख्य थ्रेड से बाहर है और आपके परिणाम मुख्य थ्रेड पर वितरित किए गए हैं (ताकि आप अपडेट कर सकें यूआई आदि)। एक और विकल्प इवेंटबस का उपयोग करेगा, – AgentKnopf

6

WeakReference कक्षा मूल रूप से जेआरई को दिए गए उदाहरण के लिए संदर्भ काउंटर बढ़ाने के लिए रोकती है।

मैं जावा के मेमोरी प्रबंधन में नहीं जाऊंगा और सीधे आपके प्रश्न का उत्तर दूंगा: WeakReference यह जानने के लिए AsyncTask प्रदान करके स्थिति को हल करता है कि क्या इसकी मूल गतिविधि अभी भी मान्य है या नहीं।

अभिविन्यास परिवर्तन स्वयं स्वचालित रूप से AsyncTask को पुनरारंभ नहीं करेगा। आपको ज्ञात व्यवहार को ज्ञात तंत्र (onCreate/onDestroy, onSave/RestoreInstanceState) के साथ वांछित व्यवहार को कोड करना होगा।

मूल AsyncTask के संबंध में, मैं 100% यकीन है कि जो इन विकल्पों में से क्या होगा नहीं कर रहा हूँ: क्योंकि केवल वस्तु इसे करने के लिए एक संदर्भ (पकड़े

  • या तो जावा धागा बंद हो जाता है और AsyncTask disposes, मूल Activity)
  • नष्ट हो जाता है या फिर कुछ आंतरिक जावा वस्तु AsyncTask वस्तु के लिए एक संदर्भ का कहना है, अपने कचरा संग्रहण अवरुद्ध, प्रभावी ढंग से पृष्ठभूमि में समाप्त करने के लिए AsyncTask छोड़ने

किसी भी तरह से, AsyncTask मैन्युअल रूप से निरस्त/रोकें और फिर से शुरू करें/इसे फिर से शुरू करें (या इसे नए Activity पर सौंप दें), या इसके बजाय Service का उपयोग करें।

+0

जब आप AsyncTask गतिविधि गतिविधि – Qamar

1

यह स्थिति को कैसे हल करता है?

ऐसा नहीं है।

WeakReference का संदर्भ null पर सेट किया गया है जब कचरा कलेक्टर निर्धारित करता है कि रेफरेंस कमजोर पहुंच योग्य है। ऐसा तब नहीं होता जब कोई गतिविधि रोका जा सके, और जब गतिविधि नष्ट हो जाती है और फ्रेमवर्क इसके सभी संदर्भों को त्याग देता है तो तत्काल ऐसा नहीं होता है। यदि जीसी नहीं चला है, तो AsyncTask के लिए यह पूरी तरह से संभव है, जबकि WeakReference में अभी भी एक मृत गतिविधि का संदर्भ शामिल है।

न केवल यह, लेकिन यह दृष्टिकोण AsyncTask को बेकार उपभोग करने वाले CPU से रोकने के लिए कुछ भी नहीं करता है।

ActivityAsyncTask और cancel(...) के उचित टियरडाउन जीवन चक्र विधि में एक मजबूत संदर्भ बनाए रखने का एक बेहतर तरीका है। AsyncTask को isCancelled() पर नज़र रखना चाहिए और यदि इसकी आवश्यकता नहीं है तो काम करना बंद कर दें।

यदि आप कॉन्फ़िगरेशन परिवर्तनों में जीवित रहने के लिए AsyncTask चाहते हैं (लेकिन गतिविधि विनाश के अन्य रूपों में) आप इसे बनाए रखा खंड में होस्ट कर सकते हैं।

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