- Android Services — Tutorial
- 1. Android Services
- 1.1. What are services?
- 1.2. Services and background processing
- 1.3. Platform service and custom services
- 1.4. Starting and defining custom services
- 1.5. Foreground services
- 2. Defining custom services
- 2.1. Implementation and declaration
- 2.2. Start a service
- 2.3. Service start process and execution
- 2.4. Service restart behavior
- 2.5. Stopping a service
- 3. IntentServices for one time tasks
- 4. Communication with services
- 4.1. Options for communication
- 4.2. Using Intent data
- 4.3. Using receiver
- 4.4. Activity binding to local service
- 4.5. Handler and ResultReceiver or Messenger
- 4.6. AIDL for services in a different process
- 5. Scheduling service
- 6. Exercise: Using services and service communication
- 7. Exercise: Define and consume local service
- Погружение в службы Android
- Введение
- Потоки, службы и жизненный цикл компонентов Android
- Изменения в Android O
- Запущенные службы
- Intent
- Передний план и механизм постоянного уведомления
- Остановка запущенных служб
- Привязанные службы
- bindService() и onCreate()
- Привязка службы
- Отвязка от службы и вызов onDestroy()
- Привязанные и запущенные службы одновременно
- Переход в запущенное состояние
- Завершение работы службы и отвязывание
- Примеры
Android Services — Tutorial
Using styles and themes in Android. Developing own services and using system services in Android. This tutorial describes how to create and consume Android services.
1. Android Services
1.1. What are services?
A service is a component which runs in the background without direct interaction with the user. As the service has no user interface, it is not bound to the lifecycle of an activity.
Services are used for repetitive and potentially long running operations, i.e., Internet downloads, checking for new data, data processing, updating content providers and the like.
Services run with a higher priority than inactive or invisible activities and therefore it is less likely that the Android system terminates them. Services can also be configured to be restarted if they get terminated by the Android system once sufficient system resources are available again.
It is possible to assign services the same priority as foreground activities. In this case it is required to have a visible notification active for the related service. It is frequently used for services which play videos or music.
1.2. Services and background processing
By default, a service runs in the same process as the main thread of the application.
Therefore, you need to use asynchronous processing in the service to perform resource intensive tasks in the background. A commonly used pattern for a service implementation is to create and run a new Thread in the service to perform the processing in the background and then to terminate the service once it has finished the processing.
Services which run in the process of the application are sometimes called local services .
1.3. Platform service and custom services
The Android platform provides and runs predefined system services and every Android application can use them, given the right permissions. These system services are usually exposed via a specific Manager class. Access to them can be gained via the getSystemService() method. The Context class defines several constants for accessing these services.
An Android application can, in addition to consuming the existing Android platform services, define and use new services. Defining your custom services allows you to design responsive applications. You can fetch the application data via it and once the application is started by the user, it can present fresh data to the user.
1.4. Starting and defining custom services
Custom services are started from other Android components, i.e., activities, broadcast receivers and other services.
1.5. Foreground services
A foreground service is a service that should have the same priority as an active activity and therefore should not be killed by the Android system, even if the system is low on memory. A foreground service must provide a notification for the status bar, which is placed under the «Ongoing» heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
2. Defining custom services
2.1. Implementation and declaration
A service needs to be declared in the AndroidManifest.xml file and the implementing class must extend the Service class or one of its subclasses.
The following code shows an example for a service declaration and its implementation.
2.2. Start a service
An Android component (service, receiver, activity) can trigger the execution of a service via the startService(intent) method.
Alternatively, you can also start a service via the bindService() method call. This allows you to communicate directly with the service. We discuss that later.
2.3. Service start process and execution
If the startService(intent) method is called and the service is not yet running, the service object is created and the onCreate() method of the service is called.
Once the service is started, the onStartCommand(intent) method in the service is called. It passes in the Intent object from the startService(intent) call.
If startService(intent) is called while the service is running, its onStartCommand() is also called. Therefore your service needs to be prepared that onStartCommand() can be called several times.
What if you call this method twice in your code? Do you have to worry about synchronizing the onStartCommand() method call? No, this method is called by the Android system in the main user interface thread, therefore it cannot be called simultaneously from two different threads. |
A service is only started once, no matter how often you call the startService() method.
2.4. Service restart behavior
In its onStartCommand() method call, the service returns an int which defines its restart behavior in case the service gets terminated by the Android platform. You can use the constants, the most common options are described by the following table.
Option | Description |
---|---|
You can check if the service was restarted via the Intent.getFlags() method. START_FLAG_REDELIVERY (in case the service was started with Service.START_REDELIVER_INTENT) or START_FLAG_RETRY (in case the service was started with Service.START_STICKY) is passed. |
2.5. Stopping a service
You stop a service via the stopService() method. No matter how frequently you called the startService(intent) method, one call to the stopService() method stops the service.
A service can terminate itself by calling the stopSelf() method. This is typically done if the service finishes its work.
3. IntentServices for one time tasks
You can also extend the IntentService class for your service implementation.
The IntentService is used to perform a certain task in the background. Once done, the instance of IntentService terminates itself automatically. An example for its usage would be downloading certain resources from the internet.
The IntentService class offers the onHandleIntent() method which will be asynchronously called by the Android system.
4. Communication with services
4.1. Options for communication
There are several possibilities for a communication between an activity and a service. The following description discusses the possible approaches and provides recommendation which to use.
4.2. Using Intent data
In a simple scenario no direct communication is required. The service receives the intent data from the starting Android component and performs its work. No notification is necessary. For example, in case the service updates a content provider, the activity is notified by the content provider and no extra step in the service is necessary. This approach works for local and services running in their own process.
4.3. Using receiver
You can use broadcasts and registered receivers for the communication. For example, your activity can register a broadcast receiver for an event and the service sends outs corresponding events. This is a very typical scenario, in which the service need to signal to the activity that his processing has finished.
This communication flow is depicted in the following graphic.
This approach works for local and services running in their own process.
Android provides the LocalBroadcastManager class in the support library v4. This is a helper class to register for and send broadcasts of Intents to local objects within your process. This approach improves security as the broadcast events are only visible within your process and is faster than using standard events.
4.4. Activity binding to local service
If the service is started in the same process as the activity, the activity can directly bind to the service. This is a relatively simple and efficient way to communicate and recommended for activities which need to have a fast communication layer with the service.
This approach works for local services.
4.5. Handler and ResultReceiver or Messenger
If the service should be communicating back to the activity, it can receive an object of type Messenger via the Intent data it receives from the activity. If the Messenger is bound to a Handler in the activity, the service can send objects of type Message to the activity.
A Messenger is parcelable, which means it can be passed to another process and you can use this object to send Messages to the Handler in the activity.
Messenger also provides the method getBinder() which allows passing a Messenger to the activity. The activity can therefore send Messages to the service.
This approach works for local services running in their own process.
4.6. AIDL for services in a different process
To bind to a service which runs in a different process, you need to use Inter Process Communication (IPC) to community your the data. To do so, you need to create a AIDL file which looks similar to a Java interface, but ends with the .aidl file extension and is only allowed to extend other AIDL files.
This approach is required if you need to bind to a service running in another process, i.e., if your service is consumed by other Android applications.
You can find more information about this approach in the Android developer documentation about AIDL.
5. Scheduling service
See https://www.vogella.com/tutorials/AndroidTaskScheduling/article.html — Android task scheduling to learn how to schedule service periodically.
6. Exercise: Using services and service communication
The following example demonstrates how to use a service to download a file from the Internet based on a button click from an activity. Once done, the service notifies the activity via a broadcast receiver that the download is complete.
In this exercise you use the IntentService class, as this class provides automatic background processing.
Create a new project called com.vogella.android.service.receiver with the activity called MainActivity.
Create the following class for the service.
Add this class to the AndroidManifest.xml file. Also add the permission to write to external storage and to access the Internet. The resulting AndroidManifest.xml file should look similar to the following listing.
Change the layout file of your activity to the following.
Change MainActivity to the following.
If you run your example and press the button, the download should be performed by the service. Once done, the user interface is updated and a Toast with the file name is shown.
Change the setting so that the service runs in its own process. Ensure that the application still works, as broadcast receivers are received across process boundaries.
7. Exercise: Define and consume local service
This exercise demonstrates how to bind to a local service from an activity.
The activity binds itself to the service to access its data.
Create a new project called com.vogella.android.localservice with the activity called MainActivity using the Empty Activity template.
Create the following LocalWordService class.
Register your service in the AndroidManifest.xml file.
Change the layout file of the activity similar to the following example.
Change your activity class to the following code.
Run your application. Via your buttons you can update your list or tell the service to fetch more data.
Источник
Погружение в службы Android
Перевод статьи «Deep Dive into Android Services» от Nazmul Idris. Я оставил оригинальное название автора, хотя это скорее не «погружение», а «знакомство». Думаю, текст будет полезен начинающим разработчикам. Статья отлично дополняет офф. документацию по службам на Android. В статье разбираются особенности взаимодействия с запущенными и привязанными службами. Плюс статьи в том, что учитываются изменения в работе со службами в Android O. В переводе есть незначительные, по сравнению с оригиналом, изменения, добавленные для пущей ясности.
Введение
Большинство современных android-приложений выполняют часть задач в фоне. Это означает, что задачи выполняются в фоновом потоке, а не в потоке пользовательского интерфейса (UI-поток).
Если вы создаете Thread (поток) или Executor (обертка управления потоками) в конкретной Activity своего приложения, то это может привести к непредсказуемым результатам. Например, во время простой смены ориентации экрана, ваша Activity создается заново и потокам, привязанным к старой Activity , некуда возвращать результат.
Чтобы справиться с этим вы могли бы использовать AsyncTask . Но что, если вашему приложению необходимо запустить этот фоновый поток не только из Activity , но и из нотификации (notification) или из другого компонента?
В этом случае служба (service) это подходящий компонент Android, который свяжет жизненный цикл потока со своим жизненным циклом, и таким образом не потеряет его.
Служба — это компонент android-приложения без видимого интерфейса, который запускается в основном потоке приложения. Служба должна быть объявлена в манифесте. Если вам необходимо чтобы служба работала в фоновом потоке, вы должны самостоятельно реализовать это.
Термины фон и передний план перегружены, и могут применяться к:
- жизненному циклу компонентов Android
- потокам
В этой статье, по умолчанию будем считать, что термины фон и передний план относятся к жизненному циклу. Но, когда будет идти речь о потоках, мы будем явно говорить фоновый поток или поток переднего плана.
Существует подкласс android-служб, называемый IntentService , который запускает задачи в фоновом потоке «из коробки». Но мы не будем говорить о таких службах в этой статье.
Потоки, службы и жизненный цикл компонентов Android
Давайте сделаем шаг назад и посмотрим на более общую картину того, что должны делать службы. Ваш код, который работает в фоновом потоке, например Thread или Executor , на самом деле не связан с жизненным циклом какого-либо компонента Android. Если мы говорим об Activity , то она имеет конкретную точку запуска и остановки работы, основываясь на взаимодействии с пользователем. Однако эти точки начала и конца работы Activity не обязательно связаны с жизненным циклом Thread или Executor .
Ниже приведены пояснения к основным временным моментам этой диаграммы Гантта. Детали этих моментов (и пояснения к ним) приведены в остальной части статьи.
Метод службы onCreate() вызывается в момент ее создания (путем запуска или привязки к ней).
Затем, через некоторое время, служба запускает Thread или Executor . Когда Thread завершает работу, он дает об этом знать службе, чтобы та могла вызвать метод stopSelf() . Это довольно распространенный шаблон реализации службы.
Код, который вы пишите в ваших Thread или Executor , должен сообщить службе о запуске или остановке фонового потока.
- Когда поток начинает работу, он должен установить начальное состояние сервиса путем вызова startService()
- Когда поток завершает работу, он должен вызвать stopSelf() у службы.
Метод службы onDestroy() вызывается системой только когда вы сообщили службе, что пришло время завершать работу. Служба не знает, что будет происходить в коде ваших Thread или Executor — это зона вашей ответственности. Таким образом, задача программиста сообщить службе о начале и о завершении работы.
Службы делятся на два вида: запущенные и привязанные. Кроме того, служба может быть запущенной и допускать привязку. Мы рассмотрим каждый из случаев:
- Запущенная служба
- Привязанная служба
- Привязанная и запущенная служба одновременно
Изменения в Android O
В Android O (API 26) произошли существенные изменения в регулировании фоновых служб системой. Одно из главных изменений в том, что запущенная служба, которая не в белом списке (в белый список помещаются службы, работа которых видна пользователю; подробнее смотри в офф. документации) или которая явно не сообщает пользователю о своей работе, не будет запускаться в фоновом потоке после закрытия Activity . Другими словами, вы должны создать уведомление (notification), к которому вы прикрепляете запущенную службу. И вы должны запускать службу с помощью нового метода startForegroundService() (а не с помощью startService() ). И, после создания службы, у вас есть пять секунд чтобы вызвать метод startForeground() запущенной службы и показать видимое пользователю уведомление. Иначе система останавливает службу и показывает ANR («приложение не отвечает»). Ниже мы разъясняем эти положения с помощью примеров кода.
Запущенные службы
Запущенные службы начинают свою работу после вызова метода startService(Intent) в вашей Activity или службе. При этом Intent должен быть явным. Это означает, что вы должны явно указать в Intent имя класса запускаемой вами службы. Или, если вам важно допустить некоторую неопределенность в отношении того, какая служба запускается, вы можете предоставить фильтры намерений для ваших служб и исключить имя компонента из Intent, но затем вы должны установить пакет для намерения с помощью setPackage() , который обеспечивает достаточное устранение неоднозначности для целевой службы. Ниже мы приводим пример создания явного Intent :
Чтобы служба стала запущенной, вы должны вызвать startService() с явным намерением. Если вы не сделаете этого, тогда служба не перейдет в запущенное состояние. И, таким образом, она не сможет перейти на передний план, и stopSelf() на самом деле ничего не выполнит.
Итак, если вы не перевели службу в запущенное состояние, вы не сможете прикрепить ее к уведомлению. Это довольно важные вещи, о которых вы должны помнить, когда вам нужно перевести службу в запущенное состояние.
Служба может быть запущена несколько раз. Каждый раз, когда она запускается, вызывается onStartCommand() . Этому методу передается несколько параметров наряду с явным Intent . Даже если вы запускаете службу несколько раз, она вызывает onCreate() только однажды (конечно, если до этого служба уже не была привязана). Чтобы завершить работу, служба должна вызвать stopSelf() . После того, как служба будет остановлена (когда вы остановите ее), и если с ней ничего больше не связано, вызывается onDestroy() . Помните об этом, когда выделяете ресурсы для вашей запущенной службы.
Intent
Для старта запущенной службы необходим Intent . Компонент Android, в котором стартует служба, на самом деле не хранит соединение с ней, и если ему необходимо что-то сообщить запущенной службе, он может запустить ее снова, используя другой Intent . Это главная разница между запущенной и привязанной службой. Привязанные службы со своей стороны реализуют шаблон клиент-сервер. Где клиент (компонент Android UI или другая служба) хранит соединение и может через него вызывать методы непосредственно у службы.
Помните, что в Android O многое изменилось в отношении запущенных служб. Они больше не могут работать достаточно долго в фоне без механизма постоянного уведомления. И метод старта запущенной службы в фоне в Android O — это startForegroundService(Intent) .
Передний план и механизм постоянного уведомления
Запущенная служба может работать на переднем плане. Опять же, термин передний план не относится к тому работает ли служба в фоновом потоке или в главном потоке. Но это означает, что система присвоит службе наивысший приоритет, и поэтому служба не является кандидатом для удаления системой в случае нехватки памяти. Помещать службу на передний план стоит только в том случае, когда это действительно необходимо для создания современного и отзывчивого приложения.
Примеры использования службами переднего плана:
- Приложения, которые проигрывают медиа-файлы в фоне.
- Приложения, которые обновляют данные о местоположении в фоне.
Когда запущенная служба помещается на передний план, она должна вывести на экран уведомление, явно сообщая пользователю, что служба работает. Это важно, потому что запущенная служба на переднем плане отделена от жизненного цикла UI-компонентов (за исключением, разумеется, самого постоянного уведомления). И нет другого способа сообщить пользователю о том, что на его телефоне что-то работает (и потенциально потребляет много ресурсов) кроме как вывести в UI постоянное уведомление.
Ниже пример старта запущенной службы на переднем плане:
Вот код создания постоянного уведомления в версиях
Кроме того, вот еще одна статья, в которой больше деталей о создании уведомлений в MediaStyle (поскольку для фонового проигрывания аудио-файлов нужны как уведомления, так и привязанные и запущенные службы)
Остановка запущенных служб
Обратите внимание, что параметр piStopService типа PendingIntent (который передается в конструктор уведомления) фактически передает Intent с константой Command.STOP типа Integer . Помните, что startService(Intent) может вызываться несколько раз? Это пример такого поведения. Чтобы остановить службу мы запускаем Intent через startService(Intent) и далее обрабатываем этот Intent в методе onStartCommand() запущенной службы.
Это объясняет почему метод onStartCommand() должен уметь обрабатывать Intent ы. Используя этот механизм мы можем «сказать» службе, чтобы она остановила работу. Ниже код, который иллюстрирует эти возможности:
Если вы хотите завершить выполнение запущенной службы на переднем плане, вы должны вызвать stopForeground(true) . Этот метод также завершит работу постоянного уведомления. Однако, саму службу это не остановит. Для этого следует вызвать stopSelf() .
Чтобы остановить службу вы можете выполнить одно из следующих действий:
- Как было показано выше, передайте Intent с дополнительным параметром в startService() , который затем будет обработан в onStartCommand() и фактически служба вызовет stopSelf() . И, если к службе не привязаны никакие другие компоненты, это вызовет onDestroy() и служба завершит свою работу.
- Вы также можете создать явный Intent (указывая на класс службы) и передать его в метод stopService() , который вызовет stopSelf() и, затем, onDestroy() аналогично п.1.
Вот несколько примеров остановки службы из Activity :
И вот код в вашей службе, который будет обрабатывать эти запросы (при условии, что ваша запущенная служба находится на переднем плане):
Привязанные службы
В отличие от запущенных служб, привязанные службы позволяют установить соединение между компонентом Android, привязанным к службе, и службой. Это соединение предоставляется реализацией интерфейса IBinder , который определяет методы для взаимодействия со службой. Простым примером этого может быть реализация привязанной службы в одном процессе с клиентом (т.е. в рамках вашего собственного приложения). В этом случае Java-объект, подкласс Binder , передается клиенту, который может использовать его для вызова методов службы.
В более сложных сценариях, когда необходимо, чтобы интерфейс службы был доступен для разных процессов, для предоставления клиенту интерфейса службы следует воспользоваться объектом Messenger (является ссылкой на объект Handler , который получает обратный вызов для каждого вызова от клиента), благодаря чему со службой можно взаимодействовать с помощью объектов Message . Объект Messenger фактически основан на AIDL (Android Interface Definition Language). Messenger создает очередь из всех запросов клиентов в рамках одного потока, поэтому служба одновременно получает только один запрос. Если необходимо, чтобы служба обрабатывала одновременно сразу несколько запросов, можно использовать AIDL напрямую.
Отличия между привязанной и запущенной службами:
- У клиентского компонента нет соединения с запущенной службой. Он просто использует объекты Intent посредством startService() или stopService() , которые обрабатываются службой в методе onStartCommand() .
- Когда клиентский компонент ( Activity , Fragment или другая служба) соединяются с привязанной службой, они получают реализацию IBinder , посредством которой они могут вызывать методы у привязанной службы.
В любом случае, когда службе (привязанной или запущенной) необходимо отправлять сообщения привязанному клиенту, ей следует использовать что-то вроде LocalBroadcastManager (в том случае, если клиент и служба работают в одном процессе). Привязанные службы обычно не подключаются к привязанному клиентскому компоненту напрямую.
bindService() и onCreate()
Для того, чтобы клиентский компонент стал привязанным к службе, необходимо вызвать bindService() с явным Intent , как и в случае с запущенной службой.
BIND_AUTO_CREATE это наиболее часто встречающийся флаг в случае вызова bindService() . Существуют и другие флаги (например, BIND_DEBUG_UNBIND или BIND_NOT_FOREGROUND ). В случае BIND_AUTO_CREATE у привязанной службы вызывается onCreate() , если служба до этого еще не была создана. Фактически это означает, что служба создается в момент первой привязки к ней.
Как только вызывается bindService() , службе необходимо реагировать на запрос клиента и предоставить ему экземпляр IBinder , посредством которого клиент сможет вызывать методы привязанной службы. В примере выше, это реализуется с помощью ссылки mServiceConnection . Это обратный вызов (callback) ServiceConnection , который привязанная служба будет использовать для уведомления клиента о завершении привязки. Он также позволит клиенту узнать о разрыве соединения со службой.
Другими словами, привязка выполняется асинхронно. bindService() возвращается сразу же и не возвращает клиенту объект IBinder . Для получения объекта IBinder клиенту необходимо создать экземпляр ServiceConnection и передать его в метод bindService() . Интерфейс ServiceConnection включает метод обратного вызова, который система использует для того, чтобы выдать объект IBinder .
Ниже приведен пример реализации ServiceConnection :
Привязка службы
Давайте посмотрим, что происходит на стороне привязанной службы, когда клиент вызывает bindService(Intent) .
В привязанной службе вы должны реализовать метод onBind() , для получения клиентом экземпляра IBinder . Метод ‘onBind()’ будет вызван только один раз, при первой привязке клиента. Для последующих клиентов, система выдаст такой же экземпляр IBinder :
Объект IBinder обеспечивает программный интерфейс, с помощью которого клиенты могут взаимодействовать со службой. Как говорилось выше, самый простой способ реализации IBinder — это расширение класса Binder , экземпляр которого возвращается из метода onBind() :
В примере выше, мы просто используем метод getService() , который просто возвращает Java-объект привязанной службы клиентскому компоненту. Ссылаясь на этот экземпляр IBinder , клиент может вызывать публичные методы у привязанной службы напрямую. Обратите внимание, что эти методы выполняются в клиентском потоке. И в случае Activity или Fragment эти методы будут выполняться в главном потоке. Поэтому стоит быть осторожным с методами в привязанной службе, которые могут блокировать поток или могут стать причиной ANR.
Отвязка от службы и вызов onDestroy()
Чтобы отвязаться от привязанной службы, клиент просто вызывает unbindService(mServiceConnection) . Затем система вызовет onUnbind() в самой службе. И, если у привязанной службы больше нет клиентов, и также, если, служба не является запущенной службой, то система вызывает onDestroy .
Вот как выглядит вызов unbindService() в клиентском компоненте:
В коде выше, метод onStop() в Activity переопределен для вызова unbindService() . В зависимости от требований UX к приложению ваш клиентский компонент может привязываться к службе и отвязываться от нее в методах onStart() и onStop() соответственно, или в любых других методах жизненного цикла клиентских компонентов на ваше усмотрение.
Вот пример как может выглядеть onUnbind() в коде привязанной службы:
Обычно вы вернете false . Но, если вернуть true , то при привязке следующего клиента к службе вместо onBind() будет вызван метод onRebind() .
Привязанные и запущенные службы одновременно
Бывают ситуации, когда вам могут пригодиться службы, которые являются запущенными и вместе с тем могут допускать привязку. В предыдущих разделах, мы показали особенности работы каждого из видов служб. И уже из этих особенностей можно понять, что создание привязанных и запущенных служб одновременно необходимо для реализации особого поведения в момент начала работы со службой и при завершении работы с ней.
Если служба не запущена, то клиент, который хочет привязаться к ней, вызовет onCreate() у службы. Если служба уже запущена, этот метод не вызывается. С другой стороны, если клиент отвязывается от службы и при этом служба не запущенная, то вызывается onDestroy() и служба уничтожается.
Вы можете запустить службу путем вызова метода startService(), вывести ее на передний план и показывать постоянное уведомление. Таким образом, вы реализуете все, что мы говорили о создании запущенных служб. Но кроме того, вы можете реализовать методы, которые позволят клиентам привязываться к службе, с помощью вызова метода bindService() . Особенность такой »двойной» службы в том, что даже при отвязке всех клиентов, служба продолжает свою работу и выполняется до тех пор, пока сама не остановит себя с помощью метода stopSelf() , или до тех пор, пока другой компонент не вызовет метод stopService() .
Переход в запущенное состояние
Поскольку клиент, привязываясь к службе, не переведет ее в запущенное состояние, то для привязанных и запущенных служб одновременно, требуется чтобы служба переходила в запущенное состояние самостоятельно. Вот, как можно это сделать с учетом Android O:
В коде под спойлером:
- Метод commandStart() может быть вызван клиентом, который привязывается к службе.
- Или commandStart() вызывается через методы startService() или startForegroundService() (для Android O).
Но, перед фактическим исполнением работы, служба сначала переводит себя в запущенное состояние.
Итак, когда клиент привязывается к службе, вызывается commandStart() . Служба еще не запущена. Давайте посмотрим на код, и увидим, что случится:
- Если служба привязывается к клиенту, то она не запущена (и в mServiceStarted содержится false )
- В этом случае вызывается moveToStarted() и там создается явный Intent с Extras Command.START , и далее вызывается startService() или startForegroundService() .
- Это приводит к вызову onStartCommand() , который опять вызывает commandStart() .
- Но теперь в commandStart() значение переменной mServiceIsStarted равняется true , и поэтому метод commandStart() выполняет свое прямое предназначение, т.е. запускает полезную работу службы.
Завершение работы службы и отвязывание
Если служба не в запущенном состоянии и клиентский компонент отвязывается от службы, то служба уничтожается и вызывается onDestroy()
Но если она в запущенном состоянии она не уничтожается. И она будет «убита», только если запущенное состояние будет остановлено (через вызов stopService(Intent) или вызов startService(Intent) c Extras в Intent , которые говорят о намерении остановить службу, например Command.STOP ).
Вот диаграмма, в которой суммируются состояния службы и переходы между ними для запущенной и привязанной службы одновременно:
Примеры
Реализацию большинства из того, о чем говорилось в статье, можно глянуть на GitHub.
Это небольшая утилита для Android O и N, которая держит телефон в активном состоянии, если он на зарядке.
Источник