Bağlama hizmeti, istemci-sunucu arayüzündeki sunucudur. Etkinlikler gibi bileşenlerin hizmete bağlanmasına, istek göndermesine, yanıt almasına ve işlemler arası iletişim (IPC) gerçekleştirmesine olanak tanır. Bağlama hizmeti genellikle yalnızca başka bir uygulama bileşenine hizmet verirken etkin olur 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ı hizmet oluşturma işlemi açıklanmaktadır. Genel olarak hizmetler hakkında daha fazla bilgi edinmek için (ör. bir hizmetten bildirim gönderme ve hizmeti ön planda çalışacak şekilde ayarlama) Hizmetlere genel bakış başlıklı makaleyi inceleyin.
Temel özellikler
Bağlama hizmeti, diğer uygulamaların bağlanmasına ve etkileşim kurması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 uygulamanız gerekir. 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ılan bir hizmete bağlanma
Hizmetlere genel bakış bölümünde açıklandığı gibi, hem başlatılan hem de bağlı bir hizmet oluşturabilirsiniz. Yani startService() yöntemini çağırarak bir hizmet başlatabilirsiniz. Bu yöntem, hizmetin süresiz olarak çalışmasına olanak tanır. Ayrıca, bindService() yöntemini çağırarak bir istemcinin hizmete bağlanmasına izin verebilirsiniz.
Hizmetinizin başlatılmasına ve bağlanmasına izin verirseniz hizmet başladığında sistem, tüm istemciler bağlantıyı kaldırdığında hizmeti yok etmez.
Bunun yerine, stopSelf() veya stopService() yöntemini çağırarak hizmeti açıkça durdurmanız gerekir.
Genellikle onBind()
veya onStartCommand() yöntemlerinden birini uygulasanız da bazen her ikisini de uygulamanız gerekebilir. Örneğin, bir müzik çalar, hizmetinin süresiz olarak çalışmasına izin vermeyi ve bağlama sağlamayı yararlı bulabilir. Bu sayede 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, oynatma kontrolünü yeniden kazanmak için hizmete bağlanabilir.
Başlatılan bir hizmete bağlama eklerken hizmet yaşam döngüsü hakkında daha fazla bilgi için Bağlı hizmetin yaşam döngüsünü yönetme bölümüne bakın.
İstemci, bindService() yöntemini çağırarak bir hizmete bağlanır. Bu durumda, hizmetle bağlantıyı izleyen
ServiceConnection uygulamasını sağlaması gerekir. bindService() işlevinin döndürdüğü değer, istenen hizmetin mevcut olup olmadığını ve istemcinin bu hizmete erişim izni olup olmadığını gösterir.
Android sistemi, istemci ile hizmet arasında bağlantı oluşturduğunda ServiceConnection üzerinde onServiceConnected() yöntemini çağırır. onServiceConnected() yöntemi, istemcinin bağlı hizmetle iletişim kurmak için kullandığı bir IBinder bağımsız değişkeni içerir.
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. Sistem daha sonra aynı IBinder öğesini, onBind() yöntemini tekrar çağırmadan aynı hizmete bağlanan tüm ek istemcilere gönderir.
Son istemci hizmetle olan bağını kopardığında, hizmet startService() kullanılarak başlatılmadığı sürece sistem hizmeti yok eder.
Bağlama hizmeti uygulamanızın en önemli kısmı, 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 ele alınmaktadır.
Bağlama hizmeti 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:
- Binder sınıfını genişletme
- Hizmetiniz kendi uygulamanıza özelse ve istemciyle aynı işlemde çalışıyorsa (bu yaygın bir durumdur)
Bindersınıfını genişleterek veonBind()yönteminden bu sınıfın bir örneğini döndürerek arayüzünüzü oluşturun. İstemci,Binderdeğerini alır ve bu değeri kullanarakBinderuygulamasında veyaServiceiçinde bulunan herkese açık yöntemlere doğrudan erişebilir.Hizmetiniz yalnızca kendi uygulamanız için bir arka plan çalışanıysa bu teknik tercih edilir. Arayüzünüzü oluşturmak için bu yöntemin tercih edilmediği tek kullanım alanı, hizmetinizin diğer uygulamalar tarafından veya ayrı işlemler arasında kullanılmasıdır.
- Messenger kullanma
- Arayüzünüzün farklı işlemler arasında çalışması gerekiyorsa
Messengerile hizmet için bir arayüz oluşturabilirsiniz. Bu şekilde hizmet, farklı türdekiMessagenesnelerine yanıt veren birHandlertanımlar.Bu
Handler, istemciyleIBinderpaylaşabilen birMessengeriçin temel oluşturur. Böylece istemci,Messagenesnelerini kullanarak hizmete komut gönderebilir. Ayrıca istemci, hizmetin mesajları geri gönderebilmesi için kendiMessengerdeğerini tanımlayabilir.Bu, işlemler arası iletişim (IPC) gerçekleştirmenin en basit yoludur.
Messenger, tüm istekleri tek bir iş parçacığında sıraya koyduğundan hizmetinizi iş parçacığı açısından güvenli olacak şekilde tasarlamanız gerekmez. - AIDL kullanma
- Android Arayüz Tanımlama Dili (AIDL), nesneleri işletim sisteminin anlayabileceği temel öğelere ayırır ve IPC gerçekleştirmek için bunları işlemler arasında sıralar.
Messengerkullanan önceki teknik, temel yapısı olarak AIDL'yi kullanır.Önceki bölümde belirtildiği gibi,
Messengertüm istemci isteklerini tek bir iş parçacığında sıraya koyar. Böylece hizmet, istekleri tek tek alır. Ancak hizmetinizin aynı anda birden fazla isteği işlemesini istiyorsanız AIDL'yi doğrudan kullanabilirsiniz. Bu durumda, hizmetiniz iş parçacığı açısından güvenli ve çoklu iş parçacığı oluşturma özelliğine sahip olmalıdır.AIDL'yi doğrudan kullanmak için programlama arayüzünü tanımlayan bir
.aidldosyası 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. Bu sınıfı daha sonra hizmetinizde genişletebilirsiniz.
Not: Çoğu uygulamada, çoklu iş parçacığı özellikleri gerektirebileceği ve daha karmaşık bir uygulamaya neden olabileceği için AIDL, bağlı hizmet oluşturmak için en iyi seçenek değildir. Bu nedenle, bu belgede, hizmetiniz için nasıl kullanılacağı ele alınmamaktadır. AIDL'yi doğrudan kullanmanız gerektiğinden eminseniz AIDL belgesini inceleyin.
Binder sınıfını genişletme
Hizmetinizi yalnızca yerel uygulama kullanıyorsa ve hizmetin işlemler arasında çalışması gerekmiyorsa istemcinizin hizmetteki herkese açık yöntemlere doğrudan erişmesini sağlayan kendi Binder sınıfınızı uygulayabilirsiniz.
Not: Bu yöntem yalnızca istemci ve hizmet aynı uygulama ve işlemde olduğunda çalışır. Bu, en yaygın durumdur. Örneğin, bir etkinliği arka planda müzik çalan kendi hizmetine bağlaması gereken bir müzik uygulaması için bu yöntem idealdir.
Bunu nasıl kuracağınız aşağıda açıklanmıştır:
- Hizmetinizde, aşağıdakilerden birini yapan bir
Binderörneği oluşturun:- İstemcinin çağırabileceği herkese açık yöntemleri içerir.
- İstemcinin çağırabileceği herkese açık yöntemleri olan mevcut
Serviceörneğini döndürür. - Hizmet tarafından barındırılan başka bir sınıfın örneğini, istemcinin çağırabileceği herkese açık yöntemlerle döndürür.
onBind()geri çağırma yönteminden buBinderörneğini döndürün.- İstemcide,
onServiceConnected()geri çağırma yöntemindenBinderdeğerini alın ve sağlanan yöntemleri kullanarak bağlama hizmetine çağrı yapın.
Not: İstemcinin, döndürülen nesneyi yayınlayabilmesi ve API'lerini doğru şekilde çağırabilmesi için hizmet ve istemci aynı uygulamada olmalıdır. Bu teknik, işlemler arasında sıralama yapmadığından hizmet ve istemci de aynı işlemde olmalıdır.
Örneğin, aşağıdaki hizmet, müşterilere Binder uygulaması aracılığıyla hizmetteki yöntemlere erişim sağlar:
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 alması için getService() yöntemini sağlar. Bu sayede istemciler, hizmetteki herkese açık yöntemleri çağırabilir. Örneğin, istemciler hizmetten getRandomNumber() yöntemini çağırabilir.
Aşağıda, bir düğme tıklandığında LocalService hizmetine bağlanan ve getRandomNumber() yöntemini çağıran bir etkinlik örneği verilmiştir:
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; } }; }
Yukarıdaki örnekte, istemcinin ServiceConnection ve onServiceConnected() geri çağırma işlevinin bir uygulamasını kullanarak hizmete nasıl bağlandığı gösterilmektedir. Bir sonraki bölümde, hizmete bağlanma süreci hakkında daha fazla bilgi verilmektedir.
Not: Önceki örnekte onStop() yöntemi, istemcinin hizmetle olan bağını kaldırır ve istemcinin hizmete olan referansını serbest bırakır.
Ek notlar bölümünde açıklandığı gibi, istemcilerin hizmetlerle olan bağını uygun zamanlarda kaldırın.
Daha fazla örnek kod için ApiDemos'taki
LocalService.java sınıfına ve
LocalServiceActivities.java sınıfına bakın.
Kurye kullanma
Hizmetinizin uzak işlemlerle iletişim kurması gerekiyorsa hizmetiniz için arayüz sağlamak üzere Messenger kullanabilirsiniz. Bu teknik, AIDL kullanmanıza gerek kalmadan işlemler arası iletişim (IPC) gerçekleştirmenize olanak tanır.
Arayüzünüz için Messenger kullanmak, AIDL kullanmaktan daha basittir çünkü Messenger, hizmete yapılan tüm çağrıları sıraya alır. Saf bir AIDL arayüzü, hizmete eşzamanlı istekler gönderir. Hizmetin daha sonra çoklu iş parçacığı işlemesi gerekir.
Çoğu uygulamada hizmetin çoklu iş parçacığı oluşturması gerekmez. Bu nedenle, Messenger kullanıldığında hizmet her seferinde bir çağrıyı işler. Hizmetinizin çok iş parçacıklı olması önemliyse arayüzünüzü tanımlamak için AIDL kullanın.
Messenger kullanma hakkında bir özet:
- Hizmet, istemciden gelen her çağrı için geri çağırma alan bir
Handleruygular. - Hizmet,
Handlerkullanarak birMessengernesnesi (Handlerreferansı) oluşturur. Messenger, hizmetinonBind()üzerinden istemcilere döndürdüğü birIBinderoluşturur.- İstemciler,
Messengerörneklendirmek içinIBinderkullanır (hizmetinHandlerreferans verir). İstemci, hizmeteMessagenesneleri göndermek için bunu kullanır. - Hizmet, her
MessageöğesiniHandleriçinde, özellikle dehandleMessage()yönteminde alır.
Bu şekilde, istemcinin hizmeti çağırması için yöntem yoktur. Bunun yerine istemci, hizmetin Handler içinde aldığı mesajları (Message nesneleri) teslim eder.
Messenger arayüzünü kullanan örnek bir hizmeti aşağıda bulabilirsiniz:
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 öğesini aldığı ve what üyesine göre ne yapacağına karar verdiği yerdir.
İstemcinin tek yapması gereken, hizmet tarafından döndürülen IBinder değerine göre bir Messenger oluşturmak ve send() kullanarak mesaj göndermektir. Örneğin, hizmete bağlanan ve hizmete MSG_SAY_HELLO mesajını gönderen bir etkinlik aşağıda verilmiştir:
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; } } }
Bu örnekte, hizmetin istemciye nasıl yanıt verebileceği gösterilmemektedir.
Hizmetin yanıt vermesini istiyorsanız istemcide bir Messenger de oluşturmanız gerekir.
İstemci, onServiceConnected() geri çağırmasını aldığında hizmete bir Message gönderir. Bu istek, send() yönteminin replyTo parametresinde istemcinin Messenger değerini içerir.
İki yönlü mesajlaşmanın nasıl sağlanacağına dair bir örneği
MessengerService.java (hizmet) ve
MessengerServiceActivities.java (istemci) örneklerinde görebilirsiniz.
Bir hizmete bağlanma
Uygulama bileşenleri (istemciler), bindService() yöntemini çağırarak bir hizmete bağlanabilir. Ardından 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 işlemi eşzamansızdır ve bindService(), IBinder değerini istemciye döndürmeden hemen döndürür. IBinder almak için istemcinin bir ServiceConnection örneği oluşturması ve bunu bindService() öğesine iletmesi gerekir. ServiceConnection, sistemin IBinder değerini iletmek 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ıdan bir hizmete bağlanamazsınız.
İstemcinizden bir hizmete bağlanmak için aşağıdaki adımları uygulayın:
ServiceConnectionuygulayın.Uygulamanızın iki geri çağırma yöntemini geçersiz kılması gerekir:
onServiceConnected()- Sistem, hizmetin
onBind()yöntemi tarafından döndürülenIBinderdeğerini iletmek için bu yöntemi çağırır. onServiceDisconnected()- Android sistemi, hizmetle bağlantı beklenmedik bir şekilde kesildiğinde (ör. hizmet kilitlendiğinde veya sonlandırıldığında) bu yöntemi çağırır. İstemci bağlantıyı kaldırdığında bu yöntem çağrılmaz.
ServiceConnectionuygulamasını ileterekbindService()yöntemini çağırın.Not: Yöntem false değerini döndürürse istemcinizin hizmetle geçerli bir bağlantısı yoktur. An ancak istemcinizde
unbindService()yöntemini çağırın. Aksi takdirde istemciniz, hizmetin boştayken kapanmasını engeller.- Sistem,
onServiceConnected()geri çağırma yönteminizi çağırdığında arayüz tarafından tanımlanan yöntemleri kullanarak hizmete çağrı yapmaya başlayabilirsiniz. - Hizmetle bağlantıyı kesmek için
unbindService()numaralı telefonu arayın.Uygulamanız istemciyi yok ettiğinde istemci hâlâ bir hizmete bağlıysa yok etme işlemi istemcinin bağlantısının kaldırılmasına neden olur. İstemcinin hizmetle etkileşimi biter bitmez bağlantısını kaldırmak daha iyi bir uygulamadır. Böylece boşta olan hizmet kapatılır. Bağlama ve bağlantıyı kaldırma için uygun zamanlar hakkında daha fazla bilgi edinmek istiyorsanız Ek notlar bölümünü inceleyin.
Aşağıdaki örnekte, istemci daha önce Binder sınıfı genişletilerek oluşturulan hizmete bağlanır. Bu nedenle, döndürülen IBinder değerini LocalBinder sınıfına dönüştürmesi ve LocalService örneğini istemesi yeterlidir:
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; } };
Bu ServiceConnection ile istemci, aşağıdaki örnekte gösterildiği gibi bindService() öğesine 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);
bindService()işlevinin ilk parametresi, bağlanacak hizmeti açıkça adlandıran birIntentnesnesidir.Dikkat: Bir
Serviceöğesine bağlanmak için intent kullanıyorsanız açık intent kullanarak uygulamanızın güvenli olduğundan emin olun. Bir hizmeti başlatmak için örtük intent kullanmak güvenlik açısından tehlikelidir. Çünkü intent'e hangi hizmetin yanıt verdiğinden emin olamazsınız ve kullanıcı hangi hizmetin başladığını göremez. Android 5.0'dan (API düzeyi 21) itibaren sistem, örtük bir intent ilebindService()çağrısı yaparsanız istisna oluşturur.- İkinci parametre
ServiceConnectionnesnesidir. - Üçüncü parametre, bağlama seçeneklerini gösteren bir işarettir. Bu işaret, genellikle hizmet henüz etkin değilse hizmeti oluşturmak için
BIND_AUTO_CREATEolur. Diğer olası değerlerBIND_DEBUG_UNBIND,BIND_NOT_FOREGROUNDveya hiçbiri için0'dir.
Ek notlar
Bir hizmete bağlanmayla ilgili bazı önemli noktalar şunlardır:
- Bağlantı kesildiğinde ortaya çıkan
DeadObjectExceptionistisnalarını her zaman yakalayın. Bu, uzak yöntemler tarafından oluşturulan tek istisnadır. - Nesneler, işlemler arasında referans sayılır.
- Bağlama ve bağlamayı kaldırma işlemlerini genellikle istemcinin yaşam döngüsünün eşleşen başlatma ve kaldırma anlarında eşlersiniz. Bu durum aşağıdaki örneklerde açıklanmıştır:
- Hizmetle yalnızca etkinliğiniz görünür durumdayken etkileşim kurmanız gerekiyorsa
onStart()sırasında bağlayın veonStop()sırasında bağlantıyı kaldırın. - Etkinliğinizin arka planda durdurulmuşken bile yanıt almasını istiyorsanız
onCreate()sırasında bağlayın veonDestroy()sırasında bağlantıyı kaldırın. Bu durum, etkinliğinizin çalıştığı süre boyunca (arka planda bile) hizmeti kullanması gerektiği anlamına gelir. Dolayısıyla, hizmet başka bir işlemdeyken işlemin ağırlığını artırırsınız ve sistem tarafından sonlandırılma olasılığı daha yüksek olur.
Not: Bu geri çağırmalar her yaşam döngüsü geçişinde gerçekleştiğinden, etkinliğinizin
onResume()veonPause()geri çağırmaları sırasında genellikle bağlama ve bağlamayı kaldırma işlemleri yapılmaz. Bu geçişlerde gerçekleşen işlemleri minimumda tutun.Ayrıca, uygulamanızdaki birden fazla etkinlik aynı hizmete bağlanırsa ve bu etkinliklerden ikisi arasında geçiş olursa mevcut etkinlik bağlantıyı kaldırdığında (duraklatma sırasında) hizmet yok edilip yeniden oluşturulabilir ve bir sonraki etkinlik bağlanır (devam ettirme sırasında). Etkinliklerin yaşam döngülerini nasıl koordine ettiğine dair bu etkinlik geçişi, Etkinlik yaşam döngüsü bölümünde açıklanmıştır.
- Hizmetle yalnızca etkinliğiniz görünür durumdayken etkileşim kurmanız gerekiyorsa
Bir hizmete nasıl bağlanılacağını gösteren daha fazla örnek kod için ApiDemos'taki
RemoteService.java sınıfına bakın.
Bağlama hizmetinin yaşam döngüsünü yönetme
Bir hizmetin tüm istemcilerle olan bağı kaldırıldığında Android sistemi bu hizmeti yok eder (startService() kullanılarak başlatılmadığı sürece). Bu nedenle, tamamen 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 hizmeti 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() ile kendi kendini durdurana veya başka bir bileşen stopService() yöntemini çağırana kadar çalışır.
Ayrıca, hizmetiniz başlatılır ve bağlamayı kabul ederse sistem onUnbind() yönteminizi çağırdığında, bir istemci hizmete bir sonraki bağlandığında onRebind() çağrısı almak istiyorsanız isteğe bağlı olarak true değerini döndürebilirsiniz. onRebind() void döndürür ancak istemci, onServiceConnected() geri çağırmasında IBinder değerini almaya devam eder.
Aşağıdaki şekilde bu tür bir yaşam döngüsünün mantığı gösterilmektedir.
Başlatılan bir hizmetin yaşam döngüsü hakkında daha fazla bilgi için Hizmetlere genel bakış başlıklı makaleyi inceleyin.