सीमित सेवाओं के बारे में खास जानकारी

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

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

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

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

शुरू की गई किसी सेवा से बाइंड करना

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

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

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

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

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

जब Android सिस्टम, क्लाइंट और सेवा के बीच कनेक्शन बनाता है, तो वह ServiceConnection पर onServiceConnected() को कॉल करता है. onServiceConnected() वाले तरीके में IBinder आर्ग्युमेंट शामिल होता है. इसके बाद, क्लाइंट इसका इस्तेमाल सीमित सेवा से संपर्क करने के लिए करता है.

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

जब आखिरी क्लाइंट सेवा से अनबाइंड हो जाता है, तो सिस्टम सेवा को खत्म कर देता है. हालांकि, अगर सेवा को startService() का इस्तेमाल करके शुरू किया गया था, तो ऐसा नहीं होता.

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

बाउंड सर्विस बनाना

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

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

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

किसी मैसेंजर का इस्तेमाल करना
अगर आपको अपने इंटरफ़ेस को अलग-अलग प्रोसेस में इस्तेमाल करना है, तो Messenger की मदद से सेवा के लिए एक इंटरफ़ेस बनाया जा सकता है. इस तरह, सेवा एक Handler तय करती है, जो अलग-अलग तरह के Message ऑब्जेक्ट के लिए जवाब देती है.

यह Handler Messenger का आधार है. इसके बाद, यह क्लाइंट के साथ IBinder शेयर कर सकता है. इससे क्लाइंट, Message ऑब्जेक्ट का इस्तेमाल करके सेवा को निर्देश भेज सकता है. इसके अलावा, क्लाइंट अपना Messenger तय कर सकता है, ताकि सेवा मैसेज वापस भेज सके.

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

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

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

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

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

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

अगर सिर्फ़ लोकल ऐप्लिकेशन आपकी सेवा का इस्तेमाल करता है और उसे अलग-अलग प्रोसेस के लिए काम करने की ज़रूरत नहीं है, तो आपके पास अपनी Binder क्लास लागू करने का विकल्प होता है. इससे आपके क्लाइंट को सेवा में मौजूद सार्वजनिक तरीकों का सीधा ऐक्सेस मिलता है.

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

इसे सेट अप करने का तरीका यहां बताया गया है:

  1. अपनी सेवा में, Binder का एक इंस्टेंस बनाएं, जो इनमें से कोई एक काम करता हो:
    • इसमें ऐसे सार्वजनिक तरीके शामिल होते हैं जिन्हें क्लाइंट कॉल कर सकता है.
    • यह मौजूदा Service इंस्टेंस दिखाता है. इसमें ऐसे सार्वजनिक तरीके होते हैं जिन्हें क्लाइंट कॉल कर सकता है.
    • यह सेवा की ओर से होस्ट की गई किसी दूसरी क्लास का इंस्टेंस दिखाता है. इसमें ऐसे सार्वजनिक तरीके होते हैं जिन्हें क्लाइंट कॉल कर सकता है.
  2. onBind() कॉलबैक मेथड से Binder का यह इंस्टेंस दिखाएं.
  3. क्लाइंट में, onServiceConnected() कॉलबैक के तरीके से Binder पाएं और उपलब्ध कराए गए तरीकों का इस्तेमाल करके, सीमित सेवा को कॉल करें.

ध्यान दें: सेवा और क्लाइंट एक ही ऐप्लिकेशन में होने चाहिए, ताकि क्लाइंट, दिखाए गए ऑब्जेक्ट को कास्ट कर सके और उसके एपीआई को सही तरीके से कॉल कर सके. सेवा और क्लाइंट भी एक ही प्रोसेस में होने चाहिए, क्योंकि यह तकनीक प्रोसेस के दौरान कोई मार्शलिंग नहीं करती.

उदाहरण के लिए, यहां एक ऐसी सेवा दी गई है जो क्लाइंट को Binder लागू करने के तरीके से, सेवा में मौजूद तरीकों का ऐक्सेस देती है:

Kotlin

class LocalService : Service() {
    // Binder given to clients.
    private val binder = LocalBinder()

    // Random number generator.
    private val mGenerator = Random()

    /** Method for clients.  */
    val randomNumber: Int
        get() = mGenerator.nextInt(100)

    /**
     * Class used for the client Binder. Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    inner class LocalBinder : Binder() {
        // Return this instance of LocalService so clients can call public methods.
        fun getService(): LocalService = this@LocalService
    }

    override fun onBind(intent: Intent): IBinder {
        return binder
    }
}

Java

public class LocalService extends Service {
    // Binder given to clients.
    private final IBinder binder = new LocalBinder();
    // Random number generator.
    private final Random mGenerator = new Random();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods.
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    /** Method for clients. */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

LocalBinder, क्लाइंट को getService() तरीका उपलब्ध कराता है, ताकि वे LocalService का मौजूदा इंस्टेंस वापस पा सकें. इससे क्लाइंट, सेवा में मौजूद सार्वजनिक तरीकों को कॉल कर सकते हैं. उदाहरण के लिए, क्लाइंट इस सेवा से getRandomNumber() को कॉल कर सकते हैं.

यहां एक ऐसी गतिविधि दी गई है जो LocalService से बाइंड होती है और बटन पर क्लिक करने पर getRandomNumber() को कॉल करती है:

Kotlin

class BindingActivity : Activity() {
    private var mService: LocalService? = null
    private var mBound: Boolean = false

    /** Defines callbacks for service binding, passed to bindService().  */
    private val connection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            val binder = service as LocalService.LocalBinder
            mService = binder.getService()
            mBound = true
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            mService = null
            mBound = false
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to LocalService.
        Intent(this, LocalService::class.java).also { intent ->
            bindService(intent, connection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        unbindService(connection)
        // Release the reference so the service can be garbage-collected once it's
        // destroyed. onServiceDisconnected() isn't called when the client unbinds.
        mService = null
        mBound = false
    }

    /** Called when a button is clicked (the button in the layout file attaches to
     * this method with the android:onClick attribute).  */
    fun onButtonClick(v: View) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            val num: Int = mService?.randomNumber ?: return
            Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show()
        }
    }
}

Java

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService.
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
        // Release the reference so the service can be garbage-collected once it's
        // destroyed. onServiceDisconnected() isn't called when the client unbinds.
        mService = null;
        mBound = false;
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute). */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService(). */
    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mService = null;
            mBound = false;
        }
    };
}

ऊपर दिए गए सैंपल से पता चलता है कि क्लाइंट, ServiceConnection और onServiceConnected() कॉलबैक के लागू होने का इस्तेमाल करके, सेवा से कैसे जुड़ता है. अगले सेक्शन में, सेवा से बाइंड करने की इस प्रोसेस के बारे में ज़्यादा जानकारी दी गई है.

ध्यान दें: ऊपर दिए गए उदाहरण में, onStop() तरीका, क्लाइंट को सेवा से अनबाइंड करता है और क्लाइंट के रेफ़रंस को रिलीज़ करता है. क्लाइंट को सही समय पर सेवाओं से अनबाइंड करें, जैसा कि अतिरिक्त जानकारी सेक्शन में बताया गया है.

ज़्यादा सैंपल कोड के लिए, ApiDemos में LocalService.java क्लास और LocalServiceActivities.java क्लास देखें.

किसी मैसेंजर का इस्तेमाल करना

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

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

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

यहां Messenger इस्तेमाल करने के तरीके की खास जानकारी दी गई है:

  1. यह सेवा एक Handler लागू करती है, जो क्लाइंट से आने वाले हर कॉल के लिए कॉलबैक पाती है.
  2. यह सेवा, Handler का इस्तेमाल करके Messenger ऑब्जेक्ट बनाती है. यह ऑब्जेक्ट, Handler का रेफ़रंस होता है.
  3. Messenger एक IBinder बनाता है, जिसे सेवा onBind() से क्लाइंट को वापस भेजती है.
  4. क्लाइंट, IBinder का इस्तेमाल करके Messenger को इंस्टैंशिएट करते हैं. यह सेवा के Handler का रेफ़रंस देता है. क्लाइंट इसका इस्तेमाल करके, सेवा को Message ऑब्जेक्ट भेजते हैं.
  5. सेवा को हर Message, उसके Handler में मिलता है. खास तौर पर, handleMessage() तरीके में.

इस तरह, क्लाइंट के पास सेवा को कॉल करने के लिए कोई तरीका नहीं होता. इसके बजाय, क्लाइंट मैसेज (Message ऑब्जेक्ट) डिलीवर करता है. ये मैसेज, सेवा को उसके Handler में मिलते हैं.

यहां एक ऐसी सेवा का उदाहरण दिया गया है जो Messenger इंटरफ़ेस का इस्तेमाल करती है:

Kotlin

/** Command to the service to display a message.  */
private const val MSG_SAY_HELLO = 1

class MessengerService : Service() {

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    private lateinit var mMessenger: Messenger

    /**
     * Handler of incoming messages from clients.
     */
    internal class IncomingHandler(
            context: Context,
            private val applicationContext: Context = context.applicationContext
    ) : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_SAY_HELLO ->
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show()
                else -> super.handleMessage(msg)
            }
        }
    }

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    override fun onBind(intent: Intent): IBinder? {
        Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show()
        mMessenger = Messenger(IncomingHandler(this))
        return mMessenger.binder
    }
}

Java

public class MessengerService extends Service {
    /**
     * Command to the service to display a message.
     */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    static class IncomingHandler extends Handler {
        private Context applicationContext;

        IncomingHandler(Context context) {
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    Messenger mMessenger;

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        mMessenger = new Messenger(new IncomingHandler(this));
        return mMessenger.getBinder();
    }
}

Handler में handleMessage() तरीका वह जगह है जहां सेवा को आने वाला Message मिलता है. साथ ही, what सदस्य के आधार पर यह तय किया जाता है कि क्या करना है.

क्लाइंट को सिर्फ़ सेवा से मिले IBinder के आधार पर Messenger बनाना होगा और send() का इस्तेमाल करके मैसेज भेजना होगा. उदाहरण के लिए, यहां एक ऐसी गतिविधि दी गई है जो सेवा से जुड़ती है और सेवा को MSG_SAY_HELLO मैसेज डिलीवर करती है:

Kotlin

class ActivityMessenger : Activity() {
    /** Messenger for communicating with the service.  */
    private var mService: Messenger? = null

    /** Flag indicating whether we have called bind on the service.  */
    private var bound: Boolean = false

    /**
     * Class for interacting with the main interface of the service.
     */
    private val mConnection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = Messenger(service)
            bound = true
        }

        override fun onServiceDisconnected(className: ComponentName) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null
            bound = false
        }
    }

    fun sayHello(v: View) {
        if (!bound) return
        // Create and send a message to the service, using a supported 'what' value.
        val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0)
        try {
            mService?.send(msg)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to the service.
        Intent(this, MessengerService::class.java).also { intent ->
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection)
            mService = null
            bound = false
        }
    }
}

Java

public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean bound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            bound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null;
            bound = false;
        }
    };

    public void sayHello(View v) {
        if (!bound) return;
        // Create and send a message to the service, using a supported 'what' value.
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service.
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection);
            mService = null;
            bound = false;
        }
    }
}

इस उदाहरण में यह नहीं दिखाया गया है कि सेवा, क्लाइंट को कैसे जवाब दे सकती है. अगर आपको सेवा से जवाब चाहिए, तो आपको क्लाइंट में Messenger भी बनाना होगा. जब क्लाइंट को onServiceConnected() कॉलबैक मिलता है, तो वह सेवा को Message भेजता है. इसमें send() तरीके के replyTo पैरामीटर में क्लाइंट का Messenger शामिल होता है.

MessengerService.java (सेवा) और MessengerServiceActivities.java (क्लाइंट) सैंपल में, दोनों तरफ़ से मैसेज भेजने की सुविधा देने का उदाहरण देखा जा सकता है.

किसी सेवा से बाइंड करना

ऐप्लिकेशन के कॉम्पोनेंट (क्लाइंट), bindService() को कॉल करके किसी सेवा से जुड़ सकते हैं. इसके बाद, Android सिस्टम, सेवा के onBind() तरीके को कॉल करता है. इससे सेवा के साथ इंटरैक्ट करने के लिए, IBinder मिलता है.

बाइंडिंग एसिंक्रोनस है और bindService() क्लाइंट को IBinder दिखाए बिना तुरंत वापस आ जाता है. IBinder पाने के लिए, क्लाइंट को ServiceConnection का एक इंस्टेंस बनाना होगा और उसे bindService() को पास करना होगा. ServiceConnection में कॉलबैक का एक तरीका शामिल होता है. सिस्टम, IBinder को डिलीवर करने के लिए इस तरीके को कॉल करता है.

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

अपने क्लाइंट से किसी सेवा को बाइंड करने के लिए, यह तरीका अपनाएं:

  1. ServiceConnection लागू करें.

    आपके इंप्लिमेंटेशन को कॉलबैक के दो तरीकों को ओवरराइड करना होगा:

    onServiceConnected()
    सिस्टम इसे कॉल करता है, ताकि सेवा के onBind() तरीके से मिले IBinder को डिलीवर किया जा सके.
    onServiceDisconnected()
    Android सिस्टम इसे तब कॉल करता है, जब सेवा से कनेक्शन अचानक टूट जाता है. जैसे, जब सेवा क्रैश हो जाती है या बंद हो जाती है. जब क्लाइंट अनबाइंड होता है, तब इसे कॉल नहीं किया जाता.
  2. bindService() को कॉल करें और ServiceConnection को लागू करें.

    ध्यान दें: अगर इस तरीके से 'गलत' वैल्यू मिलती है, तो इसका मतलब है कि आपके क्लाइंट के पास सेवा का मान्य कनेक्शन नहीं है. हालांकि, अपने क्लाइंट में unbindService() को कॉल करें. ऐसा न करने पर, आपका क्लाइंट सेवा को बंद होने से रोकता है, भले ही वह इस्तेमाल में न हो.

  3. जब सिस्टम आपके onServiceConnected() कॉलबैक के तरीके को कॉल करता है, तो इंटरफ़ेस में बताए गए तरीकों का इस्तेमाल करके, सेवा को कॉल किया जा सकता है.
  4. सेवा से डिसकनेक्ट करने के लिए, unbindService() पर कॉल करें.

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

यहां दिए गए उदाहरण में, क्लाइंट को पहले से बनाई गई सेवा से कनेक्ट किया गया है. इसके लिए, Binder क्लास को एक्सटेंड किया गया है. इसलिए, इसे सिर्फ़ वापस किए गए IBinder को LocalBinder क्लास में कास्ट करना होगा और LocalService इंस्टेंस का अनुरोध करना होगा:

Kotlin

var mService: LocalService? = null

val mConnection = object : ServiceConnection {
    // Called when the connection with the service is established.
    override fun onServiceConnected(className: ComponentName, service: IBinder) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        val binder = service as LocalService.LocalBinder
        mService = binder.getService()
        mBound = true
    }

    // Called when the connection with the service disconnects unexpectedly.
    override fun onServiceDisconnected(className: ComponentName) {
        Log.e(TAG, "onServiceDisconnected")
        mService = null
        mBound = false
    }
}

Java

LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established.
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    // Called when the connection with the service disconnects unexpectedly.
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mService = null;
        mBound = false;
    }
};

इस ServiceConnection की मदद से, क्लाइंट किसी सेवा से जुड़ सकता है. इसके लिए, उसे bindService() को पास करना होगा. इसका उदाहरण यहां दिया गया है:

Kotlin

Intent(this, LocalService::class.java).also { intent ->
    bindService(intent, connection, Context.BIND_AUTO_CREATE)
}

Java

Intent intent = new Intent(this, LocalService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
  • bindService() का पहला पैरामीटर एक Intent है, जो साफ़ तौर पर उस सेवा का नाम बताता है जिसे बाइंड करना है.

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

  • दूसरा पैरामीटर, ServiceConnection ऑब्जेक्ट है.
  • तीसरा पैरामीटर एक फ़्लैग है, जो बाइंडिंग के विकल्प दिखाता है. आम तौर पर, यह BIND_AUTO_CREATE होता है, ताकि सेवा को चालू किया जा सके. ऐसा तब होता है, जब सेवा पहले से चालू न हो. अन्य संभावित वैल्यू BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND या 0 हैं.

अतिरिक्त जानकारी

किसी सेवा से बाइंड करने के बारे में कुछ ज़रूरी बातें यहां दी गई हैं:

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

    ध्यान दें: आम तौर पर, अपनी गतिविधि के onResume() और onPause() कॉलबैक के दौरान, बाइंड और अनबाइंड नहीं किया जाता. ऐसा इसलिए, क्योंकि ये कॉलबैक हर लाइफ़साइकल ट्रांज़िशन पर होते हैं. इन ट्रांज़िशन के दौरान होने वाली प्रोसेसिंग को कम से कम रखें.

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

किसी सेवा से बाइंड करने का तरीका बताने वाले ज़्यादा सैंपल कोड देखने के लिए, ApiDemos में RemoteService.java क्लास देखें.

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

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

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

इसके अलावा, अगर आपकी सेवा शुरू हो गई है और बाइंडिंग स्वीकार करती है, तो जब सिस्टम आपके onUnbind() तरीके को कॉल करता है, तो आपके पास true को वापस करने का विकल्प होता है. ऐसा तब किया जा सकता है, जब आपको अगली बार क्लाइंट के सेवा से बाइंड होने पर, onRebind() को कॉल करना हो. onRebind(), void दिखाता है. हालांकि, क्लाइंट को अब भी अपने onServiceConnected() कॉलबैक में IBinder मिलता है. इस इमेज में, इस तरह की लाइफ़साइकल के लॉजिक के बारे में बताया गया है.

शुरू की गई और सीमित सेवा की लाइफ़साइकल: onStartCommand() और onBind() को कॉल किया जाता है; जब सभी क्लाइंट अनबाइंड हो जाते हैं, तो onUnbind() को कॉल किया जाता है; अगले बाइंड पर, onRebind() को कॉल किया जाता है, अगर onUnbind() ने true दिखाया है, तो onBind() को कॉल किया जाता है; सेवा बंद होने के बाद, onDestroy() को कॉल किया जाता है.
पहली इमेज. शुरू की गई सेवा की लाइफ़साइकल, जो बाइंडिंग की अनुमति भी देती है.

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