Привязанная служба – это сервер в интерфейсе "клиент – сервер". Она позволяет компонентам, например действиям, связываться с сервисом, отправлять запросы, получать ответы и выполнять межпроцессное взаимодействие (IPC). Обычно привязанная служба существует, только пока обслуживает другой компонент приложения, и не работает в фоновом режиме постоянно.
В этом документе описывается, как создать привязанную службу и как привязать ее к другим компонентам приложения. Дополнительную информацию о сервисах в целом, например о том, как доставлять уведомления из сервиса и настроить его запуск в активном режиме, можно найти в обзоре сервисов.
Основные сведения
Привязанная служба – это реализация класса Service, которая позволяет другим приложениям привязываться к ней и взаимодействовать с ней. Чтобы обеспечить привязку к сервису, реализуйте метод обратного вызова onBind(). Этот метод возвращает объект IBinder, который определяет программный интерфейс, используемый клиентами для взаимодействия с сервисом.
Привязка к запущенному сервису
Как описано в обзоре сервисов, вы можете создать сервис, который будет одновременно запущенным и привязанным. Это означает, что вы можете запустить сервис, вызвав метод startService(), и он будет работать неограниченное время. Вы также можете разрешить клиенту привязку к сервису, вызвав bindService().
Если вы разрешите запуск и привязку сервиса, то при его запуске система не уничтожит сервис, когда все клиенты отвяжутся.
Вместо этого необходимо явно остановить сервис, вызвав stopSelf() или stopService().
Хотя обычно вы реализуете либо onBind(), либо onStartCommand(), иногда необходимо реализовать оба варианта. Например, для музыкального проигрывателя может быть полезно, чтобы его служба работала неограниченно долго, а также обеспечивала привязку. Таким образом, действие может запустить службу для воспроизведения музыки, и музыка будет продолжать играть, даже если пользователь выйдет из приложения. Когда пользователь возвращается в приложение, действие может привязаться к сервису, чтобы восстановить управление воспроизведением.
Дополнительную информацию о жизненном цикле службы при добавлении привязки к запущенной службе можно найти в разделе Управление жизненным циклом привязанной службы.
Клиент привязывается к сервису, вызывая метод bindService(). При этом необходимо реализовать интерфейс ServiceConnection, который отслеживает подключение к сервису. Возвращаемое значение bindService() указывает, существует ли запрашиваемый сервис и разрешен ли клиенту доступ к нему.
Когда система Android создает подключение между клиентом и сервисом, она вызывает метод onServiceConnected() в объекте ServiceConnection. Метод onServiceConnected() включает аргумент IBinder, который клиент использует для связи с привязанной службой.
К сервису можно подключить несколько клиентов одновременно. Однако система кеширует канал связи сервиса IBinder.
Другими словами, система вызывает метод onBind() сервиса для создания IBinder только тогда, когда привязывается первый клиент. Затем система доставляет этот же объект IBinder всем дополнительным клиентам, которые привязываются к тому же сервису, не вызывая onBind() снова.
Когда последний клиент отключается от сервиса, система удаляет сервис, если он не был запущен с помощью startService().
Самая важная часть реализации привязанной службы – определение интерфейса, который возвращает метод обратного вызова onBind(). В следующем разделе рассматриваются несколько способов определения интерфейса IBinder вашего сервиса.
Как создать привязанную службу
При создании сервиса, который предоставляет привязку, необходимо предоставить объект IBinder, который предоставляет программный интерфейс, используемый клиентами для взаимодействия с сервисом. Определить интерфейс можно тремя способами:
- Расширение класса Binder
- Если сервис является частным для вашего приложения и выполняется в том же процессе, что и клиент (это распространенный случай), создайте интерфейс, расширив класс
Binderи возвратив его экземпляр из методаonBind(). Клиент получаетBinderи может использовать его для прямого доступа к общедоступным методам, доступным в реализацииBinderилиService.Этот способ предпочтителен, если сервис является фоновым рабочим процессом для вашего приложения. Единственный случай, когда этот способ создания интерфейса не является предпочтительным, – это когда ваш сервис используется другими приложениями или в рамках отдельных процессов.
- Используйте мессенджер
- Если вам нужно, чтобы интерфейс работал в разных процессах, вы можете создать интерфейс для сервиса с помощью
Messenger. Таким образом, сервис определяетHandler, который отвечает на разные типы объектовMessage.Этот
Handlerслужит основой дляMessenger, который затем может передатьIBinderклиенту, позволяя ему отправлять команды сервису с помощью объектовMessage. Кроме того, клиент может определить собственныйMessenger, чтобы сервис мог отправлять сообщения обратно.Это самый простой способ межпроцессного взаимодействия (IPC), поскольку
Messengerставит все запросы в очередь в одном потоке, поэтому вам не нужно разрабатывать сервис с учетом потокобезопасности. - Используйте AIDL
- Язык описания интерфейсов Android (AIDL) разбивает объекты на примитивы, которые может распознать операционная система, и упорядочивает их по процессам для выполнения IPC. Предыдущий метод, использующий
Messenger, на самом деле основан на AIDL как базовой структуре.Как упоминалось в предыдущем разделе,
Messengerсоздает очередь из всех клиентских запросов в одном потоке, поэтому сервис получает запросы по одному. Однако если вы хотите, чтобы ваш сервис обрабатывал несколько запросов одновременно, вы можете использовать AIDL напрямую. В этом случае ваш сервис должен быть потокобезопасным и поддерживать многопоточность.Чтобы использовать AIDL напрямую, создайте файл
.aidl, определяющий программный интерфейс. Инструменты Android SDK используют этот файл для создания абстрактного класса, который реализует интерфейс и обрабатывает IPC. Затем вы можете расширить этот класс в своем сервисе.
Примечание. Для большинства приложений AIDL – не лучший выбор для создания привязанной службы, поскольку может потребоваться поддержка многопоточности, что усложнит реализацию. Поэтому в этом документе не рассматривается, как использовать его для вашего сервиса. Если вы уверены, что вам нужно использовать AIDL напрямую, ознакомьтесь с документацией по AIDL.
Расширение класса Binder
Если сервис используется только локальным приложением и не должен работать в разных процессах, вы можете реализовать собственный класс Binder, который предоставляет клиенту прямой доступ к открытым методам сервиса.
Примечание. Это работает, только если клиент и сервис находятся в одном приложении и процессе, что бывает чаще всего. Например, это хорошо подходит для музыкального приложения, которому необходимо привязать операцию к собственной службе, воспроизводящей музыку в фоновом режиме.
Вот как это сделать:
- В сервисе создайте экземпляр
Binder, который выполняет одно из следующих действий:- Содержит общедоступные методы, которые может вызывать клиент.
- Возвращает текущий экземпляр
Service, у которого есть общедоступные методы, вызываемые клиентом. - Возвращает экземпляр другого класса, размещенного в сервисе, с общедоступными методами, которые может вызывать клиент.
- Верните этот экземпляр
Binderиз метода обратного вызоваonBind(). - В клиенте получите
Binderиз метода обратного вызоваonServiceConnected()и выполните вызовы привязанной службы, используя предоставленные методы.
Примечание. Сервис и клиент должны находиться в одном приложении, чтобы клиент мог привести возвращенный объект и правильно вызвать его API. Сервис и клиент также должны находиться в одном процессе, поскольку этот метод не выполняет маршалинг между процессами.
Например, вот сервис, который предоставляет клиентам доступ к методам в сервисе через реализацию Binder:
Kotlin
class LocalService : Service() { // Binder given to clients. private val binder = LocalBinder() // Random number generator. private val mGenerator = Random() /** Method for clients. */ val randomNumber: Int get() = mGenerator.nextInt(100) /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ inner class LocalBinder : Binder() { // Return this instance of LocalService so clients can call public methods. fun getService(): LocalService = this@LocalService } override fun onBind(intent: Intent): IBinder { return binder } }
Java
public class LocalService extends Service { // Binder given to clients. private final IBinder binder = new LocalBinder(); // Random number generator. private final Random mGenerator = new Random(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods. return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return binder; } /** Method for clients. */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
Класс LocalBinder предоставляет метод getService(), с помощью которого клиенты могут получить текущий экземпляр LocalService. Это позволяет клиентам вызывать общедоступные методы в сервисе. Например, клиенты могут звонить в компанию "getRandomNumber()" через сервис.
Ниже приведен пример действия, которое привязывается к LocalService и вызывает getRandomNumber() при нажатии кнопки.
Kotlin
class BindingActivity : Activity() { private var mService: LocalService? = null private var mBound: Boolean = false /** Defines callbacks for service binding, passed to bindService(). */ private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { // We've bound to LocalService, cast the IBinder and get LocalService instance. val binder = service as LocalService.LocalBinder mService = binder.getService() mBound = true } override fun onServiceDisconnected(arg0: ComponentName) { mService = null mBound = false } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } override fun onStart() { super.onStart() // Bind to LocalService. Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() unbindService(connection) // Release the reference so the service can be garbage-collected once it's // destroyed. onServiceDisconnected() isn't called when the client unbinds. mService = null mBound = false } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute). */ fun onButtonClick(v: View) { if (mBound) { // Call a method from the LocalService. // However, if this call is something that might hang, then put this request // in a separate thread to avoid slowing down the activity performance. val num: Int = mService?.randomNumber ?: return Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show() } } }
Java
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService. Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(connection); // Release the reference so the service can be garbage-collected once it's // destroyed. onServiceDisconnected() isn't called when the client unbinds. mService = null; mBound = false; } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute). */ public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call is something that might hang, then put this request // in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService(). */ private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mService = null; mBound = false; } }; }
В примере выше показано, как клиент привязывается к сервису с помощью реализации ServiceConnection и обратного вызова onServiceConnected(). В следующем разделе приведена дополнительная информация о процессе привязки к сервису.
Примечание. В предыдущем примере метод onStop() отменяет привязку клиента к сервису и удаляет ссылку клиента на него.
Отключайте клиентов от сервисов в подходящее время, как описано в разделе Дополнительные примечания.
Дополнительные примеры кода можно найти в классах
LocalService.java и
LocalServiceActivities.java в ApiDemos.
Используйте мессенджер
Если вам нужно, чтобы сервис взаимодействовал с удаленными процессами, вы можете использовать Messenger, чтобы предоставить интерфейс для сервиса. Этот метод позволяет выполнять межпроцессное взаимодействие (IPC) без использования AIDL.
Использовать Messenger для интерфейса проще, чем AIDL, потому что Messenger ставит в очередь все вызовы сервиса. Чистый интерфейс AIDL отправляет одновременные запросы к сервису, который затем должен обрабатывать многопоточность.
Для большинства приложений сервису не нужно выполнять многопоточность, поэтому использование Messenger позволяет сервису обрабатывать по одному вызову за раз. Если вам нужен многопоточный сервис, используйте для определения интерфейса AIDL.
Вот как использовать Messenger:
- Сервис реализует
Handler, который получает обратный вызов для каждого вызова от клиента. - Сервис использует
Handlerдля создания объектаMessenger(который является ссылкой наHandler). MessengerсоздаетIBinder, который сервис возвращает клиентам изonBind().- Клиенты используют
IBinderдля создания экземпляраMessenger(который ссылается наHandlerсервиса), используемого клиентом для отправки объектовMessageв сервис. - Сервис получает каждый
Messageв своемHandler, а именно в методеhandleMessage().
Таким образом, у клиента нет методов для вызова сервиса. Вместо этого клиент доставляет сообщения (объекты Message), которые сервис получает в своем методе Handler.
Вот пример сервиса, использующего интерфейс Messenger:
Kotlin
/** Command to the service to display a message. */ private const val MSG_SAY_HELLO = 1 class MessengerService : Service() { /** * Target we publish for clients to send messages to IncomingHandler. */ private lateinit var mMessenger: Messenger /** * Handler of incoming messages from clients. */ internal class IncomingHandler( context: Context, private val applicationContext: Context = context.applicationContext ) : Handler() { override fun handleMessage(msg: Message) { when (msg.what) { MSG_SAY_HELLO -> Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show() else -> super.handleMessage(msg) } } } /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ override fun onBind(intent: Intent): IBinder? { Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show() mMessenger = Messenger(IncomingHandler(this)) return mMessenger.binder } }
Java
public class MessengerService extends Service { /** * Command to the service to display a message. */ static final int MSG_SAY_HELLO = 1; /** * Handler of incoming messages from clients. */ static class IncomingHandler extends Handler { private Context applicationContext; IncomingHandler(Context context) { applicationContext = context.getApplicationContext(); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ Messenger mMessenger; /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); mMessenger = new Messenger(new IncomingHandler(this)); return mMessenger.getBinder(); } }
Метод handleMessage() в Handler – это место, где сервис получает входящий Message и решает, что делать, на основе элемента what.
Клиенту нужно лишь создать Messenger на основе IBinder, возвращенного сервисом, и отправить сообщение с помощью send(). Например, вот действие, которое связывается с сервисом и передает ему сообщение MSG_SAY_HELLO:
Kotlin
class ActivityMessenger : Activity() { /** Messenger for communicating with the service. */ private var mService: Messenger? = null /** Flag indicating whether we have called bind on the service. */ private var bound: Boolean = false /** * Class for interacting with the main interface of the service. */ private val mConnection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = Messenger(service) bound = true } override fun onServiceDisconnected(className: ComponentName) { // This is called when the connection with the service has been // unexpectedly disconnected—that is, its process crashed. mService = null bound = false } } fun sayHello(v: View) { if (!bound) return // Create and send a message to the service, using a supported 'what' value. val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0) try { mService?.send(msg) } catch (e: RemoteException) { e.printStackTrace() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } override fun onStart() { super.onStart() // Bind to the service. Intent(this, MessengerService::class.java).also { intent -> bindService(intent, mConnection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() // Unbind from the service. if (bound) { unbindService(mConnection) mService = null bound = false } } }
Java
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean bound; /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); bound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected—that is, its process crashed. mService = null; bound = false; } }; public void sayHello(View v) { if (!bound) return; // Create and send a message to the service, using a supported 'what' value. Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service. bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service. if (bound) { unbindService(mConnection); mService = null; bound = false; } } }
В этом примере не показано, как сервис может ответить клиенту.
Если вы хотите, чтобы сервис отвечал, вам также нужно создать Messenger в клиенте.
Когда клиент получает обратный вызов onServiceConnected(), он отправляет в сервис запрос Message, который включает Messenger клиента в параметре replyTo метода send().
Пример реализации двустороннего обмена сообщениями можно найти в примерах
MessengerService.java (сервис) и
MessengerServiceActivities.java (клиент).
Подключение к сервису
Компоненты приложения (клиенты) могут привязываться к сервису, вызывая метод bindService(). Затем система Android вызывает метод onBind() сервиса, который возвращает объект IBinder для взаимодействия с сервисом.
Привязка выполняется асинхронно, и bindService() возвращается немедленно, не возвращая IBinder клиенту. Чтобы получить IBinder, клиент должен создать экземпляр ServiceConnection и передать его в bindService(). ServiceConnection включает метод обратного вызова, который система использует для доставки IBinder.
Примечание. К сервису могут подключаться только действия, сервисы и поставщики контента. Подключиться к сервису из широковещательного приемника нельзя.
Чтобы привязать сервис к клиенту, выполните следующие действия:
- Реализуйте
ServiceConnection.Вам нужно переопределить два метода обратного вызова:
onServiceConnected()- Система вызывает этот метод, чтобы передать объект
IBinder, возвращенный методомonBind()сервиса. onServiceDisconnected()- Система Android вызывает этот метод, когда связь с сервисом неожиданно прерывается, например в случае сбоя или принудительного завершения работы сервиса. Этот метод не вызывается, когда клиент отменяет привязку.
- Вызовите
bindService(), передав реализациюServiceConnection.Примечание. Если метод возвращает значение false, у клиента нет действительного подключения к сервису. Однако в клиенте необходимо вызвать
unbindService(). В противном случае клиент не позволит сервису завершить работу, когда он неактивен. - Когда система вызывает метод обратного вызова
onServiceConnected(), вы можете начать вызывать сервис, используя методы, определенные интерфейсом. - Чтобы отключиться от сервиса, вызовите
unbindService().Если клиент все ещё привязан к сервису, когда приложение уничтожает клиент, привязка отменяется. Рекомендуется отменять привязку клиента сразу после завершения взаимодействия с сервисом. Это позволит отключить неиспользуемый сервис. Дополнительную информацию о том, когда следует привязывать и отвязывать сервис, можно найти в разделе Дополнительные примечания.
В следующем примере клиент подключается к сервису, созданному ранее путем расширения класса Binder. Поэтому все, что нужно сделать, – это привести возвращенный объект IBinder к классу LocalBinder и запросить экземпляр LocalService:
Kotlin
var mService: LocalService? = null val mConnection = object : ServiceConnection { // Called when the connection with the service is established. override fun onServiceConnected(className: ComponentName, service: IBinder) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. val binder = service as LocalService.LocalBinder mService = binder.getService() mBound = true } // Called when the connection with the service disconnects unexpectedly. override fun onServiceDisconnected(className: ComponentName) { Log.e(TAG, "onServiceDisconnected") mService = null mBound = false } }
Java
LocalService mService; private ServiceConnection mConnection = new ServiceConnection() { // Called when the connection with the service is established. public void onServiceConnected(ComponentName className, IBinder service) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } // Called when the connection with the service disconnects unexpectedly. public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); mService = null; mBound = false; } };
С помощью этого объекта ServiceConnection клиент может привязаться к сервису, передав его в метод bindService(), как показано в следующем примере:
Kotlin
Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) }
Java
Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE);
- Первый параметр
bindService()– этоIntent, который явно указывает сервис для привязки.Внимание! Если вы используете намерение для привязки к
Service, убедитесь, что ваше приложение защищено, используя явное намерение. Использование неявного намерения для запуска сервиса представляет угрозу безопасности, поскольку вы не можете быть уверены, какой сервис ответит на намерение, а пользователь не может видеть, какой сервис запускается. Начиная с Android 5.0 (уровень API 21), система выдает исключение, если вы вызываетеbindService()с неявным намерением. - Второй параметр – объект
ServiceConnection. - Третий параметр – это флаг, указывающий на параметры привязки. Обычно это
BIND_AUTO_CREATE, чтобы создать сервис, если он ещё не запущен. Другие возможные значения:BIND_DEBUG_UNBIND,BIND_NOT_FOREGROUNDили0(нет).
Дополнительные сведения
Вот несколько важных примечаний о привязке к сервису:
- Всегда перехватывайте исключения
DeadObjectException, которые возникают при разрыве соединения. Это единственное исключение, которое выдают удаленные методы. - Объекты подсчитываются по ссылкам в разных процессах.
- Обычно привязка и отмена привязки выполняются в соответствующие моменты жизненного цикла клиента, как описано в следующих примерах:
- Если вам нужно взаимодействовать с сервисом, только когда действие видно, привяжите его во время
onStart()и отвяжите во времяonStop(). - Если вы хотите, чтобы ваше действие получало ответы, даже когда оно остановлено в фоновом режиме, привяжите его во время
onCreate()и отмените привязку во времяonDestroy(). Помните, что в этом случае сервис должен использоваться на протяжении всего времени работы действия, даже в фоновом режиме. Если сервис выполняется в другом процессе, то вы увеличиваете нагрузку на этот процесс, и система с большей вероятностью его завершит.
Примечание. Обычно привязка и отмена привязки не выполняются во время обратных вызовов
onResume()иonPause(), поскольку эти вызовы происходят при каждом переходе жизненного цикла. Сведите к минимуму обработку, которая происходит при этих переходах.Кроме того, если несколько операций в приложении привязаны к одному сервису и между двумя из них происходит переход, сервис может быть уничтожен и создан заново, поскольку текущая операция отвязывается (во время паузы) до того, как привязывается следующая (во время возобновления). Переход между действиями и координация их жизненных циклов описаны в статье Жизненный цикл объекта activity.
- Если вам нужно взаимодействовать с сервисом, только когда действие видно, привяжите его во время
Дополнительные примеры кода, показывающие, как выполнить привязку к сервису, можно найти в классе
RemoteService.java в ApiDemos.
Управление жизненным циклом привязанной службы
Когда служба отвязана от всех клиентов, система Android уничтожает ее (если она не была запущена с помощью startService()). Таким образом, вам не нужно управлять жизненным циклом службы, если она является исключительно привязанной. Система Android управляет им за вас в зависимости от того, привязан ли он к каким-либо клиентам.
Однако если вы решите реализовать метод обратного вызова onStartCommand(), то вам нужно будет явно остановить сервис, поскольку теперь он считается запущенным. В этом случае сервис работает до тех пор, пока не остановится сам с помощью метода stopSelf() или пока другой компонент не вызовет метод stopService(), независимо от того, привязан ли он к каким-либо клиентам.
Кроме того, если ваш сервис запущен и принимает привязку, то когда система вызывает метод onUnbind(), вы можете вернуть true, чтобы получить вызов onRebind() при следующей привязке клиента к сервису. onRebind() возвращает void, но клиент все равно получает IBinder в обратном вызове onServiceConnected().
На рисунке ниже показана логика такого жизненного цикла.
Подробнее о жизненном цикле запущенного сервиса…