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şletiponBind()
üzerinden bunun bir örneğini döndürerek arayüzünüzü oluşturun. İstemciBinder
dosyasını alır veBinder
uygulamasında ya daService
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 birHandler
tanımlar.Bu
Handler
, daha sonra istemciyle birIBinder
paylaşabilen ve istemcininMessage
nesnelerini kullanarak hizmete komut göndermesini sağlayan birMessenger
için temel oluşturur. Buna ek olarak, istemci kendiMessenger
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:
- 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.
- Bu
Binder
örneğinionBind()
geri çağırma yönteminden döndürün. - İstemcide,
onServiceConnected()
geri çağırma yöntemindenBinder
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:
- Hizmet, bir istemciden gelen her arama için geri arama alan bir
Handler
uygular. - Hizmet,
Handler
öğesini kullanarak birMessenger
nesnesi (Handler
için referans) oluşturur. Messenger
, hizmetinonBind()
üzerinden istemcilere döndürdüğü birIBinder
oluşturur.- İstemciler, istemcinin
Message
nesnelerini hizmete göndermek için kullandığıMessenger
(hizmetinHandler
öğesine referans veren) örneğini oluşturmak içinIBinder
öğesini kullanır. - Hizmet, her
Message
değeriniHandler
içinde (özelliklehandleMessage()
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:
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ülenIBinder
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.
ServiceConnection
uygulamasını geçerekbindService()
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.- Sistem,
onServiceConnected()
geri çağırma yönteminizi çağırdığında arayüzde tanımlanan yöntemleri kullanarak hizmete çağrı yapmaya başlayabilirsiniz. - 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 birIntent
'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çlabindService()
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ğerlerBIND_DEBUG_UNBIND
,BIND_NOT_FOREGROUND
veya hiçbiri için0
ş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ı veonStop()
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 veonDestroy()
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()
veonPause()
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.
- Hizmetle yalnızca etkinliğiniz görünür durumdayken etkileşimde bulunmanız gerekiyorsa
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.
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.