लंबे समय तक चलने वाले संचालन के लिए Android AsyncTask


90

यहाँ पाए गए AsyncTask के दस्तावेज़ का हवाला देते हुए , यह कहता है:

AsyncTasks को छोटे संचालन के लिए आदर्श रूप से उपयोग किया जाना चाहिए (कुछ सेकंड सबसे अधिक।) यदि आपको लंबे समय तक चलने वाले थ्रेड रखने की आवश्यकता है, तो यह अत्यधिक अनुशंसा की जाती है कि आप java.util.concurrentacacge द्वारा प्रदान किए गए विभिन्न API का उपयोग करें। एक्ज़ीक्यूटर, थ्रेडपूल एक्ज़ीक्यूटर और फ़्यूचरटैस्क।

अब मेरा सवाल उठता है: क्यों? doInBackground()समारोह रन यूआई धागा बंद तो क्या नुकसान यहाँ एक लंबे चल रहा आपरेशन होने से है?


2
वास्तविक डिवाइस के लिए एक ऐप (जो कि asyncTask का उपयोग करता है) को तैनात करते समय मुझे जो समस्या आई थी, वह यह थी कि लंबे समय तक चलने वाला doInBackgroundफंक्शन स्क्रीन को फ्रीज कर देता है अगर प्रगति पट्टी का उपयोग नहीं किया जाता है।
venkatKA

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

यदि मैं किसी सेवा के भीतर AsyncTask बनाता हूं तो क्या होगा? कि समस्या का समाधान नहीं होगा?
एडी

1
IntentService का उपयोग करें, पृष्ठभूमि में लंबे ऑपरेशन को चलाने के लिए सही समाधान।
कीयूर थुमर

जवाबों:


120

यह एक बहुत अच्छा सवाल है, इस मुद्दे को पूरी तरह से समझने के लिए एंड्रॉइड प्रोग्रामर के रूप में समय लगता है। वास्तव में AsyncTask के दो मुख्य मुद्दे हैं जो संबंधित हैं:

  • वे खराब रूप से गतिविधि जीवन चक्र से बंधे हैं
  • वे बहुत आसानी से मेमोरी लीक बनाते हैं।

अंदर RoboSpice (मंशा एप्लिकेशन Google Play पर उपलब्ध ) हम विस्तार से इस सवाल का जवाब। यह AsyncTasks, लोडर, उनकी विशेषताओं और कमियों के बारे में गहराई से विचार देगा और आपको नेटवर्क अनुरोधों के लिए एक वैकल्पिक समाधान भी पेश करेगा: रोबोस्पाइस। नेटवर्क अनुरोध एंड्रॉइड में एक सामान्य आवश्यकता है और प्रकृति लंबे समय तक चलने वाले संचालन द्वारा हैं। यहाँ एप्लिकेशन से एक अंश है:

AsyncTask और गतिविधि जीवन चक्र

AsyncTasks गतिविधि इंस्टेंस के जीवन चक्र का पालन नहीं करते हैं। यदि आप किसी गतिविधि के अंदर एक AsyncTask शुरू करते हैं और आप डिवाइस को घुमाते हैं, तो गतिविधि नष्ट हो जाएगी और एक नया उदाहरण बन जाएगा। लेकिन AsyncTask नहीं मरेगा। यह पूरा होने तक जीवित रहेगा।

और जब यह पूरा हो जाता है, तो AsyncTask नई गतिविधि के UI को अपडेट नहीं करेगा। वास्तव में यह उस गतिविधि के पूर्व उदाहरण को अपडेट करता है जो अब प्रदर्शित नहीं होता है। यह java.lang.IllegalArgumentException के प्रकार का अपवाद हो सकता है: यदि आप उपयोग करते हैं, तो विंडो प्रबंधक से संलग्न नहीं देखें, उदाहरण के लिए, गतिविधि के अंदर एक दृश्य पुनः प्राप्त करने के लिए FindById।

स्मृति रिसाव मुद्दा

आपकी गतिविधियों के आंतरिक वर्गों के रूप में AsyncTasks बनाना बहुत सुविधाजनक है। जैसा कि AsyncTask को कार्य पूरा होने या प्रगति पर होने पर गतिविधि के विचारों में हेरफेर करने की आवश्यकता होगी, गतिविधि के एक आंतरिक वर्ग का उपयोग सुविधाजनक लगता है: आंतरिक वर्ग बाहरी वर्ग के किसी भी क्षेत्र तक सीधे पहुंच सकते हैं।

फिर भी, इसका मतलब है कि आंतरिक वर्ग अपने बाहरी वर्ग उदाहरण पर एक अदृश्य संदर्भ रखेगा: गतिविधि।

लंबे समय तक, यह एक मेमोरी रिसाव पैदा करता है: यदि एस्किंटस्क लंबे समय तक रहता है, तो यह गतिविधि को "जीवित" रखता है, जबकि एंड्रॉइड इससे छुटकारा पाना चाहेगा क्योंकि यह अब प्रदर्शित नहीं किया जा सकता है। गतिविधि को एकत्र नहीं किया जा सकता है और यह डिवाइस पर संसाधनों को संरक्षित करने के लिए एंड्रॉइड के लिए एक केंद्रीय तंत्र है।


लंबे समय तक चलने वाले कार्यों के लिए AsyncTasks का उपयोग करना वास्तव में बहुत बुरा विचार है। फिर भी, वे छोटे जीवित लोगों के लिए ठीक हैं जैसे कि 1 या 2 सेकंड के बाद व्यू अपडेट करना।

मैं आपको रोबोस्पाइस मोटिवेशन ऐप डाउनलोड करने के लिए प्रोत्साहित करता हूं , यह वास्तव में इसे गहराई से समझाता है और कुछ पृष्ठभूमि संचालन करने के लिए विभिन्न तरीकों के नमूने और प्रदर्शन प्रदान करता है।


@ सिनोलस हाय। मेरे पास एक ऐप है जहां यह एनएफसी टैग से डेटा स्कैन करता है और सर्वर को भेजता है। यह अच्छे सिग्नल क्षेत्रों में ठीक काम करता है, लेकिन जहाँ कोई संकेत नहीं है कि AsyncTask जो कि वेबकॉल को चालू रखता है। उदाहरण के लिए प्रगति संवाद बॉक्स मिनटों तक चलता है और फिर जब यह गायब होता है तो स्क्रीन काली और अनुत्तरदायी हो जाती है। मेरा AsyncTask एक आंतरिक वर्ग है। मैं X सेकंड के बाद कार्य को रद्द करने के लिए हैंडलर लिख रहा हूं। लगता है कि ऐप स्कैन के बाद पुराने डेटा को सर्वर घंटों में भेज देता है। यह AsyncTask के खत्म नहीं होने और फिर शायद घंटों के पूरा होने के कारण हो सकता है? मैं किसी भी अंतर्दृष्टि की सराहना करेंगे। धन्यवाद
टर्टलबॉय

जो होता है उसे देखने के लिए ट्रेस करें। लेकिन हां, यह काफी संभव है! यदि आप अपने asynctask को अच्छी तरह से उतरते हैं, तो आप इसे ठीक से रद्द कर सकते हैं, यदि आप RS या किसी सेवा में माइग्रेट नहीं करना चाहते हैं, तो यह एक अच्छा प्रारंभिक बिंदु होगा ...
Snicolas

@Snicolas उत्तर के लिए धन्यवाद। मैंने अपनी समस्या को रेखांकित करते हुए कल SO पर एक पोस्ट किया था और हैंडलर कोड दिखा रहा था जिसे मैंने 8 सेकंड के बाद AsyncTask को रोकने की कोशिश करने के लिए लिखा था। क्या आप एक बार देखने का मन करेंगे, अगर आपको समय मिले? एक हैंडलर से AsyncTask.cancel (सच) को कॉल करने से कार्य ठीक से रद्द हो जाएगा? मुझे पता है कि मुझे समय-समय पर अपने doInBackgroud में iscancelled () के मूल्य की जांच करनी चाहिए, लेकिन मुझे नहीं लगता कि मेरी परिस्थितियों पर लागू होता है क्योंकि मैं सिर्फ एक लाइन webcall HttpPost बना रहा हूं और UI पर अपडेट प्रकाशित नहीं कर रहा हूं। उदाहरण के लिए एक IntentService से एक HttPost बनाने के लिए संभव है
turtleboy


आपके पास रोबोस्पाइस (जीथब पर) में एक कोशिश होनी चाहिए। ;)
स्निकोलस

38

क्यों ?

क्योंकि AsyncTask, डिफ़ॉल्ट रूप से, एक थ्रेड पूल का उपयोग करता है जिसे आपने नहीं बनाया था । संसाधनों को कभी भी एक पूल से न बाँधें जिसे आपने नहीं बनाया है, क्योंकि आप नहीं जानते कि पूल की आवश्यकताएं क्या हैं। और कभी भी पूल से संसाधन न बांधें जो आपने नहीं बनाया अगर उस पूल के लिए प्रलेखन आपको नहीं बताता है, जैसा कि यहां है।

विशेष रूप से, एंड्रॉइड 3.2 के साथ शुरू होने पर, AsyncTaskडिफ़ॉल्ट रूप से ( android:targetSdkVersion13 या अधिक सेट वाले ऐप्स के लिए) द्वारा उपयोग किए गए थ्रेड पूल में केवल एक थ्रेड होता है - यदि आप इस थ्रेड को अनिश्चित काल तक टाई करते हैं, तो आपका कोई भी अन्य कार्य नहीं चलेगा।


इस स्पष्टीकरण के लिए धन्यवाद .. मैं लंबे समय से चल रहे संचालन (हालांकि मैं आमतौर पर उन सेवाओं को खुद को सौंपता हूं) के लिए AsyncTasks के उपयोग के बारे में कुछ भी गलत नहीं पा सकता हूं, लेकिन थ्रेडपूल (जिसके लिए आप वास्तव में कर सकते हैं) पर आपका तर्क इसके आकार के बारे में कोई धारणा नहीं बनाना) स्पॉट-ऑन लगता है। एक सेवा का उपयोग करने के बारे में अनूप के पद के पूरक के रूप में: उस सेवा को स्वयं भी कार्य को एक पृष्ठभूमि थ्रेड पर चलाना चाहिए, और इसके मुख्य थ्रेड को ब्लॉक नहीं करना चाहिए। एक विकल्प एक IntentService हो सकता है, या, अधिक जटिल संगामिति आवश्यकताओं के लिए, अपनी खुद की मल्टीथ्रेडिंग रणनीति लागू कर सकता है।
baske

अगर मैं एक सेवा के अंदर AsyncTask शुरू करता हूँ तो भी क्या यह वही है ?? मेरा मतलब है, क्या लंबे समय तक चलने वाला ऑपरेशन अभी भी एक समस्या है?
एडी

1
@ एडी: हाँ, क्योंकि यह थ्रेड पूल की प्रकृति को नहीं बदलता है। A के लिए Service, बस a Threadया a का उपयोग करें ThreadPoolExecutor
कॉमन्सवेअर

धन्यवाद @CommonsWare सिर्फ आखिरी सवाल, क्या TimerTaches AsyncTasks के समान नुकसान साझा करता है? या यह एक पूरी बात है?
एडी

1
@ एडी: TimerTaskमानक जावा से है, न कि एंड्रॉइड से। TimerTaskको बड़े पैमाने पर छोड़ दिया गया है ScheduledExecutorService(जो अपने नाम के बावजूद, मानक जावा के हिस्से के रूप में है)। न तो एंड्रॉइड से बंधे हैं, और इसलिए आपको अभी भी एक सेवा की आवश्यकता है यदि आप पृष्ठभूमि में उन चीजों को चलाने की अपेक्षा करते हैं। और, आपको वास्तव मेंAlarmManager , एंड्रॉइड से विचार करना चाहिए , इसलिए आपको घड़ी की टिक को देखने के लिए एक सेवा को लटकाए जाने की आवश्यकता नहीं है।
कॉमन्सवेयर

4

Aysnc टास्क विशेष धागे हैं जो अभी भी आपके ऐप्स GUI के साथ उपयोग किए जाने के लिए हैं लेकिन UI थ्रेड के संसाधन-भारी कार्यों को रखते हुए। इसलिए जब अपडेट सूचियों जैसे सामान, अपने विचारों को बदलने आदि के लिए आपको कुछ भ्रूण संचालन या अपडेट संचालन करने की आवश्यकता होती है, तो आपको एसिंक्स कार्यों का उपयोग करना चाहिए ताकि आप इन कार्यों को यूआई थ्रेड से दूर रख सकें लेकिन ध्यान दें कि ये ऑपरेशन अभी भी किसी तरह यूआई से जुड़े हुए हैं ।

लंबे समय तक चलने वाले कार्यों के लिए, जिन्हें UI अपडेशन की आवश्यकता नहीं है, आप इसके बजाय सेवाओं का उपयोग कर सकते हैं, क्योंकि वे UI के बिना भी रह सकते हैं।

इसलिए छोटे कार्यों के लिए, एसिंक्स कार्यों का उपयोग करें क्योंकि वे ओएस द्वारा मारे जा सकते हैं जब आपकी स्पैनिंग गतिविधि मर जाती है (आमतौर पर मध्य ऑपरेशन नहीं मरेंगे लेकिन अपना कार्य पूरा करेंगे)। और लंबे और दोहराए जाने वाले कार्यों के लिए, इसके बजाय सेवाओं का उपयोग करें।

अधिक जानकारी के लिए, धागे देखें:

कुछ सेकंड से अधिक समय के लिए AsyncTask?

तथा

जब गतिविधि नष्ट हो गई है तब भी AsyncTask बंद नहीं होगा


1

AsyncTask के साथ समस्या यह है कि यदि इसे गतिविधि के गैर-स्थिर आंतरिक वर्ग के रूप में परिभाषित किया गया है, तो इसमें गतिविधि का संदर्भ होगा। इस परिदृश्य में जहां एस्कॉन टास्क का कंटेनर खत्म हो जाता है, लेकिन बैकग्राउंड का काम एसिंक्सटैस्क में जारी रहता है, एक्टिविटी ऑब्जेक्ट को इकट्ठा नहीं किया जाएगा क्योंकि इसका एक संदर्भ है, यह मेमोरी लीक का कारण बनता है।

इसे ठीक करने के लिए समाधान async कार्य को गतिविधि के स्थिर आंतरिक वर्ग के रूप में परिभाषित किया गया है और संदर्भ के कमजोर संदर्भ का उपयोग करता है।

लेकिन फिर भी, सरल और त्वरित पृष्ठभूमि कार्यों के लिए इसका उपयोग करना एक अच्छा विचार है। स्वच्छ कोड के साथ ऐप विकसित करने के लिए, जटिल पृष्ठभूमि कार्यों को चलाने के लिए और इसके परिणामों से यूआई को अपडेट करने के लिए RxJava का उपयोग करना बेहतर है।

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