जब कोई ऐप्लिकेशन का कॉम्पोनेंट शुरू होता है और ऐप्लिकेशन के अन्य कॉम्पोनेंट नहीं चल रहे होते हैं, तो Android सिस्टम, ऐप्लिकेशन के लिए एक नई Linux प्रोसेस शुरू करता है. इसमें प्रोग्राम चलाने का एक थ्रेड होता है. डिफ़ॉल्ट रूप से, एक ही ऐप्लिकेशन के सभी कॉम्पोनेंट, एक ही प्रोसेस और थ्रेड में चलते हैं. इसे मुख्य थ्रेड कहा जाता है.
अगर कोई ऐप्लिकेशन कॉम्पोनेंट शुरू होता है और उस ऐप्लिकेशन के लिए पहले से ही कोई प्रोसेस चल रही है, क्योंकि ऐप्लिकेशन का कोई अन्य कॉम्पोनेंट पहले से ही शुरू हो चुका है, तो कॉम्पोनेंट उसी प्रोसेस में शुरू होता है और एक्ज़ीक्यूशन के उसी थ्रेड का इस्तेमाल करता है. हालांकि, अपने ऐप्लिकेशन में अलग-अलग कॉम्पोनेंट को अलग-अलग प्रोसेस में चलाया जा सकता है. साथ ही, किसी भी प्रोसेस के लिए अतिरिक्त थ्रेड बनाए जा सकते हैं.
इस दस्तावेज़ में, Android ऐप्लिकेशन में प्रोसेस और थ्रेड के काम करने के तरीके के बारे में बताया गया है.
प्रोसेस
डिफ़ॉल्ट रूप से, किसी ऐप्लिकेशन के सभी कॉम्पोनेंट एक ही प्रोसेस में चलते हैं. ज़्यादातर ऐप्लिकेशन, इस सेटिंग में बदलाव नहीं करते. हालांकि, अगर आपको यह कंट्रोल करना है कि कोई कॉम्पोनेंट किस प्रोसेस से जुड़ा है, तो मेनिफ़ेस्ट फ़ाइल में ऐसा किया जा सकता है.
हर तरह के कॉम्पोनेंट एलिमेंट—<activity>, <service>, <receiver>, और <provider>—के लिए मेनिफ़ेस्ट एंट्री, android:process एट्रिब्यूट के साथ काम करती है. इससे यह तय किया जा सकता है कि कॉम्पोनेंट किस
प्रोसेस में चलेगा. इस एट्रिब्यूट को इस तरह सेट किया जा सकता है कि हर कॉम्पोनेंट अपनी प्रोसेस में चले या कुछ कॉम्पोनेंट एक प्रोसेस शेयर करें, जबकि अन्य कॉम्पोनेंट ऐसा न करें.
android:process को इस तरह भी सेट किया जा सकता है कि अलग-अलग ऐप्लिकेशन के कॉम्पोनेंट एक ही प्रोसेस में चलें. हालांकि, इसके लिए ज़रूरी है कि ऐप्लिकेशन, एक ही Linux उपयोगकर्ता आईडी शेयर करें और एक ही सर्टिफ़िकेट से साइन किए गए हों.
The <application>
एलिमेंट, android:process एट्रिब्यूट के साथ भी काम करता है. इसका इस्तेमाल, डिफ़ॉल्ट वैल्यू सेट करने के लिए किया जा सकता है. यह वैल्यू सभी कॉम्पोनेंट पर लागू होती है.
Android, किसी प्रोसेस को किसी भी समय बंद कर सकता है. ऐसा तब होता है, जब अन्य प्रोसेस को संसाधनों की ज़रूरत होती है और वे प्रोसेस, उपयोगकर्ता को तुरंत सेवा दे रही होती हैं. बंद की गई प्रोसेस में चल रहे ऐप्लिकेशन कॉम्पोनेंट, बंद होने के बाद खत्म हो जाते हैं. जब इन कॉम्पोनेंट के लिए कोई काम होता है, तो इनके लिए एक प्रोसेस फिर से शुरू की जाती है.
Android सिस्टम, यह तय करते समय कि किन प्रोसेस को बंद करना है, उपयोगकर्ता के लिए उनकी अहमियत का आकलन करता है. उदाहरण के लिए, यह उन प्रोसेस को ज़्यादा आसानी से बंद कर देता है जो स्क्रीन पर अब नहीं दिख रही हैं. इसके मुकाबले, यह उन प्रोसेस को कम आसानी से बंद करता है जो स्क्रीन पर दिख रही हैं. इसलिए, किसी प्रोसेस को खत्म करना है या नहीं, यह इस बात पर निर्भर करता है कि उस प्रोसेस में चल रहे कॉम्पोनेंट किस स्थिति में हैं.
प्रोसेस की लाइफ़साइकल और ऐप्लिकेशन की स्थितियों के साथ उसके संबंध के बारे में जानकारी, प्रोसेस और ऐप्लिकेशन की लाइफ़साइकल में दी गई है.
थ्रेड
जब कोई ऐप्लिकेशन लॉन्च किया जाता है, तो सिस्टम उस ऐप्लिकेशन के लिए एक्ज़ीक्यूशन का एक थ्रेड बनाता है. इसे मुख्य थ्रेड कहा जाता है. यह थ्रेड बहुत अहम होता है, क्योंकि यह इवेंट को सही यूज़र इंटरफ़ेस (यूआई) विजेट पर भेजने की ज़िम्मेदारी लेता है. इसमें ड्रॉइंग इवेंट भी शामिल हैं. यह लगभग हमेशा वह थ्रेड होता है जिसमें आपका ऐप्लिकेशन, Android यूज़र इंटरफ़ेस (यूआई) टूलकिट के android.widget और android.view पैकेज के कॉम्पोनेंट के साथ इंटरैक्ट करता है.
इस वजह से, मुख्य थ्रेड को कभी-कभी यूआई थ्रेड भी कहा जाता है. हालांकि, कुछ खास मामलों में, किसी ऐप्लिकेशन का मुख्य थ्रेड, उसका यूआई थ्रेड नहीं हो सकता. ज़्यादा जानकारी के लिए, थ्रेड
एनोटेशन देखें.
सिस्टम, किसी कॉम्पोनेंट के हर इंस्टेंस के लिए अलग थ्रेड नहीं बनाता. एक ही प्रोसेस में चलने वाले सभी कॉम्पोनेंट, यूआई थ्रेड में इंस्टैंशिएट किए जाते हैं. साथ ही, हर कॉम्पोनेंट के लिए सिस्टम कॉल, उसी थ्रेड से भेजे जाते हैं. इसलिए, सिस्टम कॉलबैक का जवाब देने वाले तरीके—जैसे कि उपयोगकर्ता की कार्रवाइयों की रिपोर्ट करने के लिए onKeyDown() या लाइफ़साइकल कॉलबैक तरीका—हमेशा प्रोसेस के यूआई थ्रेड में चलते हैं.
उदाहरण के लिए, जब उपयोगकर्ता स्क्रीन पर किसी बटन को छूता है, तो आपके ऐप्लिकेशन का यूआई थ्रेड, टच इवेंट को विजेट पर भेजता है. इसके बाद, विजेट अपनी प्रेस की गई स्थिति सेट करता है और इवेंट क्यू में अमान्य करने का अनुरोध पोस्ट करता है. यूआई थ्रेड, अनुरोध को डीक्यू करता है और विजेट को फिर से ड्रॉ करने की सूचना देता है.
अगर आपने अपने ऐप्लिकेशन को सही तरीके से लागू नहीं किया है, तो इस सिंगल-थ्रेड मॉडल से खराब परफ़ॉर्मेंस मिल सकती है. ऐसा तब होता है, जब आपका ऐप्लिकेशन, उपयोगकर्ता के इंटरैक्शन के जवाब में ज़्यादा काम करता है. यूआई थ्रेड में लंबे समय तक चलने वाली कार्रवाइयां करने से, पूरा यूआई ब्लॉक हो जाता है. जैसे, नेटवर्क ऐक्सेस या डेटाबेस क्वेरी. जब थ्रेड ब्लॉक हो जाता है, तो ड्रॉइंग इवेंट सहित कोई भी इवेंट नहीं भेजा जा सकता.
उपयोगकर्ता को ऐसा लगता है कि ऐप्लिकेशन जवाब देना बंद कर दिया है. इससे भी खराब बात यह है कि अगर यूआई थ्रेड कुछ सेकंड से ज़्यादा समय के लिए ब्लॉक हो जाता है, तो उपयोगकर्ता को "ऐप्लिकेशन जवाब नहीं दे रहा है" (एएनआर) डायलॉग दिखता है. इसके बाद, उपयोगकर्ता आपके ऐप्लिकेशन को बंद कर सकता है या उसे अनइंस्टॉल भी कर सकता है.
ध्यान रखें कि Android यूज़र इंटरफ़ेस (यूआई) टूलकिट, थ्रेड-सेफ़ नहीं है. इसलिए, वर्कर थ्रेड से अपने यूआई में बदलाव न करें. यूज़र इंटरफ़ेस (यूआई) में सभी बदलाव, यूआई थ्रेड से करें. Android के सिंगल-थ्रेड मॉडल के दो नियम हैं:
- यूआई थ्रेड को ब्लॉक न करें.
- यूआई थ्रेड के बाहर से, Android यूज़र इंटरफ़ेस (यूआई) टूलकिट को ऐक्सेस न करें.
वर्कर थ्रेड
इस सिंगल-थ्रेड मॉडल की वजह से, यह ज़रूरी है कि आपके ऐप्लिकेशन का यूआई रिस्पॉन्सिव हो. इसके लिए, यूआई थ्रेड को ब्लॉक न करें. अगर आपको ऐसी कार्रवाइयां करनी हैं जो तुरंत नहीं होती हैं, तो पक्का करें कि उन्हें अलग बैकग्राउंड या वर्कर थ्रेड में किया जाए. बस यह याद रखें कि यूआई या मुख्य थ्रेड के अलावा, किसी अन्य थ्रेड से यूआई को अपडेट नहीं किया जा सकता.
इन नियमों का पालन करने में आपकी मदद करने के लिए, Android अन्य थ्रेड से यूआई थ्रेड को ऐक्सेस करने के कई तरीके उपलब्ध कराता है. यहां उन तरीकों की सूची दी गई है जिनसे मदद मिल सकती है:
यहां दिए गए उदाहरणों में, किसी टास्क को बैकग्राउंड थ्रेड पर ऑफ़लोड करने और टास्क पूरा होने के बाद यूआई थ्रेड को अपडेट करने का तरीका बताया गया है:
Kotlin
// Kotlin coroutines implementation. fun onClick(v: View) { // Launch a coroutine in the lifecycle scope (e.g., in an Activity or Fragment). lifecycleScope.launch { // Run the blocking task on the IO dispatcher. val bitmap = withContext(Dispatchers.IO) { BitmapFactory.decodeFile("image.png") } // Back on the main thread, update the UI. imageView.setImageBitmap(bitmap) } }
Java
// Java Executor implementation. // (executorService is assumed to be defined elsewhere). public void onClick(View v) { executorService.execute(() -> { // Run the heavy task on a background thread. Bitmap bitmap = BitmapFactory.decodeFile("image.png"); // Update the View on the UI thread. imageView.post(() -> imageView.setImageBitmap(bitmap)); }); }
यह लागू करने का तरीका थ्रेड-सेफ़ है, क्योंकि बैकग्राउंड में होने वाली कार्रवाई, अलग थ्रेड से की जाती है. वहीं, ImageView में हमेशा यूआई थ्रेड से बदलाव किया जाता है.
हालांकि, जैसे-जैसे कार्रवाई की जटिलता बढ़ती है, इस तरह का कोड जटिल हो सकता है और इसे बनाए रखना मुश्किल हो सकता है. वर्कर थ्रेड के साथ ज़्यादा जटिल इंटरैक्शन को मैनेज करने के लिए, अपने वर्कर थ्रेड में Handler का इस्तेमाल किया जा सकता है. इससे, यूआई थ्रेड से भेजे गए मैसेज को प्रोसेस किया जा सकता है. बैकग्राउंड थ्रेड पर काम शेड्यूल करने और यूआई थ्रेड पर वापस कम्यूनिकेट करने के तरीके के बारे में पूरी जानकारी पाने के लिए, देखें
बैकग्राउंड में होने वाले काम की खास जानकारी.
थ्रेड-सेफ़ तरीके
कुछ स्थितियों में, लागू किए गए तरीकों को एक से ज़्यादा थ्रेड से कॉल किया जाता है. इसलिए, उन्हें थ्रेड-सेफ़ बनाने के लिए लिखा जाना चाहिए.
यह मुख्य रूप से उन तरीकों के लिए सही है जिन्हें रिमोट से कॉल किया जा सकता है. जैसे, बाउंड सर्विस में मौजूद तरीके. जब
तरीके पर कॉल, उसी प्रोसेस में होता है जिसमें
IBinder चल रहा है, तो तरीका कॉलर के थ्रेड में एक्ज़ीक्यूट होता है.IBinder
हालांकि, जब कॉल किसी अन्य प्रोसेस में होता है, तो तरीका, थ्रेड के पूल से चुने गए थ्रेड में एक्ज़ीक्यूट होता है. सिस्टम, IBinder के साथ-साथ उसी प्रोसेस में थ्रेड का पूल बनाए रखता है.
यह प्रोसेस के यूआई थ्रेड में एक्ज़ीक्यूट नहीं होता.
उदाहरण के लिए, किसी सर्विस के
onBind() तरीके को सर्विस की प्रोसेस के यूज़र इंटरफ़ेस (यूआई) थ्रेड से कॉल किया जाता है. वहीं, onBind() से मिलने वाले ऑब्जेक्ट में लागू किए गए तरीकों को पूल में मौजूद थ्रेड से कॉल किया जाता है. जैसे, रिमोट प्रोसीजर कॉल (आरपीसी) के तरीकों को लागू करने वाली सब-क्लास. किसी सर्विस के एक से ज़्यादा क्लाइंट हो सकते हैं. इसलिए, एक से ज़्यादा पूल थ्रेड, एक ही समय पर एक ही IBinder तरीके का इस्तेमाल कर सकते हैं. इसलिए, IBinder के तरीकों को थ्रेड-सेफ़ बनाने के लिए लागू किया जाना चाहिए.
इसी तरह, कॉन्टेंट प्रोवाइडर को अन्य प्रोसेस से डेटा के अनुरोध मिल सकते हैं.
ContentResolver और ContentProvider
क्लास, इंटरप्रोसेस कम्यूनिकेशन (आईपीसी) को मैनेज करने के तरीके की जानकारी छिपाती हैं.
हालांकि, उन अनुरोधों का जवाब देने वाले ContentProvider के तरीकों—
तरीकों query(),
insert(),
delete(),
update(), और getType()—को
कॉन्टेंट प्रोवाइडर की प्रोसेस में मौजूद थ्रेड के पूल से कॉल किया जाता है. इन्हें प्रोसेस के यूआई
थ्रेड से कॉल नहीं किया जाता. इन तरीकों को एक ही समय पर किसी भी संख्या में थ्रेड से कॉल किया जा सकता है. इसलिए, इन्हें भी थ्रेड-सेफ़ बनाने के लिए लागू किया जाना चाहिए.
इंटरप्रोसेस कम्यूनिकेशन
Android, आरपीसी का इस्तेमाल करके आईपीसी के लिए एक तरीका उपलब्ध कराता है. इसमें, किसी ऐक्टिविटी या अन्य ऐप्लिकेशन कॉम्पोनेंट से किसी तरीके को कॉल किया जाता है. हालांकि, यह रिमोट से किसी अन्य प्रोसेस में एक्ज़ीक्यूट होता है. साथ ही, नतीजे को कॉलर को वापस भेजा जाता है. इसमें, किसी तरीके के कॉल और उसके डेटा को उस लेवल पर डीकंपोज़ करना शामिल है जिसे ऑपरेटिंग सिस्टम समझ सके. इसके बाद, इसे लोकल प्रोसेस और पता स्पेस से रिमोट प्रोसेस और पता स्पेस में ट्रांसमिट करना. फिर, वहां कॉल को फिर से असेंबल करना और फिर से लागू करना.
इसके बाद, रिटर्न वैल्यू को उल्टी दिशा में ट्रांसमिट किया जाता है. Android, आईपीसी के इन लेन-देन को पूरा करने के लिए सभी कोड उपलब्ध कराता है. इसलिए, आरपीसी प्रोग्रामिंग इंटरफ़ेस को तय करने और लागू करने पर फ़ोकस किया जा सकता है.
आईपीसी करने के लिए, आपके ऐप्लिकेशन को bindService() का इस्तेमाल करके किसी सर्विस से बाइंड करना होगा. ज़्यादा जानकारी के लिए, सेवाओं की खास जानकारी देखें.