सेवाओं की खास जानकारी

Service एक ऐसा ऐप्लिकेशन कॉम्पोनेंट है जो बैकग्राउंड में लंबे समय तक चलने वाले ऑपरेशन कर सकता है. इसमें कोई यूज़र इंटरफ़ेस नहीं होता. शुरू होने के बाद, कोई सेवा कुछ समय तक चलती रह सकती है. भले ही, उपयोगकर्ता किसी दूसरे ऐप्लिकेशन पर स्विच कर ले. इसके अलावा, कोई कॉम्पोनेंट किसी सेवा से इंटरैक्ट करने के लिए उससे बंध सकता है और इंटरप्रोसेस कम्यूनिकेशन (आईपीसी) भी कर सकता है. उदाहरण के लिए, कोई सेवा बैकग्राउंड में नेटवर्क लेन-देन मैनेज कर सकती है, संगीत चला सकती है, फ़ाइल I/O कर सकती है या कॉन्टेंट उपलब्ध कराने वाली कंपनी के साथ इंटरैक्ट कर सकती है.

ध्यान दें: कोई सेवा, होस्ट करने की प्रोसेस के मुख्य थ्रेड में चलती है. सेवा अपनी थ्रेड नहीं बनाती और किसी दूसरी प्रोसेस में तब तक नहीं चलती, जब तक आपने इसके लिए अलग से निर्देश न दिया हो. ऐप्लिकेशन के काम न करने (ANR) से जुड़ी गड़बड़ियों से बचने के लिए, आपको सेवा में किसी भी ब्लॉकिंग ऑपरेशन को अलग थ्रेड पर चलाना चाहिए.

सेवाओं के टाइप

ये तीन तरह की सेवाएं हैं:

फ़ोरग्राउंड

फ़ोरग्राउंड सेवा, कोई ऐसा काम करती है जो उपयोगकर्ता को दिखता है. उदाहरण के लिए, कोई ऑडियो ऐप्लिकेशन, ऑडियो ट्रैक चलाने के लिए फ़ोरग्राउंड सेवा का इस्तेमाल करेगा. फ़ोरग्राउंड सेवाओं को सूचना दिखानी होगी. फ़ोरग्राउंड सेवाएं तब भी चलती रहती हैं, जब उपयोगकर्ता ऐप्लिकेशन के साथ इंटरैक्ट न कर रहा हो.

फ़ोरग्राउंड सेवा का इस्तेमाल करते समय, आपको एक सूचना दिखानी होगी, ताकि उपयोगकर्ताओं को यह पता रहे कि सेवा चल रही है. इस सूचना को तब तक नहीं हटाया जा सकता, जब तक सेवा को बंद नहीं किया जाता या उसे फ़ोरग्राउंड से नहीं हटाया जाता.

अपने ऐप्लिकेशन में फ़ोरग्राउंड सेवाओं को कॉन्फ़िगर करने के तरीके के बारे में ज़्यादा जानें.

ध्यान दें: WorkManager एपीआई, टास्क शेड्यूल करने का एक आसान तरीका उपलब्ध कराता है. साथ ही, ज़रूरत पड़ने पर, इन टास्क को फ़ोरग्राउंड सेवाओं के तौर पर चला सकता है. कई मामलों में, सीधे तौर पर फ़ोरग्राउंड सेवाओं का इस्तेमाल करने के बजाय, WorkManager का इस्तेमाल करना बेहतर होता है.

बैकग्राउंड
बैकग्राउंड सेवा, ऐसा काम करती है जिस पर उपयोगकर्ता का ध्यान सीधे तौर पर नहीं जाता. उदाहरण के लिए, अगर किसी ऐप्लिकेशन ने अपने स्टोरेज को कम करने के लिए किसी सेवा का इस्तेमाल किया है, तो आम तौर पर वह बैकग्राउंड सेवा होगी.

ध्यान दें: अगर आपका ऐप्लिकेशन एपीआई लेवल 26 या उसके बाद के वर्शन को टारगेट करता है, तो सिस्टम बैकग्राउंड में चल रही सेवाओं पर पाबंदियां लगाता है. ऐसा तब होता है, जब ऐप्लिकेशन फ़ोरग्राउंड में नहीं होता. उदाहरण के लिए, ज़्यादातर मामलों में, आपको बैकग्राउंड में जगह की जानकारी ऐक्सेस नहीं करनी चाहिए. इसके बजाय, WorkManager का इस्तेमाल करके टास्क शेड्यूल करें.

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

इस दस्तावेज़ में आम तौर पर, शुरू की गई और बाउंड की गई सेवाओं के बारे में अलग-अलग बताया गया है. हालांकि, आपकी सेवा दोनों तरह से काम कर सकती है—इसे शुरू किया जा सकता है (ताकि यह अनलिमिटेड समय तक चलती रहे) और इसे बाउंड भी किया जा सकता है. यह सिर्फ़ इस बात पर निर्भर करता है कि आपने कुछ कॉलबैक तरीके लागू किए हैं या नहीं: onStartCommand() कॉम्पोनेंट को इसे शुरू करने की अनुमति देने के लिए और onBind() बाइंड करने की अनुमति देने के लिए.

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

सेवा और थ्रेड में से किसी एक को चुनना

सेवा, एक ऐसा कॉम्पोनेंट है जो बैकग्राउंड में चल सकता है. भले ही, उपयोगकर्ता आपके ऐप्लिकेशन के साथ इंटरैक्ट न कर रहा हो. इसलिए, आपको सेवा सिर्फ़ तब बनानी चाहिए, जब आपको इसकी ज़रूरत हो.

अगर आपको अपनी मुख्य थ्रेड के बाहर काम करना है, लेकिन सिर्फ़ तब जब उपयोगकर्ता आपके ऐप्लिकेशन के साथ इंटरैक्ट कर रहा हो, तो आपको किसी दूसरे ऐप्लिकेशन कॉम्पोनेंट के संदर्भ में नई थ्रेड बनानी चाहिए. उदाहरण के लिए, अगर आपको सिर्फ़ गतिविधि के दौरान संगीत चलाना है, तो onCreate() में एक थ्रेड बनाएं. इसके बाद, onStart() में इसे चलाएं और onStop() में इसे रोकें. इसके अलावा, Thread क्लास के बजाय, java.util.concurrent पैकेज या Kotlin कोरूटीन के थ्रेड पूल और एक्ज़ीक्यूटर का इस्तेमाल करें. बैकग्राउंड थ्रेड में प्रोसेस को ट्रांसफ़र करने के बारे में ज़्यादा जानकारी के लिए, Android पर थ्रेडिंग दस्तावेज़ देखें.

याद रखें कि किसी सेवा का इस्तेमाल करने पर भी, वह डिफ़ॉल्ट रूप से आपके ऐप्लिकेशन की मुख्य थ्रेड में ही चलती है. इसलिए, अगर सेवा में ज़्यादा या ब्लॉक करने वाले ऑपरेशन किए जाते हैं, तो आपको सेवा में एक नई थ्रेड बनानी चाहिए.

बुनियादी बातें

कोई सेवा बनाने के लिए, आपको Service की सब-क्लास बनानी होगी या उसकी किसी मौजूदा सब-क्लास का इस्तेमाल करना होगा. इसे लागू करते समय, आपको कुछ कॉलबैक तरीकों को बदलना होगा. ये ऐसे तरीके होते हैं जो सेवा के लाइफ़साइकल के मुख्य पहलुओं को मैनेज करते हैं. साथ ही, आपको एक ऐसा तरीका भी देना होगा जिससे कॉम्पोनेंट, सेवा से बंध सकें. हालांकि, ऐसा तब ही करना चाहिए, जब ज़रूरी हो. ये सबसे अहम कॉलबैक तरीके हैं, जिन्हें आपको बदलना चाहिए:

onStartCommand()
जब कोई अन्य कॉम्पोनेंट (जैसे, कोई गतिविधि) सेवा शुरू करने का अनुरोध करता है, तो सिस्टम startService() को कॉल करके इस तरीके को शुरू करता है. इस तरीके का इस्तेमाल करने पर, सेवा शुरू हो जाती है और यह बैकग्राउंड में कभी भी चल सकती है. अगर आपने यह तरीका अपनाया है, तो stopSelf() या stopService() को कॉल करके, काम पूरा होने पर सेवा को बंद करना आपकी ज़िम्मेदारी है. अगर आपको सिर्फ़ बाइंडिंग की सुविधा देनी है, तो आपको यह तरीका लागू करने की ज़रूरत नहीं है.
onBind()
जब कोई दूसरा कॉम्पोनेंट सेवा से कनेक्ट करना चाहता है, तो सिस्टम bindService() को कॉल करके इस तरीके को शुरू करता है. जैसे, आरपीसी (रिकॉर्ड किए गए अनुरोध) करने के लिए. इस तरीके को लागू करते समय, आपको एक इंटरफ़ेस उपलब्ध कराना होगा. क्लाइंट इस इंटरफ़ेस का इस्तेमाल करके, IBinder दिखाकर सेवा के साथ इंटरैक्ट करते हैं. आपको हमेशा यह तरीका लागू करना चाहिए. हालांकि, अगर आपको बाइंडिंग की अनुमति नहीं देनी है, तो आपको null दिखाना चाहिए.
onCreate()
सिस्टम, इस तरीके को एक बार सेटअप करने की प्रोसेस को पूरा करने के लिए इस्तेमाल करता है. ऐसा तब किया जाता है, जब सेवा को पहली बार बनाया जाता है. यह प्रोसेस, onStartCommand() या onBind() को कॉल करने से पहले पूरी की जाती है. अगर सेवा पहले से चल रही है, तो इस तरीके को कॉल नहीं किया जाता.
onDestroy()
सिस्टम इस तरीके को तब लागू करता है, जब सेवा का इस्तेमाल बंद हो जाता है और उसे बंद किया जा रहा होता है. आपकी सेवा को थ्रेड, रजिस्टर किए गए Listener या रिसीवर जैसे संसाधनों को हटाने के लिए, इसे लागू करना चाहिए. यह सेवा को मिलने वाला आखिरी कॉल है.

अगर कोई कॉम्पोनेंट startService() को कॉल करके सेवा शुरू करता है (इससे onStartCommand() को कॉल किया जाता है), तो सेवा तब तक चलती रहती है, जब तक वह stopSelf() से अपने-आप बंद नहीं हो जाती या कोई दूसरा कॉम्पोनेंट stopService() को कॉल करके उसे बंद नहीं कर देता.

अगर कोई कॉम्पोनेंट सेवा बनाने के लिए bindService() को कॉल करता है और onStartCommand() को नहीं कॉल किया जाता है, तो सेवा सिर्फ़ तब तक चलती है, जब तक कॉम्पोनेंट उससे बंधा होता है. सभी क्लाइंट से सेवा को अनबाउंड करने के बाद, सिस्टम उसे मिटा देता है.

Android सिस्टम किसी सेवा को सिर्फ़ तब बंद करता है, जब डिवाइस में स्टोरेज कम हो और उसे उस गतिविधि के लिए सिस्टम के संसाधनों को वापस पाना हो जिस पर उपयोगकर्ता का फ़ोकस है. अगर सेवा किसी ऐसी गतिविधि से जुड़ी है जिस पर उपयोगकर्ता का फ़ोकस है, तो उसे बंद किए जाने की संभावना कम होती है. अगर सेवा को फ़ोरग्राउंड में चलाने के लिए डिक्लेयर्ड किया गया है, तो उसे शायद ही बंद किया जाए. अगर सेवा शुरू हो गई है और लंबे समय से चल रही है, तो सिस्टम समय के साथ बैकग्राउंड टास्क की सूची में इसकी स्थिति को कम कर देता है. साथ ही, सेवा को बंद करने की संभावना बहुत ज़्यादा बढ़ जाती है. अगर आपकी सेवा शुरू हो गई है, तो आपको इसे सिस्टम के रीस्टार्ट को आसानी से मैनेज करने के लिए डिज़ाइन करना होगा. अगर सिस्टम आपकी सेवा को बंद कर देता है, तो संसाधन उपलब्ध होते ही वह उसे फिर से शुरू कर देता है. हालांकि, यह इस बात पर भी निर्भर करता है कि onStartCommand() से कौनसी वैल्यू वापस की जाती है. सिस्टम किसी सेवा को कब मिटा सकता है, इस बारे में ज़्यादा जानकारी के लिए, प्रोसेस और थ्रेडिंग दस्तावेज़ देखें.

नीचे दिए गए सेक्शन में, आपको startService() और bindService() सेवा के तरीके बनाने का तरीका बताया जाएगा. साथ ही, अन्य ऐप्लिकेशन कॉम्पोनेंट से इनका इस्तेमाल करने का तरीका भी बताया जाएगा.

मेनिफ़ेस्ट में किसी सेवा के बारे में बताना

आपको अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल में सभी सेवाओं का एलान करना होगा. ठीक उसी तरह जैसे गतिविधियों और अन्य कॉम्पोनेंट के लिए किया जाता है.

अपनी सेवा का एलान करने के लिए, <application> एलिमेंट के चाइल्ड के तौर पर <service> एलिमेंट जोड़ें. उदाहरण के लिए:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

मेनिफ़ेस्ट में अपनी सेवा के बारे में बताने के बारे में ज़्यादा जानने के लिए, <service> एलिमेंट का रेफ़रंस देखें.

प्रॉपर्टी तय करने के लिए, <service> एलिमेंट में कुछ और एट्रिब्यूट शामिल किए जा सकते हैं. जैसे, सेवा शुरू करने के लिए ज़रूरी अनुमतियां और वह प्रोसेस जिसमें सेवा को चलाया जाना चाहिए. android:name एट्रिब्यूट, ज़रूरी एट्रिब्यूट है. इससे सेवा की क्लास का नाम पता चलता है. ऐप्लिकेशन पब्लिश करने के बाद, इस नाम में कोई बदलाव न करें. ऐसा इसलिए, ताकि सेवा को शुरू करने या बांधने के लिए, साफ़ तौर पर बताए गए इंटेंट पर निर्भरता की वजह से कोड के काम न करने का जोखिम न हो. ऐसी चीज़ें जो बदली नहीं जा सकतीं ब्लॉग पोस्ट पढ़ें.

चेतावनी: यह पक्का करने के लिए कि आपका ऐप्लिकेशन सुरक्षित है, Service शुरू करते समय हमेशा साफ़ तौर पर बताए गए इंटेंट का इस्तेमाल करें. साथ ही, अपनी सेवाओं के लिए इंटेंट फ़िल्टर का एलान न करें. किसी सेवा को शुरू करने के लिए इंप्लिसिट इंटेंट का इस्तेमाल करना, सुरक्षा के लिहाज़ से खतरनाक हो सकता है. ऐसा इसलिए, क्योंकि यह पक्का नहीं किया जा सकता कि इंटेंट का जवाब कौनसी सेवा देगी. साथ ही, उपयोगकर्ता यह भी नहीं देख सकता कि कौनसी सेवा शुरू हुई है. Android 5.0 (एपीआई लेवल 21) से, अगर किसी इंप्लिसिट इंटेंट के साथ bindService() को कॉल किया जाता है, तो सिस्टम एक अपवाद दिखाता है.

android:exported एट्रिब्यूट को शामिल करके और उसे false पर सेट करके, यह पक्का किया जा सकता है कि आपकी सेवा सिर्फ़ आपके ऐप्लिकेशन के लिए उपलब्ध हो. इससे दूसरे ऐप्लिकेशन, साफ़ तौर पर इंटेंट का इस्तेमाल करने पर भी आपकी सेवा शुरू नहीं कर पाएंगे.

ध्यान दें: उपयोगकर्ता यह देख सकते हैं कि उनके डिवाइस पर कौनसी सेवाएं चल रही हैं. अगर उन्हें कोई ऐसी सेवा दिखती है जिसकी जानकारी उन्हें नहीं है या जिस पर उन्हें भरोसा नहीं है, तो वे उस सेवा को बंद कर सकते हैं. उपयोगकर्ताओं की गलती से आपकी सेवा बंद न हो, इसके लिए आपको अपने ऐप्लिकेशन मेनिफ़ेस्ट में <service> एलिमेंट में android:description एट्रिब्यूट जोड़ना होगा. ब्यौरे में, कम शब्दों में बताएं कि सेवा क्या करती है और इससे क्या फ़ायदे मिलते हैं.

शुरू की गई सेवा बनाना

शुरू की गई सेवा वह होती है जिसे कोई दूसरा कॉम्पोनेंट startService() को कॉल करके शुरू करता है. इससे सेवा के onStartCommand() तरीके को कॉल किया जाता है.

जब कोई सेवा शुरू की जाती है, तो उसका लाइफ़साइकल, उसे शुरू करने वाले कॉम्पोनेंट से अलग होता है. सेवा, बैकग्राउंड में कभी भी चल सकती है. भले ही, उसे शुरू करने वाला कॉम्पोनेंट नष्ट हो गया हो. इसलिए, जब सेवा का काम पूरा हो जाए, तो उसे stopSelf() को कॉल करके खुद को बंद कर देना चाहिए. इसके अलावा, कोई दूसरा कॉम्पोनेंट भी stopService() को कॉल करके उसे बंद कर सकता है.

ऐप्लिकेशन का कोई कॉम्पोनेंट, जैसे कि कोई गतिविधि, startService() को कॉल करके और Intent को पास करके सेवा शुरू कर सकती है. Intent से सेवा के बारे में पता चलता है और इसमें सेवा के इस्तेमाल के लिए कोई डेटा शामिल होता है. सेवा को onStartCommand() तरीके से यह Intent मिलता है.

उदाहरण के लिए, मान लें कि किसी गतिविधि को किसी ऑनलाइन डेटाबेस में कुछ डेटा सेव करना है. गतिविधि, startService() को इंटेंट भेजकर, साथी सेवा शुरू कर सकती है और उसे सेव करने के लिए डेटा दे सकती है. सेवा को onStartCommand() में इंटेंट मिलता है, वह इंटरनेट से कनेक्ट होती है, और डेटाबेस लेन-देन करती है. लेन-देन पूरा हो जाने के बाद, सेवा अपने-आप बंद हो जाती है और उसे मिटा दिया जाता है.

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

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

Android फ़्रेमवर्क, Service का IntentServiceसबक्लास भी उपलब्ध कराता है. यह सबक्लास, एक बार में एक करके सभी स्टार्ट रिक्वेस्ट को हैंडल करने के लिए, वर्कर्स थ्रेड का इस्तेमाल करता है. नए ऐप्लिकेशन के लिए, इस क्लास का इस्तेमाल करने का सुझाव नहीं दिया जाता. ऐसा इसलिए है, क्योंकि बैकग्राउंड में प्रोसेस करने की सीमाओं के लागू होने की वजह से, यह Android 8 Oreo के बाद के वर्शन पर ठीक से काम नहीं करेगी. इसके अलावा, Android 11 से इसे बंद कर दिया गया है. IntentService की जगह JobIntentService का इस्तेमाल किया जा सकता है. यह Android के नए वर्शन के साथ काम करता है.

नीचे दिए गए सेक्शन में, अपनी कस्टम सेवा लागू करने का तरीका बताया गया है. हालांकि, ज़्यादातर इस्तेमाल के उदाहरणों के लिए, आपको WorkManager का इस्तेमाल करना चाहिए. Android पर बैकग्राउंड प्रोसेसिंग की गाइड पढ़ें और देखें कि क्या आपकी ज़रूरतों के हिसाब से कोई समाधान है.

सेवा क्लास को एक्सटेंड करना

हर इनकमिंग इंटेंट को हैंडल करने के लिए, Service क्लास को बड़ा किया जा सकता है. बुनियादी तौर पर लागू करने का तरीका यहां बताया गया है:

Kotlin

class HelloService : Service() {

    private var serviceLooper: Looper? = null
    private var serviceHandler: ServiceHandler? = null

    // Handler that receives messages from the thread
    private inner class ServiceHandler(looper: Looper) : Handler(looper) {

        override fun handleMessage(msg: Message) {
            // Normally we would do some work here, like download a file.
            // For our sample, we just sleep for 5 seconds.
            try {
                Thread.sleep(5000)
            } catch (e: InterruptedException) {
                // Restore interrupt status.
                Thread.currentThread().interrupt()
            }

            // Stop the service using the startId, so that we don't stop
            // the service in the middle of handling another job
            stopSelf(msg.arg1)
        }
    }

    override fun onCreate() {
        // Start up the thread running the service.  Note that we create a
        // separate thread because the service normally runs in the process's
        // main thread, which we don't want to block.  We also make it
        // background priority so CPU-intensive work will not disrupt our UI.
        HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply {
            start()

            // Get the HandlerThread's Looper and use it for our Handler
            serviceLooper = looper
            serviceHandler = ServiceHandler(looper)
        }
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show()

        // For each start request, send a message to start a job and deliver the
        // start ID so we know which request we're stopping when we finish the job
        serviceHandler?.obtainMessage()?.also { msg ->
            msg.arg1 = startId
            serviceHandler?.sendMessage(msg)
        }

        // If we get killed, after returning from here, restart
        return START_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        // We don't provide binding, so return null
        return null
    }

    override fun onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show()
    }
}

Java

public class HelloService extends Service {
  private Looper serviceLooper;
  private ServiceHandler serviceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service. Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block. We also make it
    // background priority so CPU-intensive work doesn't disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    serviceLooper = thread.getLooper();
    serviceHandler = new ServiceHandler(serviceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = serviceHandler.obtainMessage();
      msg.arg1 = startId;
      serviceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

उदाहरण के तौर पर दिया गया कोड, onStartCommand() में आने वाले सभी कॉल को मैनेज करता है और बैकग्राउंड थ्रेड पर चल रहे Handler में काम को पोस्ट करता है. यह IntentService की तरह ही काम करता है और सभी अनुरोधों को एक के बाद एक क्रम से प्रोसेस करता है. अगर आपको एक साथ कई अनुरोध चलाने हैं, तो कोड में बदलाव करके, थ्रेड पूल पर काम चलाया जा सकता है.

ध्यान दें कि onStartCommand() मेथड से पूर्णांक दिखना चाहिए. इंटिजर एक वैल्यू है, जो बताती है कि अगर सिस्टम किसी सेवा को बंद कर देता है, तो उसे कैसे जारी रखना चाहिए. onStartCommand() से मिलने वाली वैल्यू, इनमें से कोई एक स्थिर वैल्यू होनी चाहिए:

START_NOT_STICKY
अगर onStartCommand() के वापस आने के बाद सिस्टम, सेवा को बंद कर देता है, तो सेवा को फिर से न बनाएं. ऐसा तब तक न करें, जब तक डिलीवर किए जाने के लिए इंटेंट बाकी हों. यह सबसे सुरक्षित विकल्प है, ताकि ज़रूरत न होने पर भी आपकी सेवा न चले और आपका ऐप्लिकेशन, अधूरे किसी भी काम को आसानी से फिर से शुरू कर सके.
START_STICKY
अगर onStartCommand() के वापस आने के बाद सिस्टम, सेवा को बंद कर देता है, तो सेवा को फिर से बनाएं और onStartCommand() को कॉल करें. हालांकि, आखिरी इंटेंट को फिर से डिलीवर न करें. इसके बजाय, सिस्टम onStartCommand() को किसी भी इंटेंट के साथ कॉल करता है, बशर्ते सेवा शुरू करने के लिए कोई इंटेंट बाकी न हो. ऐसे में, उन इंटेंट को डिलीवर किया जाता है. यह उन मीडिया प्लेयर (या मिलती-जुलती सेवाओं) के लिए सही है जो निर्देशों को लागू नहीं कर रहे हैं, लेकिन अनलिमिटेड तौर पर चल रहे हैं और किसी काम के लिए इंतज़ार कर रहे हैं.
START_REDELIVER_INTENT
अगर onStartCommand() के वापस आने के बाद सिस्टम, सेवा को बंद कर देता है, तो सेवा को फिर से बनाएं और सेवा को डिलीवर किए गए आखिरी इंटेंट के साथ onStartCommand() को कॉल करें. बकाया इंटेंट को क्रम से डिलीवर किया जाता है. यह उन सेवाओं के लिए सही है जो किसी काम को सक्रिय रूप से कर रही हों और उसे तुरंत फिर से शुरू करना ज़रूरी हो. जैसे, फ़ाइल डाउनलोड करना.

रिटर्न की गई इन वैल्यू के बारे में ज़्यादा जानने के लिए, हर कॉन्स्टेंट के लिए लिंक किया गया रेफ़रंस दस्तावेज़ देखें.

सेवा शुरू करना

किसी ऐक्टिविटी या अन्य ऐप्लिकेशन कॉम्पोनेंट से सेवा शुरू की जा सकती है. इसके लिए, Intent को startService() या startForegroundService() पर पास करें. Android सिस्टम, सेवा के onStartCommand() तरीके को कॉल करता है और उसे Intent भेजता है. इससे यह तय होता है कि कौनसी सेवा शुरू करनी है.

ध्यान दें: अगर आपका ऐप्लिकेशन एपीआई लेवल 26 या उसके बाद के वर्शन को टारगेट करता है, तो सिस्टम, बैकग्राउंड सेवाओं का इस्तेमाल करने या उन्हें बनाने पर पाबंदियां लगाता है. ऐसा तब तक होता है, जब तक ऐप्लिकेशन खुद फ़ोरग्राउंड में न हो. अगर किसी ऐप्लिकेशन को फ़ोरग्राउंड सेवा बनानी है, तो ऐप्लिकेशन को startForegroundService() को कॉल करना चाहिए. यह तरीका, बैकग्राउंड सेवा बनाता है. हालांकि, यह तरीका सिस्टम को यह सिग्नल देता है कि सेवा खुद को फ़ोरग्राउंड में प्रमोट करेगी. सेवा बन जाने के बाद, उसे पांच सेकंड के अंदर अपने startForeground() तरीके को कॉल करना होगा.

उदाहरण के लिए, कोई ऐक्टिविटी, startService() के साथ साफ़ तौर पर बताए गए इंटेंट का इस्तेमाल करके, पिछले सेक्शन (HelloService) में मौजूद उदाहरण सेवा को शुरू कर सकती है, जैसा कि यहां दिखाया गया है:

Kotlin

startService(Intent(this, HelloService::class.java))

Java

startService(new Intent(this, HelloService.class));

startService() तरीका तुरंत काम करता है और Android सिस्टम, सेवा के onStartCommand() तरीके को कॉल करता है. अगर सेवा पहले से चालू नहीं है, तो सिस्टम पहले onCreate() को कॉल करता है और फिर onStartCommand() को कॉल करता है.

अगर सेवा, बाइंडिंग की सुविधा भी नहीं देती है, तो startService() के साथ डिलीवर किया गया इंटेंट, ऐप्लिकेशन कॉम्पोनेंट और सेवा के बीच कम्यूनिकेशन का एकमात्र तरीका होता है. हालांकि, अगर आपको सेवा से नतीजा वापस चाहिए, तो सेवा शुरू करने वाला क्लाइंट, ब्रॉडकास्ट के लिए PendingIntent (getBroadcast() के साथ) बना सकता है और उसे सेवा शुरू करने वाले Intent में सेवा को डिलीवर कर सकता है. इसके बाद, सेवा नतीजा देने के लिए ब्रॉडकास्ट का इस्तेमाल कर सकती है.

सेवा शुरू करने के कई अनुरोधों की वजह से, सेवा के onStartCommand() पर कई कॉल किए जाते हैं. हालांकि, सेवा को बंद करने के लिए, stopSelf() या stopService() के साथ सिर्फ़ एक अनुरोध ज़रूरी है.

किसी सेवा को बंद करना

शुरू की गई सेवा को अपना लाइफ़साइकल मैनेज करना होगा. इसका मतलब है कि सिस्टम तब तक सेवा को बंद या नष्ट नहीं करता, जब तक उसे सिस्टम मेमोरी वापस नहीं लानी पड़ती. साथ ही, onStartCommand() के वापस आने के बाद भी सेवा चलती रहती है. सेवा को stopSelf() को कॉल करके खुद को बंद करना चाहिए या कोई दूसरा कॉम्पोनेंट stopService() को कॉल करके उसे बंद कर सकता है.

stopSelf() या stopService() का इस्तेमाल करके, सेवा को बंद करने का अनुरोध करने के बाद, सिस्टम जल्द से जल्द सेवा को बंद कर देता है.

अगर आपकी सेवा, onStartCommand() के एक से ज़्यादा अनुरोधों को एक साथ मैनेज करती है, तो किसी अनुरोध को शुरू करने का अनुरोध पूरा होने के बाद, सेवा को बंद नहीं करना चाहिए. ऐसा इसलिए, क्योंकि आपको शुरू करने का एक नया अनुरोध मिल सकता है. पहले अनुरोध के खत्म होने पर सेवा बंद करने से, दूसरा अनुरोध भी बंद हो जाएगा. इस समस्या से बचने के लिए, stopSelf(int) का इस्तेमाल करें. इससे यह पक्का किया जा सकता है कि सेवा को बंद करने का अनुरोध, हमेशा शुरू करने के सबसे हाल के अनुरोध पर आधारित हो. इसका मतलब है कि stopSelf(int) को कॉल करते समय, आपको शुरू करने के अनुरोध (onStartCommand() को डिलीवर किया गया startId) का आईडी पास करना होगा, जो आपके रोकने के अनुरोध से जुड़ा है. इसके बाद, अगर stopSelf(int) को कॉल करने से पहले, सेवा को शुरू करने का नया अनुरोध मिलता है, तो आईडी मेल नहीं खाता और सेवा बंद नहीं होती.

चेतावनी: सिस्टम के संसाधनों को बर्बाद होने और बैटरी की खपत से बचने के लिए, पक्का करें कि आपका ऐप्लिकेशन काम पूरा होने के बाद अपनी सेवाएं बंद कर दे. ज़रूरत पड़ने पर, दूसरे कॉम्पोनेंट stopService() को कॉल करके सेवा को बंद कर सकते हैं. भले ही, आपने सेवा के लिए बाइंडिंग की सुविधा चालू की हो, फिर भी अगर उसे कभी onStartCommand() पर कॉल मिलता है, तो आपको खुद ही सेवा को बंद करना होगा.

किसी सेवा के लाइफ़साइकल के बारे में ज़्यादा जानने के लिए, किसी सेवा का लाइफ़साइकल मैनेज करना सेक्शन देखें.

बाउंड सेवा बनाना

बाउंड की गई सेवा, ऐप्लिकेशन के कॉम्पोनेंट को bindService() को कॉल करके, लंबे समय तक कनेक्ट रहने की अनुमति देती है. आम तौर पर, यह कॉम्पोनेंट को startService() को कॉल करके, इसे शुरू करने की अनुमति नहीं देता.

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

बाउंड सेवा बनाने के लिए, onBind() कॉलबैक का तरीका लागू करें, ताकि IBinder दिखाया जा सके. यह IBinder, सेवा के साथ इंटरफ़ेस के लिए तय किया जाता है. इसके बाद, ऐप्लिकेशन के अन्य कॉम्पोनेंट इंटरफ़ेस को वापस पाने और सेवा पर मेथड कॉल करने के लिए, bindService() को कॉल कर सकते हैं. यह सेवा सिर्फ़ उस ऐप्लिकेशन कॉम्पोनेंट को दिखाने के लिए बनाई जाती है जो उससे जुड़ा होता है. इसलिए, जब सेवा से कोई कॉम्पोनेंट नहीं जुड़ा होता, तो सिस्टम उसे मिटा देता है. onStartCommand() की मदद से सेवा शुरू करने पर, आपको उस सेवा को बंद करने के लिए, नहीं करना पड़ता.

बाउंड सेवा बनाने के लिए, आपको इंटरफ़ेस तय करना होगा. इससे यह तय होता है कि क्लाइंट, सेवा के साथ कैसे कम्यूनिकेट कर सकता है. सेवा और क्लाइंट के बीच यह इंटरफ़ेस, IBinder को लागू करने वाला होना चाहिए. साथ ही, आपकी सेवा को onBind() कॉलबैक तरीके से यही रिटर्न करना चाहिए. क्लाइंट को IBinder मिलने के बाद, वह उस इंटरफ़ेस के ज़रिए सेवा के साथ इंटरैक्ट करना शुरू कर सकता है.

एक से ज़्यादा क्लाइंट, एक साथ सेवा से बंधे रह सकते हैं. जब कोई क्लाइंट सेवा के साथ इंटरैक्ट करना बंद कर देता है, तो वह अनबाइंड करने के लिए unbindService() को कॉल करता है. जब सेवा से कोई क्लाइंट कनेक्ट नहीं होता है, तो सिस्टम उस सेवा को बंद कर देता है.

बाउंड सेवा को लागू करने के कई तरीके हैं. साथ ही, इसे शुरू की गई सेवा के मुकाबले लागू करना ज़्यादा मुश्किल होता है. इन वजहों से, बाउंड सेवा की चर्चा, बाउंड सेवाओं के बारे में अलग दस्तावेज़ में दिखती है.

उपयोगकर्ता को सूचनाएं भेजना

जब कोई सेवा चल रही होती है, तो वह स्नैकबार सूचनाओं या स्टेटस बार सूचनाओं का इस्तेमाल करके, उपयोगकर्ता को इवेंट की सूचना दे सकती है.

स्नैकबार सूचना एक ऐसा मैसेज होता है जो मौजूदा विंडो के ऊपर सिर्फ़ कुछ समय के लिए दिखता है. स्टेटस बार की सूचना में, स्टेटस बार में एक आइकॉन और मैसेज दिखता है. उपयोगकर्ता, कोई कार्रवाई करने के लिए इस आइकॉन को चुन सकता है. जैसे, कोई गतिविधि शुरू करना.

आम तौर पर, जब बैकग्राउंड में कोई काम पूरा हो जाता है, जैसे कि फ़ाइल डाउनलोड हो जाती है, तो स्टेटस बार पर सूचना दिखाना सबसे सही तरीका होता है. इससे उपयोगकर्ता, उस काम पर कार्रवाई कर सकता है. जब उपयोगकर्ता, बड़े किए गए व्यू से सूचना चुनता है, तो सूचना किसी गतिविधि को शुरू कर सकती है. जैसे, डाउनलोड की गई फ़ाइल दिखाना.

किसी सेवा की लाइफ़साइकल मैनेज करना

किसी सेवा का लाइफ़साइकल, किसी गतिविधि के लाइफ़साइकल से काफ़ी आसान होता है. हालांकि, यह ज़्यादा ज़रूरी है कि आप इस बात पर ध्यान दें कि आपकी सेवा कैसे बनाई और बंद की जाती है. ऐसा इसलिए, क्योंकि कोई सेवा, उपयोगकर्ता को बताए बिना बैकग्राउंड में चल सकती है.

सेवा के लाइफ़साइकल में, इसे बनाने से लेकर मिटाने तक के दौरान, इनमें से कोई एक पाथ अपनाया जा सकता है:

  • शुरू की गई सेवा

    जब कोई दूसरा कॉम्पोनेंट startService() को कॉल करता है, तब सेवा बनाई जाती है. इसके बाद, सेवा अनलिमिटेड तौर पर चलती है और stopSelf() को कॉल करके, अपने-आप बंद हो जाती है. कोई दूसरा कॉम्पोनेंट भी stopService() को कॉल करके, सेवा को रोक सकता है. सेवा बंद होने पर, सिस्टम उसे मिटा देता है.

  • बाउंड की गई सेवा

    जब कोई दूसरा कॉम्पोनेंट (क्लाइंट) bindService() को कॉल करता है, तब सेवा बनाई जाती है. इसके बाद, क्लाइंट IBinder इंटरफ़ेस की मदद से सेवा के साथ संपर्क करता है. क्लाइंट, unbindService() को कॉल करके कनेक्शन बंद कर सकता है. एक ही सेवा के लिए कई क्लाइंट बाइंड किए जा सकते हैं. जब सभी क्लाइंट अनबाइंड हो जाते हैं, तो सिस्टम उस सेवा को मिटा देता है. सेवा को अपने-आप बंद होने की ज़रूरत नहीं है.

ये दोनों पाथ पूरी तरह से अलग नहीं हैं. किसी ऐसी सेवा को भी बाइंड किया जा सकता है जो पहले से ही startService() के साथ शुरू हो चुकी है. उदाहरण के लिए, बैकग्राउंड में संगीत चलाने की सेवा शुरू करने के लिए, startService() के साथ Intent का इस्तेमाल करें. Intent से, चलाए जाने वाले संगीत की पहचान की जाती है. बाद में, जब उपयोगकर्ता प्लेयर पर कुछ कंट्रोल करना चाहता है या मौजूदा गाने के बारे में जानकारी पाना चाहता है, तो bindService() को कॉल करके, किसी गतिविधि को सेवा से जोड़ा जा सकता है. ऐसे मामलों में, stopService() या stopSelf() तब तक सेवा बंद नहीं करता, जब तक सभी क्लाइंट अनबाइंड नहीं हो जाते.

लाइफ़साइकल कॉलबैक लागू करना

किसी गतिविधि की तरह ही, सेवा के लाइफ़साइकल में कॉलबैक मैथड होते हैं. इनका इस्तेमाल करके, सेवा की स्थिति में होने वाले बदलावों पर नज़र रखी जा सकती है. साथ ही, सही समय पर काम किया जा सकता है. यहां दी गई स्केलेटन सेवा, लाइफ़साइकल के हर तरीके को दिखाती है:

Kotlin

class ExampleService : Service() {
    private var startMode: Int = 0             // indicates how to behave if the service is killed
    private var binder: IBinder? = null        // interface for clients that bind
    private var allowRebind: Boolean = false   // indicates whether onRebind should be used

    override fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return startMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return binder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return allowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Java

public class ExampleService extends Service {
    int startMode;       // indicates how to behave if the service is killed
    IBinder binder;      // interface for clients that bind
    boolean allowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return startMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return allowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

ध्यान दें: ऐक्टिविटी लाइफ़साइकल कॉलबैक मैथड के उलट, आपको इन कॉलबैक मैथड के सुपरक्लास को लागू करने के लिए, नहीं कॉल करने की ज़रूरत है.

दूसरी इमेज. सेवा का लाइफ़साइकल. बाईं ओर मौजूद डायग्राम में, startService() का इस्तेमाल करके सेवा बनाने पर उसका लाइफ़साइकल दिखाया गया है. वहीं, दाईं ओर मौजूद डायग्राम में, bindService() का इस्तेमाल करके सेवा बनाने पर उसका लाइफ़साइकल दिखाया गया है.

दूसरी इमेज में, किसी सेवा के लिए सामान्य कॉलबैक के तरीके दिखाए गए हैं. इस आंकड़े में, startService() की बनाई गई सेवाओं को bindService() की बनाई गई सेवाओं से अलग दिखाया गया है. हालांकि, ध्यान रखें कि किसी भी सेवा को शुरू करने का तरीका चाहे जो भी हो, क्लाइंट उससे कनेक्ट कर सकते हैं. किसी सेवा को शुरू में onStartCommand() से शुरू किया गया था (क्लाइंट ने startService() पर कॉल किया था). अब भी उस सेवा को onBind() पर कॉल मिल सकता है (जब क्लाइंट ने bindService() पर कॉल किया हो).

इन तरीकों को लागू करके, सेवा के लाइफ़साइकल के इन दो नेस्ट किए गए लूप पर नज़र रखी जा सकती है:

  • किसी सेवा का पूरा लाइफ़टाइम, onCreate() को कॉल करने और onDestroy() के रिटर्न होने के बीच होता है. किसी गतिविधि की तरह ही, सेवा का शुरुआती सेटअप onCreate() में होता है और बाकी सभी संसाधन onDestroy() में रिलीज़ किए जाते हैं. उदाहरण के लिए, संगीत चलाने की सेवा, onCreate() में संगीत चलाने के लिए थ्रेड बना सकती है और onDestroy() में थ्रेड को रोक सकती है.

    ध्यान दें: onCreate() और onDestroy() तरीके सभी सेवाओं के लिए इस्तेमाल किए जाते हैं. भले ही, उन्हें startService() या bindService() ने बनाया हो.

  • किसी सेवा का सक्रिय लाइफ़टाइम, onStartCommand() या onBind() को कॉल करने से शुरू होता है. हर तरीके को वह Intent दिया जाता है जो startService() या bindService() को पास किया गया था.

    अगर सेवा शुरू हो जाती है, तो पूरे लाइफ़टाइम के खत्म होने के साथ ही, चालू लाइफ़टाइम भी खत्म हो जाता है. हालांकि, onStartCommand() के वापस आने के बाद भी सेवा चालू रहती है. अगर सेवा को बांध दिया गया है, तो onUnbind() के वापस आने पर, चालू रहने की अवधि खत्म हो जाती है.

ध्यान दें: शुरू की गई सेवा को stopSelf() या stopService() पर कॉल करके बंद किया जा सकता है. हालांकि, सेवा के लिए कोई कॉलबैक नहीं है (onStop() कॉलबैक नहीं है). अगर सेवा किसी क्लाइंट से बंधी नहीं है, तो सेवा बंद होने पर सिस्टम उसे मिटा देता है—onDestroy() ही एक ऐसा कॉलबैक है जो मिलता है.

बाइंडिंग की सुविधा देने वाली सेवा बनाने के बारे में ज़्यादा जानने के लिए, बाइंड की गई सेवाएं दस्तावेज़ देखें. इसमें, बाइंड की गई सेवा के लाइफ़साइकल को मैनेज करने वाले सेक्शन में, onRebind() कॉलबैक के तरीके के बारे में ज़्यादा जानकारी दी गई है.