Android bind service from service

Полный список

— используем биндинг для подключения к сервису

В прошлых уроках мы общались с сервисом асинхронно. Т.е. мы отправляли запрос через startService, а ответ нам приходил когда-нибудь потом посредством PendingIntent или BroadcastReceiver.

Но есть и синхронный способ взаимодействия с сервисом. Он достигается с помощью биндинга (binding, я также буду использовать слово «подключение»). Мы подключаемся к сервису и можем взаимодействовать с ним путем обычного вызова методов с передачей данных и получением результатов. В этом уроке передавать данные не будем. Пока что разберемся, как подключаться и отключаться.

Как вы помните, для запуска и остановки сервиса мы использовали методы startService и stopService. Для биндинга используются методы bindService и unbindService.

Создадим два Application. В одном будет приложение, в другом сервис.

Создадим первый проект:

Project name: P0971_ServiceBindClient
Build Target: Android 2.3.3
Application name: ServiceBindClient
Package name: ru.startandroid.develop.p0971servicebindclient
Create Activity: MainActivity

Добавим в strings.xml строки:

4 кнопки: для запуска, остановки и биндинга сервиса

В onCreate мы создаем Intent, который позволит нам добраться до сервиса.

Объект ServiceConnection позволит нам определить, когда мы подключились к сервису и когда связь с сервисом потеряна (если сервис был убит системой при нехватке памяти). При подключении к сервису сработает метод onServiceConnected. На вход он получает имя компонента-сервиса и объект Binder для взаимодействия с сервисом. В этом уроке мы этим Binder пока не пользуемся. При потере связи сработает метод onServiceDisconnected.

Переменную bound мы используем для того, чтобы знать – подключены мы в данный момент к сервису или нет. Соответственно при подключении мы переводим ее в true, а при потере связи в false.

Далее идут обработчики кнопок. В onClickStart мы стартуем сервис, в onClickStop – останавливаем.

В onClickBind – соединяемся с сервисом, используя метод bindService. На вход передаем Intent, ServiceConnection и флаг BIND_AUTO_CREATE, означающий, что, если сервис, к которому мы пытаемся подключиться, не работает, то он будет запущен.

В onClickUnBind с помощью bound проверяем, что соединение уже установлено. Далее отсоединяемся методом unbindService, на вход передавая ему ServiceConnection. И в bound пишем false, т.к. мы сами разорвали соединение. Метод onServiceDisconnected не сработает при явном отключении.

Создадим второй проект, без Activity:

Project name: P0972_ServiceBindServer
Build Target: Android 2.3.3
Application name: ServiceBindServer
Package name: ru.startandroid.develop.p0972servicebindserver

Создаем сервис MyService.java:

Методы onCreate и onDestroy нам знакомы – они вызываются при создании и уничтожении сервиса. А onBind, onRebind и onUnbind используются при биндинге и мы далее будем смотреть как именно. Метод onStartCommand не используем.

В методе onBind возвращаем пока объект-заглушку Binder. В этом уроке он не будет использован.

Прописываем сервис в манифесте и настраиваем для него IntentFilter с Action = ru.startandroid.develop.p0972servicebindserver.MyService.

Все сохраняем, инсталлим сервис и запускаем приложение.

На самом экране ничего происходить не будет. Все внимание на логи.

Попробуем подключиться к неработающему сервису. Жмем Bind. В логах:

MyService onCreate
MyService onBind
MainActivity onServiceConnected

Сервис создался и сработал его метод onBind. Также сработал метод onServiceConnected в ServiceConnection, т.е. Activity теперь знает, что подключение к сервису установлено.

Попробуем отключиться. Жмем Unbind.

MyService onUnbind
MyService onDestroy

Сработал метод Unbind в сервисе и сервис закрылся. Т.е. если мы биндингом запустили сервис, он будет жить, пока живет соединение. Как только мы отключаемся, сервис останавливается. onServiceDisconnected не сработал, т.к. мы сами отключились.

Теперь попробуем соединиться с сервисом и убить его. Посмотрим, что станет с соединением. Жмем Bind.

MyService onCreate
MyService onBind
MainActivity onServiceConnected

Теперь в процессах убиваем процесс сервиса

Сработал метод onServiceDisconnected объекта ServiceConnection. Тем самым Activity уведомлено, что соединение разорвано.

Теперь немного подождем (у меня это заняло 5 секунд) и в логах появляются строки:

MyService onCreate
MyService onBind
MainActivity onServiceConnected

Сервис запустился и соединение восстановилось. Очень удобно.

Жмем Unbind и отключаемся.

Попробуем снова подключиться к незапущенному сервису, но уже без флага BIND_AUTO_CREATE. Перепишем onClickBind в MainActivity.java:

Вместо флага BIND_AUTO_CREATE мы написали 0.

Сохраняем, запускаем. Жмем Bind. В логах ничего. Мы убрали флаг, сервис сам не создается при подключении.

Давайте запустим его методом startService. Жмем Start. В логах:

MyService onCreate
MyService onBind
MainActivity onServiceConnected

Сервис создался и приложение подключилось к нему. Т.е. попыткой биндинга мы оставили некую «заявку» на подключение, и когда сервис был запущен методом startService, он эту заявку увидел и принял подключение.

Отключились от сервиса. Но сервис продолжает жить, потому что он был запущен не биндингом, а методом startService. А там уже свои правила закрытия сервиса. Это мы проходили в прошлых уроках.

Сервис завершил работу.

Попробуем запустить сервис методом startService и, пока он работает, несколько раз подключимся и отключимся. Жмем Start.

Подключаемся и отключаемся, т.е. жмем Bind

MyService onBind
MainActivity onServiceConnected

Сработали методы onBind и onUnbind в сервисе, и onServiceConnected в ServiceConnection.

Еще раз подключаемся и отключаемся — жмем Bind, а затем Unbind

При повторном подключении к сервису методы onBind и onUnbind не сработали. Только onServiceConnected.

И далее, сколько бы мы не подключались, так и будет.

Остановим сервис – нажмем Stop.

Это поведение можно скорректировать. Для этого необходимо возвращать true в методе onUnbind. Сейчас мы там вызываем метод супер-класса, а он возвращает false.

Перепишем метод Unbind в MyService.java:

Сохраним и инсталлим сервис. Жмем Start, а затем жмем поочередно Bind и Unbind, т.е. подключаемся и отключаемся. Смотрим логи:

MyService onCreate
MyService onBind
MainActivity onServiceConnected
MyService onUnbind

Сервис создан, подключились и отключились. Продолжаем подключаться и отключаться.

MyService onRebind
MainActivity onServiceConnected
MyService onUnbind
MyService onRebind
MainActivity onServiceConnected
MyService onUnbind

Последующие подключения и отключения сопровождаются вызовами методов onRebind и onUnbind. Таким образом, у нас есть возможность обработать в сервисе каждое повторное подключение/отключение.

Вот примерно такой Lifecycle имеет биндинг сервиса. Разумеется, я рассмотрел не все возможные комбинации запуска методов startService, stopService, bindService и unbindService. Оставляю это вам, если есть интерес. Я рассмотрел только типичные случаи.

Читайте также:  Mtg arena android apk

Также я не рассматривал возможность одновременного подключения нескольких приложений или сервисов к одному сервису. А такая возможность существует. В этом случае, если сервис запущен биндингом, то он будет жить, пока не отключатся все подключившиеся.

Насколько я понял по хелпу, не рекомендуется оставлять незавершенные подключения к сервисам по окончании работы приложения. В хелповских примерах подключение к сервису производится в методе onStart, а отключение — в onStop. Но, разумеется, если вам надо, чтобы подключение оставалось при временном уходе Activity в background, то используйте onCreate и onDestroy. Также есть четкая рекомендация от гугла — не использовать для этих целей onResume и onPause.

На следующем уроке:

— обмен данными в биндинге

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Bound Services

In this document

Key classes

Samples

See also

A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves another application component and does not run in the background indefinitely.

This document shows you how to create a bound service, including how to bind to the service from other application components. However, you should also refer to the Services document for additional information about services in general, such as how to deliver notifications from a service, set the service to run in the foreground, and more.

The Basics

A bound service is an implementation of the Service class that allows other applications to bind to it and interact with it. To provide binding for a service, you must implement the onBind() callback method. This method returns an IBinder object that defines the programming interface that clients can use to interact with the service.

Binding to a Started Service

As discussed in the Services document, you can create a service that is both started and bound. That is, the service can be started by calling startService() , which allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService() .

If you do allow your service to be started and bound, then when the service has been started, the system does not destroy the service when all clients unbind. Instead, you must explicitly stop the service, by calling stopSelf() or stopService() .

Although you should usually implement either onBind() or onStartCommand() , it’s sometimes necessary to implement both. For example, a music player might find it useful to allow its service to run indefinitely and also provide binding. This way, an activity can start the service to play some music and the music continues to play even if the user leaves the application. Then, when the user returns to the application, the activity can bind to the service to regain control of playback.

Be sure to read the section about Managing the Lifecycle of a Bound Service, for more information about the service lifecycle when adding binding to a started service.

A client can bind to the service by calling bindService() . When it does, it must provide an implementation of ServiceConnection , which monitors the connection with the service. The bindService() method returns immediately without a value, but when the Android system creates the connection between the client and service, it calls onServiceConnected() on the ServiceConnection , to deliver the IBinder that the client can use to communicate with the service.

Multiple clients can connect to the service at once. However, the system calls your service’s onBind() method to retrieve the IBinder only when the first client binds. The system then delivers the same IBinder to any additional clients that bind, without calling onBind() again.

When the last client unbinds from the service, the system destroys the service (unless the service was also started by startService() ).

When you implement your bound service, the most important part is defining the interface that your onBind() callback method returns. There are a few different ways you can define your service’s IBinder interface and the following section discusses each technique.

Creating a Bound Service

When creating a service that provides binding, you must provide an IBinder that provides the programming interface that clients can use to interact with the service. There are three ways you can define the interface:

Extending the Binder class If your service is private to your own application and runs in the same process as the client (which is common), you should create your interface by extending the Binder class and returning an instance of it from onBind() . The client receives the Binder and can use it to directly access public methods available in either the Binder implementation or even the Service .

This is the preferred technique when your service is merely a background worker for your own application. The only reason you would not create your interface this way is because your service is used by other applications or across separate processes. Using a Messenger If you need your interface to work across different processes, you can create an interface for the service with a Messenger . In this manner, the service defines a Handler that responds to different types of Message objects. This Handler is the basis for a Messenger that can then share an IBinder with the client, allowing the client to send commands to the service using Message objects. Additionally, the client can define a Messenger of its own so the service can send messages back.

Читайте также:  Часы надпись для андроид

This is the simplest way to perform interprocess communication (IPC), because the Messenger queues all requests into a single thread so that you don’t have to design your service to be thread-safe.

Using AIDL AIDL (Android Interface Definition Language) performs all the work to decompose objects into primitives that the operating system can understand and marshall them across processes to perform IPC. The previous technique, using a Messenger , is actually based on AIDL as its underlying structure. As mentioned above, the Messenger creates a queue of all the client requests in a single thread, so the service receives requests one at a time. If, however, you want your service to handle multiple requests simultaneously, then you can use AIDL directly. In this case, your service must be capable of multi-threading and be built thread-safe.

To use AIDL directly, you must create an .aidl file that defines the programming interface. The Android SDK tools use this file to generate an abstract class that implements the interface and handles IPC, which you can then extend within your service.

Note: Most applications should not use AIDL to create a bound service, because it may require multithreading capabilities and can result in a more complicated implementation. As such, AIDL is not suitable for most applications and this document does not discuss how to use it for your service. If you’re certain that you need to use AIDL directly, see the AIDL document.

Extending the Binder class

If your service is used only by the local application and does not need to work across processes, then you can implement your own Binder class that provides your client direct access to public methods in the service.

Note: This works only if the client and service are in the same application and process, which is most common. For example, this would work well for a music application that needs to bind an activity to its own service that’s playing music in the background.

Here’s how to set it up:

  1. In your service, create an instance of Binder that either:
    • contains public methods that the client can call
    • returns the current Service instance, which has public methods the client can call
    • or, returns an instance of another class hosted by the service with public methods the client can call
  2. Return this instance of Binder from the onBind() callback method.
  3. In the client, receive the Binder from the onServiceConnected() callback method and make calls to the bound service using the methods provided.

Note: The reason the service and client must be in the same application is so the client can cast the returned object and properly call its APIs. The service and client must also be in the same process, because this technique does not perform any marshalling across processes.

For example, here’s a service that provides clients access to methods in the service through a Binder implementation:

The LocalBinder provides the getService() method for clients to retrieve the current instance of LocalService . This allows clients to call public methods in the service. For example, clients can call getRandomNumber() from the service.

Here’s an activity that binds to LocalService and calls getRandomNumber() when a button is clicked:

The above sample shows how the client binds to the service using an implementation of ServiceConnection and the onServiceConnected() callback. The next section provides more information about this process of binding to the service.

Note: The example above doesn’t explicitly unbind from the service, but all clients should unbind at an appropriate time (such as when the activity pauses).

For more sample code, see the LocalService.java class and the LocalServiceActivities.java class in ApiDemos.

Using a Messenger

Compared to AIDL

When you need to perform IPC, using a Messenger for your interface is simpler than implementing it with AIDL, because Messenger queues all calls to the service, whereas, a pure AIDL interface sends simultaneous requests to the service, which must then handle multi-threading.

For most applications, the service doesn’t need to perform multi-threading, so using a Messenger allows the service to handle one call at a time. If it’s important that your service be multi-threaded, then you should use AIDL to define your interface.

If you need your service to communicate with remote processes, then you can use a Messenger to provide the interface for your service. This technique allows you to perform interprocess communication (IPC) without the need to use AIDL.

Here’s a summary of how to use a Messenger :

  • The service implements a Handler that receives a callback for each call from a client.
  • The Handler is used to create a Messenger object (which is a reference to the Handler ).
  • The Messenger creates an IBinder that the service returns to clients from onBind() .
  • Clients use the IBinder to instantiate the Messenger (that references the service’s Handler ), which the client uses to send Message objects to the service.
  • The service receives each Message in its Handler —specifically, in the handleMessage() method.

In this way, there are no «methods» for the client to call on the service. Instead, the client delivers «messages» ( Message objects) that the service receives in its Handler .

Here’s a simple example service that uses a Messenger interface:

Notice that the handleMessage() method in the Handler is where the service receives the incoming Message and decides what to do, based on the what member.

All that a client needs to do is create a Messenger based on the IBinder returned by the service and send a message using send() . For example, here’s a simple activity that binds to the service and delivers the MSG_SAY_HELLO message to the service:

Читайте также:  Рейтинг автонавигаторов для андроид

Notice that this example does not show how the service can respond to the client. If you want the service to respond, then you need to also create a Messenger in the client. Then when the client receives the onServiceConnected() callback, it sends a Message to the service that includes the client’s Messenger in the replyTo parameter of the send() method.

You can see an example of how to provide two-way messaging in the MessengerService.java (service) and MessengerServiceActivities.java (client) samples.

Binding to a Service

Application components (clients) can bind to a service by calling bindService() . The Android system then calls the service’s onBind() method, which returns an IBinder for interacting with the service.

The binding is asynchronous. bindService() returns immediately and does not return the IBinder to the client. To receive the IBinder , the client must create an instance of ServiceConnection and pass it to bindService() . The ServiceConnection includes a callback method that the system calls to deliver the IBinder .

Note: Only activities, services, and content providers can bind to a service—you cannot bind to a service from a broadcast receiver.

So, to bind to a service from your client, you must:

Your implementation must override two callback methods:

onServiceConnected() The system calls this to deliver the IBinder returned by the service’s onBind() method. onServiceDisconnected() The Android system calls this when the connection to the service is unexpectedly lost, such as when the service has crashed or has been killed. This is not called when the client unbinds.

  • Call bindService() , passing the ServiceConnection implementation.
  • When the system calls your onServiceConnected() callback method, you can begin making calls to the service, using the methods defined by the interface.
  • To disconnect from the service, call unbindService() .

    When your client is destroyed, it will unbind from the service, but you should always unbind when you’re done interacting with the service or when your activity pauses so that the service can shutdown while its not being used. (Appropriate times to bind and unbind is discussed more below.)

    For example, the following snippet connects the client to the service created above by extending the Binder class, so all it must do is cast the returned IBinder to the LocalService class and request the LocalService instance:

    With this ServiceConnection , the client can bind to a service by passing it to bindService() . For example:

    • The first parameter of bindService() is an Intent that explicitly names the service to bind (thought the intent could be implicit).
    • The second parameter is the ServiceConnection object.
    • The third parameter is a flag indicating options for the binding. It should usually be BIND_AUTO_CREATE in order to create the service if its not already alive. Other possible values are BIND_DEBUG_UNBIND and BIND_NOT_FOREGROUND , or 0 for none.

    Additional notes

    Here are some important notes about binding to a service:

    • You should always trap DeadObjectException exceptions, which are thrown when the connection has broken. This is the only exception thrown by remote methods.
    • Objects are reference counted across processes.
    • You should usually pair the binding and unbinding during matching bring-up and tear-down moments of the client’s lifecycle. For example:
      • If you only need to interact with the service while your activity is visible, you should bind during onStart() and unbind during onStop() .
      • If you want your activity to receive responses even while it is stopped in the background, then you can bind during onCreate() and unbind during onDestroy() . Beware that this implies that your activity needs to use the service the entire time it’s running (even in the background), so if the service is in another process, then you increase the weight of the process and it becomes more likely that the system will kill it.

      Note: You should usually not bind and unbind during your activity’s onResume() and onPause() , because these callbacks occur at every lifecycle transition and you should keep the processing that occurs at these transitions to a minimum. Also, if multiple activities in your application bind to the same service and there is a transition between two of those activities, the service may be destroyed and recreated as the current activity unbinds (during pause) before the next one binds (during resume). (This activity transition for how activities coordinate their lifecycles is described in the Activities document.)

      For more sample code, showing how to bind to a service, see the RemoteService.java class in ApiDemos.

      Managing the Lifecycle of a Bound Service

      When a service is unbound from all clients, the Android system destroys it (unless it was also started with onStartCommand() ). As such, you don’t have to manage the lifecycle of your service if it’s purely a bound service—the Android system manages it for you based on whether it is bound to any clients.

      However, if you choose to implement the onStartCommand() callback method, then you must explicitly stop the service, because the service is now considered to be started. In this case, the service runs until the service stops itself with stopSelf() or another component calls stopService() , regardless of whether it is bound to any clients.

      Additionally, if your service is started and accepts binding, then when the system calls your onUnbind() method, you can optionally return true if you would like to receive a call to onRebind() the next time a client binds to the service. onRebind() returns void, but the client still receives the IBinder in its onServiceConnected() callback. Below, figure 1 illustrates the logic for this kind of lifecycle.

      Figure 1. The lifecycle for a service that is started and also allows binding.

      For more information about the lifecycle of a started service, see the Services document.

      Источник

  • Оцените статью