2012-05-13 10 views
48

मेरी परियोजनाओं में मैं BroadcastReceiver एस का उपयोग लंबे समय से चलने वाले धागे से कॉलबैक के रूप में कर रहा हूं (उदाहरण के लिए। डाउनलोड को समाप्त करने वाली गतिविधि को सूचित करें और वर्कर Thread से कुछ प्रतिक्रिया डेटा भेजें ताकि गतिविधि उपयोगकर्ता को उचित संदेश प्रदर्शित कर सके ..)। BroadcastReceiver एस का उपयोग करने के लिए मुझे प्रत्येक बार जब मैं इसका उपयोग कर रहा हूं, तो प्रसारण रिसीवर को पंजीकृत और अनधिकृत करने के लिए सावधान रहना होगा और जब मैं इस विधि का उपयोग अधिक अलग-अलग कार्यों के लिए कर रहा हूं (जैसे डाउनलोड करना, वेब सेवा बनाना कॉल आदि ..)। और ब्रॉडकास्ट के इरादे के माध्यम से कस्टम ऑब्जेक्ट्स भेजने के लिए मुझे ऑब्जेक्ट्स Parcelable बनाने की भी आवश्यकता है।एंड्रॉइड ब्रॉडकास्ट रिसीवर या सरल कॉलबैक विधि?

इस दृष्टिकोण के विपरीत, मैंने कॉलबैक विधियों के दृष्टिकोण को भी देखा है जो मेरे द्वारा उपयोग की जाने वाली विधि से सरल प्रतीत होता है। कॉलबैक विधियां सरल इंटरफेस विधियों के कार्यान्वयन हैं जिनका उपयोग ब्रॉडकास्ट रेकैवर के ऐप मैसेजिंग में समान प्रभाव प्राप्त करने के लिए किया जा सकता है। इस दृष्टिकोण को जटिल वस्तुओं को वापस करने के लिए पार्सलेबल कार्यान्वयन की आवश्यकता नहीं है और यह BroadcastReceiver जैसी चाबियों का उपयोग नहीं करता है .. मुझे लगता है कि बुरा हिस्सा यह है कि मुझे कॉलबैक विधि कॉल करने से पहले मुझे शून्य मान के लिए कॉलबैक ऑब्जेक्ट की जांच करने की आवश्यकता है। और यह भी सुनिश्चित करने के लिए कि मैं यूआई थ्रेड पर कार्यान्वयन से कोड चला रहा हूं, इसलिए मैं त्रुटियों के बिना यूआई अपडेट कर सकता हूं।

ठीक है, मुझे उम्मीद है कि आप समझ गए कि मेरा क्या कहना है :)।

अब सवाल यह है कि क्या आपको लगता है कि कॉलबैक विधि BroadcastReceiver दृष्टिकोण से बेहतर है (हल्का, क्लीनर, तेज़ ..) जब केवल एक ही एप्लिकेशन के अंदर उपयोग किया जाता है? (ध्यान दें कि मैं पृष्ठभूमि के काम के लिए एंड्रॉइड Service का उपयोग नहीं कर रहा हूं .. बस AsyncTask और Thread एस)

धन्यवाद!

उत्तर

78

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

कॉलबैक-तंत्र का उपयोग कुछ फायदे हैं, लेकिन वहाँ भी सीमाएं हैं:

प्रो

  • यह लागू करने के लिए सरल और सीधे आगे है।
  • आपको एक-दूसरे के साथ बातचीत करने वाले घटकों के बीच टाइप-सुरक्षा मिलती है।
  • आप मनमानी वस्तुओं को वापस कर सकते हैं।
  • यह परीक्षण को सरल बनाता है क्योंकि आपको यूनिट परीक्षणों में केवल नकली कॉलबैक (उदाहरण के लिए मॉकिटो या कुछ इसी तरह से उत्पन्न) इंजेक्ट करना पड़ता है।

विपरीत

  • आपको यूआई जोड़तोड़ करने के लिए मुख्य थ्रेड के लिए स्विच करने के लिए है।
  • आपके पास केवल 1-से-1 संबंध हो सकता है। 1-से-एन संबंध (पर्यवेक्षक पैटर्न) आगे के काम के बिना प्राप्य नहीं है। इस मामले में मैं एंड्रॉइड के Observer/Observable तंत्र को प्राथमिकता दूंगा।
  • जैसा कि आपने पहले ही कहा है, कॉलबैक वैकल्पिक होने पर कॉलबैक फ़ंक्शंस को आमंत्रित करने से पहले आपको हमेशा null की जांच करनी होगी।
  • यदि आपके घटक को विभिन्न सेवा कार्यों के साथ एक प्रकार की सेवा API प्रदान करना चाहिए और आप केवल कुछ सामान्य कॉलबैक फ़ंक्शंस के साथ कॉलबैक इंटरफ़ेस नहीं चाहते हैं, तो आपको यह तय करना होगा कि क्या आप प्रत्येक सेवा फ़ंक्शन के लिए एक विशेष कॉलबैक इंटरफ़ेस प्रदान करते हैं या आप कई कॉलबैक फ़ंक्शंस के साथ एक एकल कॉलबैक इंटरफ़ेस प्रदान करते हैं या नहीं। बाद के मामले में आपके एपीआई को सेवा कॉल के लिए उपयोग किए जाने वाले सभी कॉलबैक क्लाइंट को पूर्ण कॉलबैक इंटरफ़ेस को कार्यान्वित करना होगा, हालांकि अधिकांश विधि निकाय खाली होंगे। आप खाली निकायों के साथ एक स्टब को लागू करके इसके आसपास काम कर सकते हैं और अपने कॉलबैक क्लाइंट को उस स्टब से प्राप्त कर सकते हैं, लेकिन यह संभव नहीं है कि पहले से ही किसी अन्य बेस क्लास से विरासत में हो। हो सकता है कि आप किसी प्रकार की गतिशील प्रॉक्सी कॉलबैक का उपयोग कर सकें (http://developer.android.com/reference/java/lang/reflect/Proxy.html देखें), लेकिन फिर यह वास्तव में जटिल हो जाता है और मैं एक और तंत्र का उपयोग करने के बारे में सोचूंगा।
  • कॉलबैक कॉल के लिए ग्राहक को विभिन्न विधियों/घटकों के माध्यम से प्रचारित किया जाना चाहिए यदि यह सेवा के कॉलर द्वारा सीधे पहुंच योग्य नहीं है।

BroadcastReceiver -approach के बारे में कुछ अंक:

प्रो

  • आप अपने घटकों के बीच एक ढीला संयोजन को प्राप्त।
  • आपके पास 1-से-n संबंध हो सकता है (1-से-0 सहित)।
  • onReceive() विधि हमेशा मुख्य धागे पर निष्पादित की जाती है।
  • आप अपने पूरे एप्लिकेशन में घटकों को सूचित कर सकते हैं, इसलिए संचार घटकों को एक दूसरे को "देखने" की आवश्यकता नहीं है।

विपरीत

  • यह एक बहुत ही सामान्य दृष्टिकोण है, इसलिए प्राथमिकता निर्धारण और Intent द्वारा पहुँचाया डेटा की unmarshalling एक अतिरिक्त त्रुटि स्रोत है।
  • यदि आप अन्य ऐप्स के साथ सहसंबंध को खत्म करना चाहते हैं, तो आपको अपने Intent की कार्रवाइयां अद्वितीय (जैसे पैकेज नाम को प्रीपेड करके) बनाना है, क्योंकि उनका मूल उद्देश्य अनुप्रयोगों के बीच प्रसारण करना है।
  • आपको BroadcastReceiver-पंजीकरण और पंजीकरण रद्द करना है। यदि आप इसे अधिक आरामदायक तरीके से करना चाहते हैं, तो आप अपने गतिविधि को एनोटेट करने के लिए एक कस्टम एनोटेशन लागू कर सकते हैं, जो पंजीकृत होना चाहिए और आधार Activity कक्षा को कार्यान्वित करना है जो एस के साथ onResume() resp में पंजीकरण और अनियंत्रण करता है। onPause() विधियां।
  • जैसा कि आपने पहले ही कहा है, Intent के साथ भेजे गए डेटा को Parcelable इंटरफ़ेस को कार्यान्वित करना है, लेकिन इसके अलावा सख्त आकार सीमा है और यदि आप अपने Intent के साथ बड़ी मात्रा में डेटा लेते हैं तो यह प्रदर्शन समस्याओं का कारण बन जाएगा। उस पर चर्चा के लिए http://code.google.com/p/android/issues/detail?id=5878 देखें। इसलिए यदि आप छवियों को उदाहरण के लिए भेजना चाहते हैं तो आपको उन्हें एक भंडार में अस्थायी रूप से स्टोर करना होगा और आपके Intent के प्राप्तकर्ता से छवि तक पहुंचने के लिए एक संबंधित आईडी या यूआरएल भेजना होगा जो इसे उपयोग के बाद भंडार से हटा देता है। यदि कई रिसीवर हैं (जब छवि को भंडार से हटाया जाना चाहिए और उसे कौन करना चाहिए?) इससे आगे की समस्याएं होती हैं।
  • यदि आप इस तरह के अधिसूचना तंत्र का अधिक उपयोग करते हैं तो आपके आवेदन का नियंत्रण प्रवाह छुपा हो सकता है और जब आप डीबगिंग करते हैं तो Intent के अनुक्रमों के साथ चित्रों को चित्रित करते हैं, यह समझने के लिए कि किसी विशिष्ट त्रुटि को किस प्रकार ट्रिगर किया गया है या क्यों कुछ अधिसूचना श्रृंखला टूट गई है बिंदु।

मेरी राय में, यहां तक ​​कि एक मोबाइल ऐप में कम से कम 2 परतों पर एक आर्किटेक्चर आधार होना चाहिए: यूआई-लेयर और कोर लेयर (व्यवसाय तर्क आदि के साथ)। सामान्य रूप से, लंबे समय तक चलने वाले कार्यों को अपने स्वयं के थ्रेड में निष्पादित किया जाता है (शायद AsyncTask या HandlerThread के माध्यम से MessageQueue एस) कोर परत के अंदर और UI को यह कार्य पूरा होने के बाद अपडेट किया जाना चाहिए। सामान्य रूप से कॉलबैक के साथ आप अपने घटकों के बीच एक तंग युग्मन प्राप्त करते हैं, इसलिए मैं केवल एक परत के भीतर इस दृष्टिकोण का उपयोग करना पसंद करूंगा, न कि परत सीमाओं में संचार के लिए। UI- और कोर-लेयर के बीच संदेश प्रसारण के लिए मैं BroadcastReceiver -approach का उपयोग करूंगा जो आपको अपनी यूआई परत को लॉजिक लेयर से डीक्यूप्ल करने देता है।

+0

मैंने इसे एक उत्तर के रूप में सम्मानित किया है और इसे बक्षीस दिया है क्योंकि यह सबसे पूरा उत्तर है .. आपके विचारों के लिए धन्यवाद! – Cata

+0

उत्कृष्ट जवाब। मैं कॉलबैक/इंटरफ़ेस पैटर्न का प्रशंसक हूं लेकिन मैं अक्सर ब्रॉडकास्ट इरादे पैटर्न के व्यापक उपयोग के साथ परियोजनाओं का उत्तराधिकारी हूं और मुझे अक्सर आश्चर्य होता है कि क्या मैं इसके बारे में गलत तरीके से जा रहा हूं। यह सुनकर अच्छा लगा कि वास्तव में यह सर्वोत्तम अभ्यास के बजाय डिजाइन वरीयता का मामला है। मुझे इंटरफेस द्वारा प्रदान की जाने वाली टाइप-सुरक्षा और कोड स्पष्टता पसंद है और मैं शायद –

+0

के लिए उनके साथ रहूंगा, बहुत रोचक और विस्तृत राय +1 – Jorgesys

6

मुझे नहीं लगता कि आप अपने मामले में BroadcastReceiver का उपयोग करके क्या हासिल करते हैं। कॉलबैक या बेहतर, Handlers ऐसा करने का तरीका होगा। BroadcastReceiver अच्छा है जब आप नहीं जानते कि ग्राहक कौन हैं।

+0

आपके उत्तर के लिए धन्यवाद, हालांकि मैं अधिक उत्तरों के लिए थोड़ा इंतजार करूंगा .. – Cata

2

ब्रॉडकास्ट्रेसीवर का उपयोग किया जाना चाहिए यदि आपको कॉलबैक (या एलेक्स द्वारा सुझाए गए हैंडलर) के दौरान अनुप्रयोगों में प्रसारण भेजने की आवश्यकता है तो आपकी स्थिति में उपयोग करना बेहतर होगा।

यदि आप इन दोनों के अलावा अन्य उपयोग करना चाहते हैं, तो Observer (एंड्रॉइड में इंटरफ़ेस शामिल) और प्रतिनिधि का उपयोग करने पर विचार करें।

प्रतिनिधि के लिए कृपया this SO post पर विचार करें।

3

मैं सिर्फ अन्य महान जवाब आप पहले से ही प्राप्त हो गया है करने के लिए एक और विकल्प जोड़ देंगे ...

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

<activity android:name=".MyActivity"> 
     <intent-filter > 
       <action android:name="intent.you.want.to.receive" /> 
       <category android:name="android.intent.category.DEFAULT" /> 
     </intent-filter>  
.... 
</activity> 

फिर अपनी गतिविधि में onNewIntent(Intent) विधि ओवरराइड इसे प्राप्त करने के।

इरादा भेजने के लिए, Context.startActivity(Intent) विधि का उपयोग करें। सबसे अधिक संभावना है कि आप अपने इरादे पर FLAG_ACTIVITY_SINGLE_TOP ध्वज जोड़ना चाहेंगे, इसलिए यदि कोई पहले से चल रहा है तो यह आपकी गतिविधि का एक नया उदाहरण नहीं बनाता है।

संपादित करें: मैंने अभी देखा है कि आप एक ही एप्लिकेशन में चल रहे हैं। इसलिए, एक साधारण कॉलबैक शायद सबसे अच्छा है।उपरोक्त समाधान एक ऐप में काम करता है, लेकिन विभिन्न अनुप्रयोगों के लिए अधिक उपयुक्त है। अगर मैं किसी की मदद करता हूं तो मैं इसे यहां छोड़ दूंगा। सौभाग्य!

+0

एक्सेलेंट टिप!हालांकि, मैं जोड़ना चाहता हूं कि वही '' दृष्टिकोण सेवाओं पर भी लागू होता है, यदि आप गैर-UI विशिष्ट कार्यान्वयन को अलग करना चाहते हैं, तो इस मामले में आप 'Context.startService' कहेंगे (इरादा) 'इसके बजाए। यदि आपकी लक्षित सेवा ['IntentService'] (http://developer.android.com/reference/android/app/IntentService.html) तक फैली हुई है तो आपके पास" एंटिंट्रोसिस संदेश कतार "मुफ्त में होगा क्योंकि 'IntentService' केवल तभी होगा उस समय एक 'इरादा' पर निष्पादित करें और 'ऑनहेंडलेंट' विधि को कार्यकर्ता थ्रेड पर निष्पादित किया जाएगा। – dbm

1

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

http://developer.android.com/resources/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.html

यदि नहीं, तो आप हमेशा asyncTask, सेवा, संचालकों, आदि ...

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