गतिविधि संदर्भ या एप्लिकेशन संदर्भ कब कॉल करें?


265

इन दोनों संदर्भों के बारे में बहुत कुछ पोस्ट किया गया है .. लेकिन मैं अभी भी इसे काफी सही नहीं मान रहा हूं

जैसा कि मैं इसे अब तक समझता हूं: प्रत्येक अपनी कक्षा का एक उदाहरण है जिसका अर्थ है कि कुछ प्रोग्रामर आपको this.getApplicationContext()किसी भी मेमोरी को "लीक" नहीं करने के लिए जितनी बार संभव हो उतना उपयोग करने की सलाह देते हैं । इसका कारण यह है कि अन्य this( Activityउदाहरण संदर्भ प्राप्त करना ) इंगित करता है Activityकि हर बार नष्ट हो रहा है जब उपयोगकर्ता फोन को झुकाता है या ऐप आदि को छोड़ देता है .. जो कि स्पष्ट रूप से कचरा कलेक्टर (जीसी) नहीं पकड़ता है और इसलिए बहुत अधिक मेमोरी का उपयोग करता है ..

लेकिन क्या कोई कृपया कुछ बहुत अच्छे कोडिंग उदाहरणों के साथ आ सकता है जहां इसका उपयोग करना सही होगा this(वर्तमान Activityउदाहरण का संदर्भ प्राप्त करना ) और आवेदन का संदर्भ बेकार / गलत होगा?

जवाबों:


408

getApplicationContext()लगभग हमेशा गलत होता है। सुश्री हैकबॉर्न (दूसरों के बीच) बहुत स्पष्ट हैं कि आप केवलgetApplicationContext() तब उपयोग करते हैं जब आप जानते हैं कि आप क्यों उपयोग कर रहे हैं getApplicationContext()और केवल जब आपको उपयोग करने की आवश्यकता है getApplicationContext()

कुंद होने के लिए, "कुछ प्रोग्रामर" का उपयोग getApplicationContext()(या getBaseContext(), कुछ हद तक) क्योंकि उनका जावा अनुभव सीमित है। वे एक आंतरिक वर्ग को लागू (जैसे, एक OnClickListenerएक के लिए Buttonएक में Activity) और एक की जरूरत है Context। बल्कि का उपयोग करने से MyActivity.thisबाहरी वर्ग 'पर प्राप्त करने के लिए this, वे का उपयोग getApplicationContext()या getBaseContext()एक पाने के लिए Contextवस्तु।

आप केवलgetApplicationContext() तब उपयोग करते हैं जब आप जानते हैं कि आपको किसी ऐसी Contextचीज़ की आवश्यकता Contextहै जो आपके निपटान में किसी भी अन्य संभावना से अधिक समय तक रह सकती है । परिदृश्य में शामिल हैं:

  • का प्रयोग करें getApplicationContext()अगर आप कुछ एक से बंधा जरूरत है Contextजो अपने आप को वैश्विक विस्तार होगा। मैं उपयोग करता हूं getApplicationContext(), उदाहरण के लिए, सेवा के लिए उपयोग किए जाने WakefulIntentServiceवाले स्थैतिक के WakeLockलिए। चूंकि WakeLockयह स्थिर है, और इसे बनाने के Contextलिए मुझे एक की आवश्यकता है PowerManager, यह उपयोग करने के लिए सबसे सुरक्षित है getApplicationContext()

  • का प्रयोग करें getApplicationContext()आप एक करने के लिए बाध्य है जब Serviceएक से Activity, अगर आप पारित करने के लिए चाहते हैं ServiceConnection(यानी, बंधन को संभाल) के बीच Activityउदाहरणों के माध्यम से onRetainNonConfigurationInstance()। एंड्रॉइड इन के माध्यम से आंतरिक रूप से बाइंडिंग को ट्रैक ServiceConnectionsकरता Contextsहै और बाइंडिंग बनाने के लिए संदर्भ रखता है । यदि आप इससे बंधते हैं Activity, तो नए Activityउदाहरण में एक संदर्भ होगा ServiceConnectionजिसमें पुराने के लिए एक अंतर्निहित संदर्भ होता है Activity, और पुराने Activityको एकत्र नहीं किया जा सकता है।

कुछ डेवलपर्स Applicationअपने स्वयं के वैश्विक डेटा के लिए कस्टम उपवर्गों का उपयोग करते हैं , जिन्हें वे पुनः प्राप्त करते हैं getApplicationContext()। यह निश्चित रूप से संभव है। मैं स्थैतिक डेटा सदस्यों को पसंद करता हूं, यदि आपके अलावा कोई अन्य कारण केवल एक कस्टम Applicationऑब्जेक्ट हो सकता है। मैंने एक कस्टम Applicationऑब्जेक्ट का उपयोग करके एक ऐप बनाया और पाया कि यह दर्दनाक है। सुश्री हैकबॉर्न भी इस स्थिति से सहमत हैं

यहां कारण हैं कि आप जहां भी जाते हैं उसका उपयोग क्यों नहींgetApplicationContext() करते हैं:

  • यह एक पूर्ण नहीं है Context, जो कुछ भी Activityकरता है उसका समर्थन करता है। विभिन्न चीजें जो आप इस के साथ करने की कोशिश Contextकरेंगे असफल हो जाएंगे, ज्यादातर जीयूआई से संबंधित हैं

  • यह मेमोरी लीक्स बना सकता है, यदि आपके द्वारा इस पर बनाई गई किसी चीज पर Contextसे getApplicationContext()होल्ड होता है, जिसे आप साफ नहीं करते हैं। ए के साथ Activity, अगर यह किसी चीज़ पर टिका है, तो एक बार Activityकचरा इकट्ठा हो जाता है, बाकी सब कुछ भी बाहर निकल जाता है। Applicationवस्तु अपने प्रक्रिया के जीवन भर के लिए बनी हुई है।


1
इस उत्तर के लिए आपका बहुत-बहुत धन्यवाद। इस उत्तर को पढ़ने से पहले एक और लिंक मुझे मिला, जिससे कुछ लोगों को मदद मिल सकती है। stackoverflow.com/questions/7298731/… - यह लिंक स्मृति को लीक करने के बारे में मेरी चिंताओं की व्याख्या करता है।
नोरफेल्ट

27
@Norfeldt: FYI करें, आपकी टिप्पणी का लिंक इस उत्तर पर वापस जाता है।
कॉमन्सवेयर

2
धन्यवाद .. यह लिंक था: stackoverflow.com/questions/5796611/… यह स्मृति रिसाव का वर्णन करता है कि मैं इस का उपयोग करके डर गया था
नॉरफेल्ड

6
@djaqeel: आपकी बोली का उत्तरार्द्ध लगभग सही है। यह बेहतर है कि "किसी ऐसी गतिविधि को कोई संदर्भ न दें जो गतिविधि से अधिक समय तक जीवित रहेगी, जैसे कि स्थैतिक डेटा सदस्य"। हालाँकि, आप अभी भी केवल तभी उपयोग getApplicationContext()करते हैं जब आप ठीक से जानते हों कि आपको किसी दिए गए स्थिति में इसकी आवश्यकता क्यों है। एक लेआउट मुद्रास्फीति? गतिविधि का उपयोग करें। एक सेवा से बांधना, जहां आपको कॉन्फ़िगरेशन परिवर्तन से बचने के लिए उस बंधन की आवश्यकता होती है? उपयोग करें getApplicationContext(), इसलिए बंधन Activityउदाहरण से बंधा नहीं है ।
कॉमन्सवेयर

7
@Sever: मैं अपने जवाब में इसे कवर करता हूं। डेव स्मिथ का एक उत्कृष्ट ब्लॉग पोस्ट भी है जो संदर्भों को कवर करता है: doubleencore.com/2013/06/context उनका सारांश पैराग्राफ: "ज्यादातर मामलों में, आपके द्वारा काम कर रहे संलग्नक घटक से सीधे आपके लिए उपलब्ध संदर्भ का उपयोग करें। आप सुरक्षित रूप से पकड़ सकते हैं। जब तक यह संदर्भ उस घटक के जीवनचक्र से आगे नहीं बढ़ता है, तब तक आपको संदर्भ के संदर्भ में एक वस्तु से एक संदर्भ को बचाने की आवश्यकता है जो आपकी गतिविधि या सेवा से परे रहता है, यहां तक ​​कि अस्थायी रूप से, उस संदर्भ को स्विच करें जिसे आप सहेजते हैं आवेदन के संदर्भ में। "
कॉमन्सवेयर

48

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

इसके बारे में सोचने और समीक्षा करने के लिए और अधिक:

टोस्ट संदेश के लिए, Google देव गाइड एप्लिकेशन संदर्भ का उपयोग करता है और स्पष्ट रूप से इसका उपयोग करने के लिए कहता है: टोस्ट सूचनाएं

देव गाइड के संवाद अनुभाग में, आप देखते हैं कि AlertDialog.Builder अनुप्रयोग संदर्भ का उपयोग करता है, और फिर प्रगति बार एक गतिविधि संदर्भ का उपयोग करता है। यह Google द्वारा समझाया नहीं गया है। संवाद

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

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


5
मैं पूरी तरह से सहमत। कॉमन्सवेयर का जवाब मेरे लिए थोड़ा आश्चर्यचकित करने वाला था। मुझे खुशी है कि मुझे यह सवाल मिला, क्योंकि int वह Google प्रलेखन बताता है कि getApplicationContext का उपयोग करना इतना खतरनाक हो सकता है।
स्टीव श्वार्ज़

38

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

यहां छवि विवरण दर्ज करें

अधिक जानकारी के लिए सभी गुण मूल लेखक के यहाँ जाते हैं


11

किस संदर्भ का उपयोग करें?

प्रसंग दो प्रकार के होते हैं:

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

  2. गतिविधि संदर्भ गतिविधि के साथ जुड़ा हुआ है और यदि गतिविधि नष्ट हो जाती है तो इसे नष्ट किया जा सकता है - एक ही आवेदन के साथ कई गतिविधियां (संभावना से अधिक) हो सकती हैं। और कभी-कभी आपको गतिविधि संदर्भ संभाल की आवश्यकता होती है। उदाहरण के लिए, क्या आपको एक नई गतिविधि लॉन्च करनी चाहिए, आपको इसके इंटेंट में गतिविधि संदर्भ का उपयोग करने की आवश्यकता है ताकि नई लॉन्चिंग गतिविधि गतिविधि स्टैक के संदर्भ में वर्तमान गतिविधि से जुड़ी हो। हालाँकि, आप एक नई गतिविधि लॉन्च करने के लिए एप्लिकेशन के संदर्भ का भी उपयोग कर सकते हैं, लेकिन फिर आपको Intent.FLAG_ACTIVITY_NEW_TASKइसे एक नए कार्य के रूप में मानने के लिए ध्वज सेट करने की आवश्यकता है ।

आइए कुछ मामलों पर विचार करें:

  • MainActivity.this MainActivity के संदर्भ को संदर्भित करता है जो गतिविधि वर्ग का विस्तार करता है लेकिन आधार वर्ग (गतिविधि) भी प्रसंग वर्ग का विस्तार करता है, इसलिए इसका उपयोग गतिविधि संदर्भ की पेशकश करने के लिए किया जा सकता है।

  • getBaseContext() गतिविधि संदर्भ प्रदान करता है।

  • getApplication() आवेदन संदर्भ प्रदान करता है।

  • getApplicationContext() आवेदन संदर्भ भी प्रदान करता है।

अधिक जानकारी के लिए कृपया इस लिंक को देखें


उस मामले के बारे में क्या है जहां किसी को ऐप में एक एलर्टडायलॉग प्रदर्शित करने की आवश्यकता होती है जैसे कि एक async प्रक्रिया एक परिणाम दिखाती है। इसका एक उदाहरण यह हो सकता है : उपयोगकर्ता डाउनलोड पर क्लिक करता है, यह एक डाउनलोड अनुरोध के लिए आग लगाता है downloadmanager, और जब समाप्त संकेत प्राप्त होता है, तो उसे एक संवाद दिखाना चाहिए जैसे "आप इस डाउनलोड के साथ क्या करना चाहते हैं?"। मेरा (हैक) समाधान Activityएक static Applicationकक्षा में सबसे हाल ही में बचाता है , और Activityडाउनलोड पूरा होने पर वर्तमान का अनुरोध करता है। हालांकि, मुझे संदेह है कि यह उचित कार्यान्वयन है। TL; DR ऐप में कहीं भी AlertDialog कैसे प्रदर्शित करें?
साइबेक्स

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

6

मैं सोच रहा था कि क्यों न हर ऑपरेशन के लिए एप्लिकेशन कॉन्सेप्ट का इस्तेमाल किया जाए जो इसे सपोर्ट करता है। अंत में यह getContext () या getActivity () के लिए मेमोरी लीक और गुम नल जांच की संभावना को कम करता है (जब इंजेक्ट किए गए एप्लिकेशन संदर्भ का उपयोग करते हैं या एप्लिकेशन से स्थिर विधि के माध्यम से प्राप्त किया जाता है)। विवरण, यदि आवश्यक हो तो केवल आवेदन हैक का उपयोग करने के लिए सुश्री हैकबर्न द्वारा दिए गए विवरण के बिना मेरे लिए आश्वस्त नहीं लगते हैं। लेकिन ऐसा लगता है कि मुझे पता नहीं क्यों मिल गया है:

ने पाया है कि कुछ एंड्रॉइड वर्जन / डिवाइस कॉम्बिनेशन पर समस्या है जो इन नियमों का पालन नहीं करते हैं। उदाहरण के लिए, यदि मेरे पास एक ब्रॉडकास्टरेसर है जो एक प्रसंग पास है और मैं उस प्रसंग को एक अनुप्रयोग प्रसंग में रूपांतरित करता हूँ और फिर अनुप्रयोग प्रसंग पर registerReceiver () को कॉल करने का प्रयास करता हूँ, तो ऐसे कई उदाहरण हैं जहाँ यह ठीक काम करता है, लेकिन कई उदाहरण हैं जहाँ मुझे मिलता है ReceiverCallNotAllowedException के कारण कोई क्रैश। ये क्रैश Android संस्करण की API 15 से 22 तक की एक विस्तृत श्रृंखला पर होते हैं। https://possiblemobile.com/2013/06/context/#comment-2443283153

क्योंकि यह गारंटी नहीं है कि नीचे दी गई तालिका में एप्लिकेशन संदर्भ द्वारा समर्थित सभी ऑपरेशन सभी Android उपकरणों पर काम करेंगे! यहां छवि विवरण दर्ज करें


4

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

ProgressDialog.show(this, ....);

या

Toast t = Toast.makeText(this,....);

इन दोनों को गतिविधि के संदर्भ से जानकारी की आवश्यकता होती है जो एप्लिकेशन संदर्भ में प्रदान नहीं की जाती है।


5
हम्म .. आपने कौन से Android OS संस्करण का परीक्षण किया? मैंने 4.4.4 पर परीक्षण किया है और यह अच्छी तरह से काम करता है। इसके अलावा, जैसा कि @Andi Jay ने उल्लेख किया है, आधिकारिक एंड्रॉइड डेवलपर दस्तावेज़ ने अपने नमूना कोड में एप्लिकेशन संदर्भ का उपयोग किया है। डेवलपर
.android.com

1
@ चीनी नाम, हाँ यह काम कर सकता है, लेकिन कभी-कभी उस ऐप के भविष्य में, यह भी दुर्घटनाग्रस्त हो जाएगा। मेरे लिए कई बार हुआ।
ओजोनुगा जुड ओचलिफु

1
जब मैं टोस्ट में गतिविधि संदर्भ का उपयोग करता हूं, तो यह मेमोरी को लीक कर देता है!
जेमशीट इस्केंडरोव

3

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

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