2012-09-12 28 views
6

यह सर्वविदित है कि एंड्रॉयड किसी भी क्षण में हत्या किए जाने का खतरा मंडरा रहा हमारे आवेदन घटकों (क्रियाएँ, सेवा) देता है। यदि आप एक ही समय में कोड साफ रखने और चिंताओं की जुदाई को संबोधित कर, एक मजबूत, गैर टपकाया समाधान प्रदान करने के लिए चाहते हैं तो यह बातें वास्तव में जटिल बना देता है।अच्छा डिजाइन: कार्यकर्ता धागे और गतिविधि पुनरारंभ

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

जब एक गतिविधि मार दिया जाता है और बाद में एक नया उदाहरण निर्मित है, मैं दो विकल्प के बारे में सोच सकते हैं: चल रहा है काम को मारने के लिए

  1. कोशिश के रूप में अच्छी तरह से है, और किसी अन्य कार्य उदाहरण अंडे जब एक नया विकल्प गतिविधि उदाहरण बनाया गया है। यह एक लंबा चल रहा कार्य के लिए एक विकल्प के रूप में यह अस्वीकार्य है से देखने के एक उपयोगकर्ता बिंदु कार्य प्रारंभ करने और प्रगति बार सूचक किसी स्पष्ट कारण के साथ वापस 0% से 80% तक से जा रहा करने के लिए नहीं है। हालांकि यह दृष्टिकोण Shelves example by Romain Guy में किया गया है। जाहिर है यह आधिकारिक डेवलपर गाइड में अनुशंसित दृष्टिकोण है।

  2. रखें कार्य चल रहा है: तो हम पर एक गतिविधि onResume पर की सदस्यता (और संभवतः शुरू) अद्यतन के लिए काम, और सदस्यता समाप्ति (और संभवतः रोक) यह हो सकता था।

दूसरे विकल्प के बाद इसका मतलब है कि गतिविधि को अस्थायी रूप से नष्ट करने के मामले में हमें एकत्रित होने के कार्य को रोकना चाहिए। उदाहरण के लिए, हम इसे एक कस्टम एप्लिकेशन क्लास के भीतर घोषित कर सकते हैं, या यहां तक ​​कि इसे बाकी एप्लिकेशन के लिए एक सेवा के रूप में भी पेश कर सकते हैं (एक सिंगलटन? एंड्रॉइड सर्विस का उपयोग कर?) मैं इस का कोई प्रशंसक नहीं हूं, हालांकि, कार्य है केवल गतिविधि द्वारा उपयोग किया जाता है, इसलिए इसे अन्य वर्गों में उपलब्ध कराने के लिए यह समझ में नहीं आता है। दूसरी तरफ एंड्रॉइड सर्विसेज को जीवन चक्र से निपटना होगा।

विकल्प # 2 में यह भी शामिल है कि पुराने गतिविधि को लीक नहीं किया गया है। यदि कोई गतिविधि मौजूद नहीं है तो हमें जीयूआई अपडेट करने की कोशिश नहीं करनी चाहिए। पूरा विचार थ्रेड-सुरक्षित होना चाहिए। अंत में कार्य को स्मृति में नहीं रहना चाहिए जब हमें यकीन है कि इसकी आवश्यकता नहीं है। लेकिन साथ ही, यदि प्रारंभिक गतिविधि नष्ट हो जाती है, तो कार्य चल रहा रहता है, और एक नई विकल्प गतिविधि बढ़ जाती है, कार्य को तुरंत जीयूआई अपडेट करने के लिए आसपास होना चाहिए और कार्य वर्तमान स्थिति प्रदर्शित करना होगा (या परिणामस्वरूप पूरा होने पर)।

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

मुझे पता है कि पहले से ही इसी तरह के प्रश्न पूछे गए हैं, लेकिन मैं विशेष रूप से समस्या को हल करने के बारे में नहीं पूछ रहा हूं, लेकिन ढीले युग्मन को प्राप्त करने और कार्य से गतिविधि को अलग करने के लिए किस डिजाइन की सिफारिश की जाएगी मुमकिन।

कम में:
- यह शायद पहले एक चालाक डिजाइन के साथ आ गया Android विकास और किसी में एक आवर्ती समस्या है। क्या कोई डिज़ाइन पैटर्न है, या एक अच्छी तरह से परीक्षण लाइब्रेरी है जो इसे सरल बनाती है?
- यदि आप # 2 को लागू करना चाहते हैं, तो आप किस वर्ग (कार्यशील, सेवा, आदि) के लिए चुनते हैं और यह गतिविधि के साथ कैसे संवाद करेगा?

पीएस "अभिविन्यास | कीबोर्डहेड" हैक एक्सडी के आधार पर समाधान पोस्ट करने से बचें। इसके अलावा, किसी भी मदद की सराहना की जाएगी।


अद्यतन:
मेरे पहले ही प्रयास में थोड़ा गंदा मिल गया है। ऐप एक ब्लूटूथ प्रिंटिंग यूटिलिटी है, जिसमें बीटी स्टेटस का पता लगाना शामिल है (और उपयोगकर्ता को अक्षम होने पर इसे सक्षम करने के लिए कहा जाता है), युग्मित उपकरणों को पुनर्प्राप्त करना (और उपयोगकर्ता को एक से अधिक होने पर एक चुनने के लिए कहना), फिर डेटा भेजना और अंत में परिणाम के बारे में उपयोगकर्ता को सूचित करें। चूंकि यह कार्य 80% आईओ कोड था, 20% जीयूआई से संबंधित संचालन, मुझे कार्य की शुरुआत और अंत में जीयूआई कोड को समूहबद्ध करना था, फिर इसे कार्य से वापस गतिविधि में ले जाना था। मेरे पास IntentService है जो भारी भारोत्तोलन करता है, फिर BroadcastReceiver के माध्यम से गतिविधि पर वापस रिपोर्ट करता है। इससे ज्यादातर समस्याएं हल होती हैं लेकिन ऐसे डिज़ाइन के साथ कुछ समस्याएं हैं। सबसे पहले, उन सभी स्थिर तारों को इनपुट और आउटपुट से फ़ील्ड को रखने और पुनर्प्राप्त करने के लिए कुंजी के रूप में उपयोग किया जाता है, जो अर्थपूर्ण युग्मन शुरू कर रहे हैं। मैं गतिविधि < -> सेवा संचार में टाइप-सुरक्षा पसंद करूंगा। और मुझे अभी तक यह हल करना है कि इरादे में सेवा के लिए जटिल कस्टम ऑब्जेक्ट्स को कैसे पास किया जाए, अब तक मैं पार्ससेलबल्स और आदिम पैरामीटर के साथ फंस गया हूं। अंत में, गतिविधि और सेवा दोनों एक ही एपीआई (ब्लूटूथ) का उपयोग कर रहे हैं, मैं एक ही कक्षा में बीटी-संबंधित कोड अल करना पसंद करता। मुझे लगता है कि मैं इस डिजाइन को फेंक दूंगा, और धागे के आधार पर एक कस्टम प्रिंटिंग कतार के साथ पुनः प्रयास करूंगा, भले ही इससे मारे गए गतिविधियों से कड़ी मेहनत हो जाएगी।

+0

AsyncTask गतिविधि को फिर से बनाया गया है, जबकि रोका गया है। प्रगति/परिणाम के लिए कार्य का उपयोग किया गया संदेश तब तक वितरित नहीं किया जाता है जब गतिविधि नष्ट हो जाती है (फिर भी रोकें/फिर से शुरू होने के बाद भी हो सकता है)। गतिविधि उदाहरणों के बीच AsyncTask के आसपास पास करने के लिए nonconfiguration-instance चीज़ का उपयोग करना काफी अच्छा काम करना चाहिए। – zapl

उत्तर

8

क्यों आपकी गतिविधि लंबे समय तक चलने वाले कार्य को होस्ट करने के लिए सेवा शुरू नहीं करती है? लंबी अवधि चलने वाली चीजों को रखने के लिए एक सेवा आपकी सबसे अच्छी शर्त है। आप इसे चलाने के लिए ओएस को संकेत प्रदान कर सकते हैं। startForeground() और START_STICKY देखें।

आप सेवा से प्रसारण करके गतिविधि में वापस संवाद कर सकते हैं। क्या आपकी गतिविधि प्रोग्रामिंग रूप से उन उद्देश्यों को सुनने के लिए broadcast receiver पंजीकृत करती है। यदि गतिविधि रोका गया है, तो अपने रिसीवर को अनधिकृत करें, इस तरह जब आप अग्रभूमि में नहीं हों तो आप जवाब नहीं देंगे।

यदि ओएस आपकी सेवा को नष्ट कर देता है, तो यह प्रक्रिया को मार रहा है, इसलिए आपका कार्य वैसे भी नष्ट हो गया है। सबसे अच्छा आप इसे पुनरारंभ कर सकते हैं। वैसे भी, यदि आप उपरोक्त मानते हैं तो सबसे चरम स्थितियों को छोड़कर ऐसा नहीं होगा।

संपादित करें: टिप्पणियों में कैप्चर किए गए कुछ विचारों का सारांश ... लंबे समय तक चलने वाले कार्यकर्ता प्रक्रिया को बनाए रखना और स्वचालित रूप से इसे फिर से शुरू करना लगभग हमेशा गलत काम है। मोबाइल उपकरणों में यह व्यवहार्य बनाने के लिए पावर स्रोत नहीं है। लेखक ने कहा कि उनके पास एक विशेष शर्त है जो इस चिंता को अस्वीकार करती है ... यह केवल तभी सच होगा जब डिवाइस लगभग हमेशा बिजली स्रोत से जुड़ा हुआ हो।

एंड्रॉइड मॉडल इरादों (अधिसूचनाओं) का एक मजबूत सेट प्रदान करना है जिसमें आपका एप्लिकेशन सुन सकता है। जब ये कुछ करने का समय होता है तो ये इरादे आपके डिवाइस/एप्लिकेशन को जगाते हैं। आपके ऐप को अधिसूचना को संभालना चाहिए, और फिर डिवाइस को तुरंत सोने के लिए जाने की अनुमति दें।

यदि आपके ईवेंट में कोई स्टॉक इरादा नहीं है, तो आप सर्वर से डिवाइस उठाने के लिए Google Cloud Messaging का उपयोग कर सकते हैं।दूसरे शब्दों में, लंबे समय तक चलने वाली प्रक्रियाओं को सर्वर पर चलने दें, और आवश्यकता होने पर डिवाइस को जगाएं।

यदि आप ऐसा कर सकते हैं, तो समय-समय पर जागने और कुछ राज्य की जांच करने के लिए AlarmManager का उपयोग करना होगा। भले ही आपने इसे अक्सर किया (उदाहरण के लिए, हर 5 मिनट, जो कि नो-नो भी है), यह सुझाव दिया जा रहा है कि उपकरण हमेशा जागृत रखने से कहीं बेहतर होगा। भी, अतुल्य वेकअप अंतराल का उपयोग करें (उपरोक्त लिंक दस्तावेज देखें)।

+0

हाँ सेवा के रूप में चलाएं, और कुछ ऐप्स के रूप में करें, कोशिश बार में एक आइकन जोड़ने से सेवा को बाहर निकलने में मदद मिलेगी, आप एंड्रॉइड ऐप बंद होने पर ईवेंट प्राप्त कर सकते हैं। –

+0

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

+0

लंबे समय तक चलने वाली, पृष्ठभूमि प्रक्रिया किसी भी मोबाइल प्लेटफॉर्म पर एक विशेष मामला है। आप बस ज्यादातर मामलों में ऐसा नहीं करना चाहते हैं क्योंकि मोबाइल उपकरणों में उस व्यवहार्य बनाने के लिए पावर स्रोत नहीं है। –