Sınır hizmetlerine genel bakış

Bağlı hizmet, istemci-sunucu arayüzündeki sunucudur. Etkinlikler gibi bileşenlerin hizmete bağlanmasını, istek göndermesini, yanıt almasını ve işlemler arası iletişim (IPC) gerçekleştirmesini sağlar. Bağlı bir hizmet genellikle yalnızca başka bir uygulama bileşenine hizmet verirken çalışır ve arka planda süresiz olarak çalışmaz.

Bu belgede, diğer uygulama bileşenlerinden hizmete nasıl bağlanılacağı da dahil olmak üzere bağlı bir hizmetin nasıl oluşturulacağı açıklanmaktadır. Bir hizmetten bildirim gönderme ve hizmetin ön planda çalışacak şekilde ayarlanması gibi genel olarak hizmetler hakkında daha fazla bilgi edinmek için Hizmetlere genel bakış sayfasını inceleyin.

Temel bilgiler

Bağlanmış hizmet, diğer uygulamaların buna bağlanıp etkileşimde bulunmasına olanak tanıyan Service sınıfının bir uygulamasıdır. Bir hizmet için bağlama sağlamak üzere onBind() geri çağırma yöntemini uygularsınız. Bu yöntem, istemcilerin hizmetle etkileşim kurmak için kullanabileceği programlama arayüzünü tanımlayan bir IBinder nesnesi döndürür.

Başlatılmış bir hizmete bağla

Hizmetlere genel bakış bölümünde belirtildiği gibi, hem başlamış hem de sınırlı olan bir hizmet oluşturabilirsiniz. Yani startService() yöntemini çağırarak bir hizmeti başlatabilir ve bu şekilde hizmetin süresiz olarak çalışmasını sağlayabilirsiniz. Ayrıca, bindService() yöntemini çağırarak bir istemcinin hizmete bağlanmasını sağlayabilirsiniz.

Hizmetinizin başlatılmasına ve bağlanmasına izin verirseniz hizmet başladığında tüm istemcilerin bağlantısını kaldırdığınızda sistem hizmeti kaldırmaz. Bunun yerine, stopSelf() veya stopService() yöntemini çağırarak hizmeti açıkça durdurmanız gerekir.

Genellikle onBind() veya onStartCommand() kodunu uygulasanız da bazen her ikisinin de uygulanması gerekir. Örneğin bir müzik çalar, hizmetinin süresiz olarak çalışmasını sağlamak ve ayrıca bağlama sağlamak için faydalı olabilir. Bu şekilde, bir etkinlik müzik çalmak için hizmeti başlatabilir ve kullanıcı uygulamadan ayrılsa bile müzik çalmaya devam eder. Ardından, kullanıcı uygulamaya döndüğünde etkinlik, oynatmanın kontrolünü tekrar kazanmak için hizmete bağlanabilir.

Başlatılmış bir hizmete bağlama eklerken hizmet yaşam döngüsü hakkında daha fazla bilgi edinmek için Bağlı bir hizmetin yaşam döngüsünü yönetme bölümüne bakın.

Bir istemci bindService() yöntemini çağırarak hizmete bağlanır. Bu olduğunda hizmetle olan bağlantıyı izleyen ServiceConnection uygulamasını sağlaması gerekir. bindService() değerinin döndürülen değeri, istenen hizmetin mevcut olup olmadığını ve istemcinin hizmete erişmesine izin verilip verilmediğini belirtir.

Android sistemi istemci ile hizmet arasında bağlantı oluşturduğunda ServiceConnection üzerinde onServiceConnected() çağrısı yapar. onServiceConnected() yöntemi, bir IBinder bağımsız değişkeni içerir. İstemci daha sonra bu bağımsız değişkeni bağlı hizmetle iletişim kurmak için kullanır.

Bir hizmete aynı anda birden fazla istemci bağlayabilirsiniz. Ancak sistem, IBinder hizmet iletişim kanalını önbelleğe alır. Diğer bir deyişle, sistem yalnızca ilk istemci bağlandığında IBinder oluşturmak için hizmetin onBind() yöntemini çağırır. Daha sonra sistem, onBind() tekrar çağırmadan aynı IBinder hizmeti aynı hizmete bağlanan tüm ek istemcilere gönderir.

Son istemci hizmet ile bağlantısını kestiğinde, hizmet startService() kullanılarak başlatılmadıysa sistem hizmeti kaldırır.

Bağlı hizmet uygulamanızın en önemli bölümü, onBind() geri çağırma yönteminizin döndürdüğü arayüzü tanımlamaktır. Aşağıdaki bölümde, hizmetinizin IBinder arayüzünü tanımlayabileceğiniz çeşitli yöntemler açıklanmaktadır.

Bağlı hizmet oluşturma

Bağlama sağlayan bir hizmet oluştururken, istemcilerin hizmetle etkileşim kurmak için kullanabileceği programlama arayüzünü sağlayan bir IBinder sağlamanız gerekir. Arayüzü üç şekilde tanımlayabilirsiniz:

Bağlayıcı sınıfını genişletme
Hizmetiniz kendi uygulamanıza özelse ve istemciyle aynı işlemi yapıyorsa (genellikle istemciyle aynı işlemi yapıyorsa) Binder sınıfını genişletip onBind() üzerinden bunun bir örneğini döndürerek arayüzünüzü oluşturun. İstemci Binder dosyasını alır ve Binder uygulamasında ya da Service uygulamasında kullanılabilen herkese açık yöntemlere doğrudan erişmek için bunu kullanabilir.

Hizmetiniz yalnızca uygulamanızın arka plan çalışanıysa tercih edilen teknik budur. Arayüz oluşturmak için tercih edilen yolun bu olmadığı tek durum, hizmetinizin başka uygulamalar tarafından veya ayrı işlemlerde kullanılmasıdır.

Messenger kullanma
Arayüzünüzü farklı işlemlerde çalışacak şekilde yapmanız gerekiyorsa Messenger ile hizmet için bir arayüz oluşturabilirsiniz. Bu şekilde hizmet, farklı Message nesne türlerine yanıt veren bir Handler tanımlar.

Bu Handler, daha sonra istemciyle bir IBinder paylaşabilen ve istemcinin Message nesnelerini kullanarak hizmete komut göndermesini sağlayan bir Messenger için temel oluşturur. Buna ek olarak, istemci kendi Messenger değerini de tanımlayabilir. Böylece hizmet mesajları geri gönderebilir.

İşlemler arası iletişimi (IPC) gerçekleştirmenin en basit yolu budur. Çünkü Messenger, tüm istekleri tek bir iş parçacığı halinde sıraya alır. Böylece hizmetinizi iş parçacığı için güvenli olacak şekilde tasarlamak zorunda kalmazsınız.

AIDL'yi kullanma
Android Arayüz Tanımlama Dili (AIDL), nesneleri işletim sisteminin anlayabileceği temel öğelere ayrıştırır ve IPC gerçekleştirmek için işlemler arasında sıralar. Messenger kullanan önceki teknik, temel yapısı olarak AIDL'ye dayanır.

Önceki bölümde belirtildiği gibi Messenger, tek bir iş parçacığındaki tüm istemci isteklerini içeren bir sıra oluşturur. Böylece hizmet, istekleri tek tek alır. Ancak hizmetinizin aynı anda birden fazla isteği işlemesini istiyorsanız doğrudan AIDL'yi kullanabilirsiniz. Bu durumda, hizmetiniz iş parçacığı için güvenli olmalı ve çoklu iş parçacığı yapabilmelidir.

AIDL'yi doğrudan kullanmak için programlama arayüzünü tanımlayan bir .aidl dosyası oluşturun. Android SDK araçları, arayüzü uygulayan ve IPC'yi işleyen soyut bir sınıf oluşturmak için bu dosyayı kullanır. Daha sonra bu sınıfı hizmetinizde genişletebilirsiniz.

Not: AIDL, çoklu iş parçacığı özellikleri gerektirebileceği ve daha karmaşık bir uygulamaya neden olabileceği için çoğu uygulamada bağlı bir hizmet oluşturmak için en iyi seçenek değildir. Bu nedenle bu belgede, hizmetin hizmetiniz için nasıl kullanılacağı ele alınmamaktadır. AIDL'yi doğrudan kullanmanız gerektiğinden eminseniz AIDL belgesine bakın.

Bağlayıcı sınıfını genişlet

Yalnızca yerel uygulama hizmetinizi kullanıyorsa ve işlemler genelinde çalışması gerekmiyorsa istemcinize hizmetteki herkese açık yöntemlere doğrudan erişim sağlayan kendi Binder sınıfınızı uygulayabilirsiniz.

Not: Bu işlem yalnızca istemci ile hizmet aynı uygulama ve işlemdeyse çalışır. Bu en yaygın durumdur. Örneğin bu, bir etkinliği arka planda müzik çalan kendi hizmetine bağlaması gereken bir müzik uygulaması için iyi sonuç verir.

Bunu nasıl kuracağınız aşağıda açıklanmıştır:

  1. Hizmetinizde aşağıdakilerden birini yapan bir Binder örneği oluşturun:
    • İstemcinin arayabileceği herkese açık yöntemleri içerir.
    • İstemcinin çağırabileceği herkese açık yöntemlere sahip mevcut Service örneğini döndürür.
    • İstemcinin çağırabileceği herkese açık yöntemlerle hizmet tarafından barındırılan başka bir sınıfın bir örneğini döndürür.
  2. Bu Binder örneğini onBind() geri çağırma yönteminden döndürün.
  3. İstemcide, onServiceConnected() geri çağırma yönteminden Binder kodunu alın ve sağlanan yöntemleri kullanarak bağlı hizmete çağrı yapın.

Not: İstemcinin döndürülen nesneyi yayınlayabilmesi ve API'lerini doğru şekilde çağırabilmesi için hizmet ile istemcinin aynı uygulamada olması gerekir. Bu teknik, işlemler arasında herhangi bir sıralama işlemi gerçekleştirmediğinden hizmet ve istemci de aynı süreçte olmalıdır.

Örneğin, istemcilerin Binder uygulaması aracılığıyla hizmetteki yöntemlere erişmesini sağlayan bir hizmeti aşağıda görebilirsiniz:

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, istemcilerin geçerli LocalService örneğini almaları için getService() yöntemini sağlar. Bu sayede istemciler hizmette genel yöntemleri çağırabilir. Örneğin, müşteriler hizmetten getRandomNumber() numarasını arayabilir.

Aşağıda, bir düğme tıklandığında LocalService öğesine bağlanan ve getRandomNumber() çağrısı yapan bir etkinlik verilmiştir:

Kotlin

class BindingActivity : Activity() {
    private lateinit var mService: LocalService
    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) {
            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)
        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
            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);
        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) {
            mBound = false;
        }
    };
}

Yukarıdaki örnekte, istemcinin ServiceConnection ve onServiceConnected() geri çağırmalarını kullanarak hizmete nasıl bağlandığı gösterilmektedir. Sonraki bölümde, hizmete bağlanma süreci hakkında daha fazla bilgi verilmektedir.

Not: Önceki örnekte verilen onStop() yöntemi, istemcinin hizmetten bağlantısını kaldırır. Ek notlar bölümünde açıklandığı gibi, uygun zamanlarda müşterilerin hizmetlerden bağlantısını kaldırın.

Daha fazla örnek kod için ApiDemos'daki LocalService.java ve LocalServiceActivities.java sınıfına bakın.

Messenger kullanma

Hizmetinizin uzak işlemlerle iletişim kurmak için kullanılması gerekiyorsa hizmetinizin arayüzünü sağlamak üzere bir Messenger kullanabilirsiniz. Bu teknik, AIDL kullanmanıza gerek kalmadan işlemler arası iletişim (IPC) gerçekleştirmenizi sağlar.

Messenger, hizmete yapılan tüm çağrıları sıraya aldığından, arayüzünüz için Messenger kullanmak AIDL kullanmaktan daha basittir. Sadece AIDL arayüzü, hizmete eşzamanlı istekler gönderir. Bu istekler daha sonra çoklu iş parçacıklarını işlemelidir.

Çoğu uygulamada hizmetin çoklu iş parçacığı işlemi gerçekleştirmesi gerekmez. Bu nedenle, Messenger kullanılması hizmetin tek seferde bir çağrıyı işlemesine olanak tanır. Hizmetinizin çok iş parçacıklı olması önemliyse arayüzünüzü tanımlamak için AIDL'yi kullanın.

Messenger etiketinin nasıl kullanılacağı aşağıda özetlenmiştir:

  1. Hizmet, bir istemciden gelen her arama için geri arama alan bir Handler uygular.
  2. Hizmet, Handler öğesini kullanarak bir Messenger nesnesi (Handler için referans) oluşturur.
  3. Messenger, hizmetin onBind() üzerinden istemcilere döndürdüğü bir IBinder oluşturur.
  4. İstemciler, istemcinin Message nesnelerini hizmete göndermek için kullandığı Messenger (hizmetin Handler öğesine referans veren) örneğini oluşturmak için IBinder öğesini kullanır.
  5. Hizmet, her Message değerini Handler içinde (özellikle handleMessage() yöntemiyle) alır.

Bu şekilde, istemcinin hizmeti çağıracağı yöntem yoktur. Bunun yerine istemci, hizmetin Handler içinde aldığı mesajları (Message nesne) teslim eder.

Messenger arayüzü kullanan basit bir örnek hizmeti aşağıda görebilirsiniz:

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 içindeki handleMessage() yöntemi, hizmetin gelen Message değerini aldığı ve what üyesine göre ne yapılacağına karar verdiği yerdir.

Bir istemcinin yapması gereken tek şey, hizmet tarafından döndürülen IBinder temelinde bir Messenger oluşturmak ve send() kullanarak bir ileti göndermektir. Örneğin, hizmete bağlanan ve MSG_SAY_HELLO mesajını hizmete ileten bir etkinliği burada görebilirsiniz:

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)
            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);
            bound = false;
        }
    }
}

Bu örnekte, hizmetin istemciye nasıl yanıt verebileceği gösterilmemektedir. Hizmetin yanıt vermesini istiyorsanız istemcide Messenger oluşturmanız da gerekir. İstemci onServiceConnected() geri çağırmasını aldığında, send() yönteminin replyTo parametresinde istemcinin Messenger değerini içeren hizmete bir Message gönderir.

İki yönlü mesajlaşmanın nasıl sağlanacağıyla ilgili bir örneği MessengerService.java (hizmet) ve MessengerServiceActivities.java (istemci) örneklerinde bulabilirsiniz.

Bir hizmete bağla

Uygulama bileşenleri (istemciler), bindService() yöntemini çağırarak bir hizmete bağlanabilir. Daha sonra Android sistemi, hizmetin onBind() yöntemini çağırır. Bu yöntem, hizmetle etkileşim kurmak için bir IBinder döndürür.

Bağlama eşzamansızdır ve bindService(), IBinder öğesini istemciye döndürmeden hemen döndürür. IBinder API'sini almak için istemcinin ServiceConnection örneği oluşturup bindService() hizmetine iletmesi gerekir. ServiceConnection, sistemin IBinder yayınlamak için çağırdığı bir geri çağırma yöntemi içerir.

Not: Bir hizmete yalnızca etkinlikler, hizmetler ve içerik sağlayıcılar bağlanabilir. Yayın alıcısından bir hizmete bağlantı bağlayamazsınız.

İstemcinizden bir hizmete bağlanmak için şu adımları uygulayın:

  1. ServiceConnection uygulamasını uygulayın.

    Uygulamanız, iki geri çağırma yöntemini geçersiz kılmalıdır:

    onServiceConnected()
    Sistem bunu çağırarak hizmetin onBind() yöntemi tarafından döndürülen IBinder değerini sağlar.
    onServiceDisconnected()
    Hizmetle bağlantı beklenmedik bir şekilde koptuğunda (örneğin, hizmet çöktüğünde veya sonlandırıldığında) Android sistemi bu işlevi çağırır. İstemci bağlantıyı kaldırdığınızda bu işlev çağrılmaz.
  2. ServiceConnection uygulamasını geçerek bindService() numaralı telefonu arayın.

    Not: Yöntem false değerini döndürürse istemcinizin hizmetle geçerli bir bağlantısı yoktur. Ancak istemcinizde unbindService() yöntemini çağırın. Aksi takdirde, istemciniz boşta kaldığında hizmetin kapanmasını engeller.

  3. Sistem, onServiceConnected() geri çağırma yönteminizi çağırdığında arayüzde tanımlanan yöntemleri kullanarak hizmete çağrı yapmaya başlayabilirsiniz.
  4. Hizmetin bağlantısını kesmek için unbindService() numaralı telefonu arayın.

    Uygulamanız istemciyi kaldırdığında istemciniz hâlâ bir hizmete bağlıysa istemcinin kaldırılması istemcinin bağlantısını kesmesine neden olur. Hizmetle etkileşim tamamlanır tamamlanmaz istemcinin bağlantısını kaldırmak daha iyi bir uygulamadır. Bu işlem, boşta kalma hizmetinin kapatılmasına neden olur. Bağlanma ve bağlantıyı kesme için uygun zamanlar hakkında daha fazla bilgi edinmek üzere Ek notlar bölümüne bakın.

Aşağıdaki örnek, istemciyi daha önce Bağlayıcı sınıfını genişleterek oluşturulan hizmete bağlar. Bu nedenle, tüm yapılması gereken döndürülen IBinder öğesini LocalBinder sınıfına yayınlayıp LocalService örneğini istemektir:

Kotlin

var mService: LocalService

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")
        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");
        mBound = false;
    }
};

Bu ServiceConnection ile istemci, aşağıdaki örnekte gösterildiği gibi bindService() ürününe ileterek bir hizmete bağlanabilir:

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);
  • İlk bindService() parametresi, bağlanacak hizmeti açık bir şekilde adlandıran bir Intent'dir.

    Dikkat: Service öğesine bağlamak için amaç kullanıyorsanız uygunsuz niyet kullanarak uygulamanızın güvenli olduğundan emin olun. Bir hizmeti başlatmak için dolaylı amaç kullanmak güvenlik açısından risk oluşturur. Çünkü hangi hizmetin amaca yanıt verdiğinden emin olamazsınız ve kullanıcı hangi hizmetin başladığını göremez. Android 5.0 (API düzeyi 21) sürümünden itibaren, dolaylı bir amaçla bindService() yöntemini çağırırsanız sistem bir istisna atar.

  • İkinci parametre ServiceConnection nesnesidir.
  • Üçüncü parametre, henüz yayında değilse hizmeti oluşturmak için bağlama seçeneklerini (genellikle BIND_AUTO_CREATE) gösteren bir işarettir. Diğer olası değerler BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND veya hiçbiri için 0 şeklindedir.

Ek notlar

Bir hizmete bağlama hakkında bazı önemli notları burada bulabilirsiniz:

  • Bağlantı kopduğunda atılan DeadObjectException istisnalarını her zaman yakala. Uzak yöntemler tarafından belirlenen tek istisna budur.
  • Nesneler işlemler genelinde sayılır.
  • Bağlama ve bağlantıyı kaldırma sürecini, genellikle aşağıdaki örneklerde açıklandığı gibi, istemcinin yaşam döngüsündeki eşleşme ve yıkım anlarında eşlersiniz:
    • Hizmetle yalnızca etkinliğiniz görünür durumdayken etkileşimde bulunmanız gerekiyorsa onStart() sırasında bağlamayı ve onStop() tarihinde bağlantıyı kaldırın.
    • Etkinliğinizin arka planda durdurulmuş olsa bile yanıt almasını istiyorsanız onCreate() sırasında bağlama ve onDestroy() sırasında bağlantıyı kesin. Bu durumda, arka planda bile, işlemlerinizin hizmeti tüm çalışma süresi boyunca kullanması gerektiği anlamına geldiğini unutmayın. Bu nedenle, hizmet başka bir işlemdeyken işlemin ağırlığını artırırsınız ve hizmetin sistem tarafından sonlandırılma olasılığı daha yüksek olur.

    Not: Etkinliğinizin onResume() ve onPause() geri çağırmaları sırasında genellikle bağlama ve bağlantıyı kaldırma yapmazsınız. Çünkü bu geri çağırmalar her yaşam döngüsü geçişinde gerçekleşir. Bu geçişlerde gerçekleşen işleme süresini minimumda tutun.

    Ayrıca, uygulamanızdaki birden fazla etkinlik aynı hizmete bağlanıyorsa ve bu etkinliklerden ikisi arasında geçiş olursa mevcut etkinlik, sonraki etkinlik bağlanmadan (devam ettirme sırasında) önce (duraklatma sırasında) hizmet yok edilip yeniden oluşturulabilir. Etkinliklerin yaşam döngülerini nasıl koordine ettiğini gösteren bu etkinlik geçişi, Etkinlik yaşam döngüsü bölümünde açıklanmıştır.

Bir hizmete nasıl bağlanacağınızı gösteren daha fazla örnek kod için ApiDemos'daki RemoteService.java sınıfına bakın.

Bağlı bir hizmetin yaşam döngüsünü yönetme

Bir hizmetin tüm istemcilerle bağlantısı kaldırıldığında Android sistemi hizmeti yok eder (startService() kullanılarak başlatılmadığı sürece). Bu nedenle, yalnızca bağlı bir hizmetse hizmetinizin yaşam döngüsünü yönetmeniz gerekmez. Android sistemi, herhangi bir istemciye bağlı olup olmadığına göre sizin için yönetir.

Ancak onStartCommand() geri çağırma yöntemini uygulamayı seçerseniz hizmet artık başlatıldı olarak kabul edildiğinden hizmeti açıkça durdurmanız gerekir. Bu durumda hizmet, herhangi bir istemciye bağlı olup olmadığına bakılmaksızın, stopSelf() veya başka bir bileşen stopService() ile kendisini durdurana kadar çalışır.

Ayrıca, hizmetiniz başlatılırsa ve bağlamayı kabul ederse sistem, onUnbind() yönteminizi çağırdığında, istemcinin hizmete bir sonraki bağlanışında onRebind() çağrısı almak isterseniz isteğe bağlı olarak true kodunu döndürebilirsiniz. onRebind(), void değerini döndürür ancak istemci, onServiceConnected() geri çağırmasında IBinder değerini yine de alır. Aşağıdaki şekilde, bu yaşam döngüsü türünün mantığı gösterilmiştir.

Şekil 1. Başlatılan ve aynı zamanda bağlamaya izin veren bir hizmetin yaşam döngüsü.

Başlatılan bir hizmetin yaşam döngüsü hakkında daha fazla bilgi edinmek için Hizmetlere genel bakış başlıklı makaleyi inceleyin.