Un Service
es un componente de la aplicación que puede realizar operaciones de larga duración en segundo plano. No proporciona una interfaz de usuario. Una vez iniciado, un servicio puede seguir ejecutándose durante un tiempo, incluso después de que el usuario cambie a otra aplicación. Además, un componente puede vincularse a un servicio para interactuar con él y hasta realizar una comunicación entre procesos (IPC). Por ejemplo, un servicio puede controlar transacciones de red, reproducir música, realizar E/S de archivos o interactuar con un proveedor de contenido, todo en segundo plano.
Precaución: Un servicio se ejecuta en el subproceso principal de su proceso de alojamiento. El servicio no crea su propio subproceso y no se ejecuta en un proceso independiente, a menos que especifiques lo contrario. Debes ejecutar cualquier operación de bloqueo en un subproceso independiente dentro del servicio para evitar errores de la aplicación que no responde (ANR).
Tipos de servicios
Estos son los tres tipos diferentes de servicios:
- Primer plano
-
Un servicio en primer plano realiza alguna operación que el usuario puede detectar. Por ejemplo, una app de audio usaría un servicio en primer plano para reproducir una pista de audio. Los servicios en primer plano deben mostrar una notificación. Los servicios en primer plano continúan ejecutándose incluso cuando el usuario no interactúa con la app.
Cuando usas un servicio en primer plano, debes mostrar una notificación para que los usuarios sepan de forma activa que el servicio se está ejecutando. Esta notificación no se puede descartar, a menos que se detenga el servicio o se quite del primer plano.
Obtén más información para configurar los servicios en primer plano en tu app.
Nota: La API de WorkManager ofrece una forma flexible de programar tareas y puede ejecutar estas tareas como servicios en primer plano si es necesario. En muchos casos, es preferible usar WorkManager que usar directamente los servicios en primer plano.
- Información general
- Un servicio en segundo plano realiza una operación que el usuario no nota directamente. Por ejemplo, si una app usara un servicio para compactar su almacenamiento, por lo general, sería un servicio en segundo plano.
Nota: Si tu app se orienta al nivel de API 26 o versiones posteriores, el sistema impone restricciones para ejecutar servicios en segundo plano cuando la app no está en primer plano. Por ejemplo, en la mayoría de las situaciones, no deberías acceder a la información de ubicación en segundo plano. En su lugar, programa tareas con WorkManager.
- Vinculado
- Un servicio se vincula cuando un componente de la aplicación se vincula a él llamando a
bindService()
. Un servicio vinculado ofrece una interfaz cliente-servidor que permite que los componentes interactúen con el servicio, envíen solicitudes, reciban resultados y, hasta, lo hagan en varios procesos con la comunicación entre procesos (IPC). Un servicio vinculado se ejecuta solo mientras otro componente de la aplicación está vinculado a él. Varios componentes pueden vincularse al servicio a la vez, pero cuando todos se desvinculan, el servicio se destruye.
Aunque en esta documentación se analizan los servicios iniciados y vinculados por separado,
tu servicio puede funcionar de ambas maneras: se puede iniciar (para ejecutarse de forma indefinida) y también permitir vinculación. Simplemente se trata de implementar un par de métodos de devolución de llamada: onStartCommand()
para permitir que los componentes lo inicien y onBind()
para permitir la vinculación.
Independientemente de si tu servicio está iniciado, vinculado o ambas cosas, cualquier componente de la aplicación puede usar el servicio (incluso desde una aplicación independiente) de la misma manera que cualquier componente puede usar una actividad: iniciándolo con un Intent
. Sin embargo, puedes declarar el servicio como privado en el archivo de manifiesto y bloquear el acceso de otras aplicaciones.
Esto se analiza con más detalle en la sección sobre Cómo declarar el servicio en el manifiesto.
Diferencia entre un servicio y un subproceso
Un servicio es simplemente un componente que se puede ejecutar en segundo plano, incluso cuando el usuario no interactúa con tu aplicación, por lo que debes crear un servicio solo si eso es lo que necesitas.
Si debes realizar tareas fuera de tu subproceso principal, pero solo mientras el usuario interactúa con tu aplicación, debes crear un subproceso nuevo en el contexto de otro componente de la aplicación. Por ejemplo, si quieres reproducir música, pero solo mientras se ejecuta tu actividad, puedes crear un subproceso en onCreate()
, comenzar a ejecutarlo en onStart()
y detenerlo en onStop()
.
También considera usar grupos de subprocesos y ejecutores del paquete java.util.concurrent
o las corrutinas de Kotlin en lugar de la clase Thread
tradicional. Consulta el documento Cómo ejecutar subprocesos en Android para obtener más información sobre cómo mover la ejecución a subprocesos en segundo plano.
Recuerda que, si usas un servicio, este se ejecutará en el subproceso principal de tu aplicación de forma predeterminada, por lo que debes crear un subproceso nuevo dentro del servicio si realiza operaciones intensivas o de bloqueo.
Conceptos básicos
Para crear un servicio, debes crear una subclase de Service
o usar una de sus subclases existentes. En tu implementación, debes anular algunos métodos de devolución de llamada que controlan aspectos clave del ciclo de vida del servicio y proporcionan un mecanismo que permite que los componentes se vinculen al servicio, si corresponde. Estos son los métodos de devolución de llamada más importantes que debes
superar:
onStartCommand()
- El sistema invoca este método llamando a
startService()
cuando otro componente (como una actividad) solicita que se inicie el servicio. Cuando se ejecuta este método, se inicia el servicio y puede ejecutarse en segundo plano de forma indefinida. Si implementas esto, es tu responsabilidad detener el servicio cuando se complete su trabajo llamando astopSelf()
ostopService()
. Si solo quieres proporcionar una vinculación, no es necesario que implementes este método. onBind()
- El sistema invoca este método llamando a
bindService()
cuando otro componente quiere vincularse con el servicio (por ejemplo, para realizar una RPC). En la implementación de este método, debes proporcionar una interfaz que los clientes usen para comunicarse con el servicio mostrando unIBinder
. Siempre debes implementar este método. Sin embargo, si no quieres permitir la vinculación, debes mostrar un valor nulo. onCreate()
- El sistema invoca este método para realizar procedimientos de configuración únicos cuando se crea el servicio inicialmente (antes de llamar a
onStartCommand()
oonBind()
). Si el servicio ya se está ejecutando, no se llama a este método. onDestroy()
- El sistema invoca este método cuando el servicio ya no se usa y se destruye. Tu servicio debe implementar esto para limpiar cualquier recurso, como subprocesos, objetos de escucha registrados o receptores. Esta es la última llamada que el servicio recibe.
Si un componente inicia el servicio llamando a startService()
(lo que genera una llamada a onStartCommand()
), el servicio sigue ejecutándose hasta que se detiene por sí mismo con stopSelf()
o cuando otro componente lo detiene llamando a stopService()
.
Si un componente llama a bindService()
para crear el servicio y no se llama a onStartCommand()
, el servicio se ejecuta solo mientras el componente esté vinculado a él. Después de que el servicio se desvincula de todos sus clientes, el sistema lo destruye.
El sistema Android detiene un servicio solo cuando hay poca memoria y debe recuperar los recursos del sistema para la actividad que tiene el enfoque del usuario. Si el servicio está vinculado a una actividad que tiene el enfoque del usuario, es menos probable que se cancele. Si se declara que el servicio se ejecuta en primer plano, rara vez se cancela.
Si el servicio se inicia y es de larga duración, el sistema baja su posición en la lista de tareas en segundo plano con el tiempo, y el servicio se vuelve muy susceptible a que se cancele. Si se inicia, debes diseñarlo para que controle de forma fluida los reinicios del sistema. Si el sistema finaliza tu servicio, lo reinicia en cuanto los recursos están disponibles, pero esto también depende del valor que devuelvas desde onStartCommand()
. Para obtener más información sobre cuándo el sistema podría destruir un servicio, consulta el documento Processes and Threading.
En las siguientes secciones, verás cómo puedes crear los métodos de servicio startService()
y bindService()
, así como cómo usarlos desde otros componentes de la aplicación.
Declarar un servicio en el manifiesto
Debes declarar todos los servicios en el archivo de manifiesto de tu aplicación, al igual que lo haces con las actividades y otros componentes.
Para declarar tu servicio, agrega un elemento <service>
como elemento secundario del elemento <application>
. A continuación, se muestra un ejemplo:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Consulta la referencia del elemento <service>
para obtener más información sobre cómo declarar tu servicio en el manifiesto.
Hay otros atributos que puedes incluir en el elemento <service>
para definir propiedades, como los permisos necesarios para iniciar el servicio y el proceso en el que se debe ejecutar. El atributo android:name
es el único atributo obligatorio, ya que especifica el nombre de clase del servicio. Después de publicar tu aplicación, no cambies este nombre para evitar el riesgo de dañar el código debido a la dependencia de intents explícitos para iniciar o vincular el servicio (lee la entrada de blog Elementos que no se pueden modificar).
Precaución: Para garantizar que tu app sea segura, siempre usa un intent explícito cuando inicies un Service
y no declares filtros de intent para tus servicios. El uso de un intent implícito para iniciar un servicio es un riesgo de seguridad porque no puedes estar seguro de qué servicio responderá al intent, y el usuario no puede ver qué servicio se inicia. A partir de Android 5.0 (nivel de API 21), el sistema arroja una excepción si llamas a bindService()
con un intent implícito.
Para garantizar que tu servicio esté disponible solo para tu app,
incluye el atributo android:exported
y configúralo en false
. Esto evita que otras apps inicien tu servicio, incluso cuando se usa un intent explícito.
Nota: Los usuarios pueden ver qué servicios se están ejecutando en su dispositivo. Si ven un servicio que no reconocen o en el que no confían, pueden detenerlo. Para evitar que los usuarios detengan tu servicio por accidente, debes agregar el atributo android:description
al elemento <service>
en el manifiesto de tu app. En la descripción, proporciona una oración breve que explique qué hace el servicio y qué beneficios brinda.
Crear un servicio iniciado
Un servicio iniciado es aquel que otro componente inicia llamando a startService()
, lo que genera una llamada al método onStartCommand()
del servicio.
Cuando se inicia un servicio, tiene un ciclo de vida independiente del componente que lo inició. El servicio puede ejecutarse en segundo plano de forma indefinida, incluso si se destruye el componente que lo inició. Por lo tanto, el servicio debería detenerse por sí mismo cuando se complete su trabajo llamando a stopSelf()
, o bien otro componente puede detenerlo llamando a stopService()
.
Un componente de la aplicación, como una actividad, puede iniciar el servicio llamando a startService()
y pasando un Intent
que especifique el servicio y que incluya los datos que este debe usar. El servicio recibe esta Intent
en el método onStartCommand()
.
Por ejemplo, imagina que una actividad necesita guardar datos en una base de datos en línea. La actividad puede iniciar un servicio complementario y enviarle los datos que se guardarán pasando un intent a startService()
. El servicio recibe el intent en onStartCommand()
, se conecta a Internet y realiza la transacción de la base de datos. Cuando se completa la transacción, el servicio se detiene y se destruye.
Precaución: Un servicio se ejecuta en el mismo proceso que la aplicación en la que se declara y en el subproceso principal de esa aplicación de forma predeterminada. Si tu servicio realiza operaciones intensivas o de bloqueo mientras el usuario interactúa con una actividad de la misma aplicación, el servicio ralentiza el rendimiento de la actividad. Para evitar afectar el rendimiento de la aplicación, inicia un subproceso nuevo dentro del servicio.
La clase Service
es la clase básica para todos los servicios. Cuando extiendes esta clase, es importante crear un subproceso nuevo en el que el servicio pueda completar todo su trabajo. De forma predeterminada, el servicio usa el subproceso principal de tu aplicación, lo que puede ralentizar el rendimiento de cualquier actividad que ejecute tu aplicación.
El framework de Android también proporciona la subclase IntentService
de Service
que usa un subproceso de trabajo para controlar todas las solicitudes de inicio, una a la vez. No se recomienda usar esta clase para apps nuevas, ya que no funcionará bien a partir de Android 8 Oreo debido a la introducción de los límites de ejecución en segundo plano.
Además, dejó de estar disponible a partir de Android 11.
Puedes usar JobIntentService como reemplazo de IntentService
que es compatible con versiones más recientes de Android.
En las siguientes secciones, se describe cómo puedes implementar tu propio servicio personalizado. Sin embargo, debes considerar usar WorkManager en su lugar para la mayoría de los casos de uso. Consulta la guía de procesamiento en segundo plano en Android para ver si hay una solución que se adapte a tus necesidades.
Extender la clase Service
Puedes extender la clase Service
para controlar cada intent entrante. Así es como se vería una implementación básica:
Kotlin
class HelloService : Service() { private var serviceLooper: Looper? = null private var serviceHandler: ServiceHandler? = null // Handler that receives messages from the thread private inner class ServiceHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000) } catch (e: InterruptedException) { // Restore interrupt status. Thread.currentThread().interrupt() } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1) } } override fun onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply { start() // Get the HandlerThread's Looper and use it for our Handler serviceLooper = looper serviceHandler = ServiceHandler(looper) } } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show() // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job serviceHandler?.obtainMessage()?.also { msg -> msg.arg1 = startId serviceHandler?.sendMessage(msg) } // If we get killed, after returning from here, restart return START_STICKY } override fun onBind(intent: Intent): IBinder? { // We don't provide binding, so return null return null } override fun onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show() } }
Java
public class HelloService extends Service { private Looper serviceLooper; private ServiceHandler serviceHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread().interrupt(); } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work doesn't disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler serviceLooper = thread.getLooper(); serviceHandler = new ServiceHandler(serviceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = serviceHandler.obtainMessage(); msg.arg1 = startId; serviceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don't provide binding, so return null return null; } @Override public void onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); } }
El código de ejemplo controla todas las llamadas entrantes en onStartCommand()
y publica el trabajo en un Handler
que se ejecuta en un subproceso en segundo plano. Funciona como un IntentService
y procesa todas las solicitudes de forma serial, una tras otra.
Puedes cambiar el código para que ejecute el trabajo en un grupo de subprocesos, por ejemplo, si deseas ejecutar varias solicitudes de forma simultánea.
Ten en cuenta que el método onStartCommand()
debe mostrar un número entero. El número entero es un valor que describe cómo el sistema debe continuar el servicio en el caso de que lo cancele. El valor que se muestra de onStartCommand()
debe ser una de las siguientes constantes:
START_NOT_STICKY
- Si el sistema cancela el servicio después de que se devuelve
onStartCommand()
, no vuelvas a crearlo, a menos que haya intents pendientes para entregar. Esta es la opción más segura para evitar que se ejecute tu servicio cuando no sea necesario y cuando tu aplicación pueda reiniciar cualquier trabajo sin terminar. START_STICKY
- Si el sistema finaliza el servicio después de que se muestra
onStartCommand()
, vuelve a crear el servicio y llama aonStartCommand()
, pero no vuelvas a entregar el último intent. En su lugar, el sistema llama aonStartCommand()
con un intent nulo, a menos que haya intents pendientes para iniciar el servicio. En ese caso, se entregan esos intents. Esto es adecuado para reproductores multimedia (o servicios similares) que no ejecutan comandos, pero se ejecutan de forma indefinida y esperan una tarea. START_REDELIVER_INTENT
- Si el sistema cierra el servicio después de que se muestra
onStartCommand()
, vuelve a crearlo y llama aonStartCommand()
con el último intent que se entregó al servicio. A su vez, se entregarán todas las intents pendientes. Esto es adecuado para los servicios que realizan de forma activa una tarea que se debe reanudar de inmediato, como descargar un archivo.
Para obtener más detalles sobre estos valores que se devuelven, consulta la documentación de referencia vinculada de cada constante.
Cómo iniciar un servicio
Para iniciar un servicio desde una actividad o algún otro componente de la aplicación, pasa un Intent
a startService()
o startForegroundService()
. El sistema Android llama al método onStartCommand()
del servicio y le pasa el Intent
, que especifica qué servicio iniciar.
Nota: Si tu app se orienta al nivel de API 26 o versiones posteriores, el sistema impone restricciones para usar o crear servicios en segundo plano, a menos que la app esté en primer plano. Si una app necesita crear un servicio en primer plano, debe llamar a startForegroundService()
. Ese método crea un servicio en segundo plano, pero el método le indica al sistema que el servicio se promocionará a primer plano. Una vez creado el servicio, este debe llamar a su método startForeground()
en un plazo de cinco segundos.
Por ejemplo, una actividad puede iniciar el servicio de ejemplo de la sección anterior (HelloService
) con un intent explícito con startService()
, como se muestra a continuación:
Kotlin
startService(Intent(this, HelloService::class.java))
Java
startService(new Intent(this, HelloService.class));
El método startService()
se muestra de inmediato, y el sistema Android llama al método onStartCommand()
del servicio. Si el servicio aún no se está ejecutando, el sistema primero llama a onCreate()
y, luego, a onStartCommand()
.
Si el servicio tampoco proporciona vinculación, el intent que se entrega con startService()
es el único modo de comunicación entre el componente de la aplicación y el servicio. Sin embargo, si deseas que el servicio envíe un resultado, el cliente que inicia el servicio puede crear un PendingIntent
para una transmisión (con getBroadcast()
) y entregarlo al servicio en el Intent
que inicia el servicio. Luego, el servicio puede usar la transmisión para entregar un resultado.
Varias solicitudes para iniciar el servicio generan varias llamadas correspondientes al onStartCommand()
del servicio. Sin embargo, solo se requiere una solicitud para detener el servicio (con stopSelf()
o stopService()
).
Cómo detener un servicio
Un servicio iniciado debe administrar su propio ciclo de vida. Es decir, el sistema no detiene ni destruye el servicio, a menos que deba recuperar la memoria del sistema, y el servicio continúa ejecutándose después de que se muestra onStartCommand()
. El servicio debe detenerse por sí mismo llamando a stopSelf()
, o bien otro componente puede detenerlo llamando a stopService()
.
Una vez que se solicita que se detenga con stopSelf()
o stopService()
, el sistema destruye el servicio lo antes posible.
Si tu servicio controla varias solicitudes a onStartCommand()
de forma simultánea, no debes detener el servicio cuando termines de procesar una solicitud de inicio, ya que es posible que hayas recibido una solicitud de inicio nueva (detenerte al final de la primera solicitud finalizaría la segunda). Para evitar este problema, puedes usar stopSelf(int)
para asegurarte de que tu solicitud para detener el servicio siempre se base en la solicitud de inicio más reciente. Es decir, cuando llamas a stopSelf(int)
, pasas el ID de la solicitud de inicio (el startId
que se entrega a onStartCommand()
) al que corresponde tu solicitud de detención. Luego, si el servicio recibe una nueva solicitud de inicio antes de que puedas llamar a stopSelf(int)
, el ID no coincide y el servicio no se detiene.
Precaución: Para evitar desperdiciar recursos del sistema y consumir energía de la batería, asegúrate de que tu aplicación detenga sus servicios cuando termine de funcionar.
Si es necesario, otros componentes pueden detener el servicio llamando a stopService()
. Incluso si habilitas la vinculación para el servicio, siempre debes detenerlo por tu cuenta si recibe una llamada a onStartCommand()
.
Para obtener más información sobre el ciclo de vida de un servicio, consulta la siguiente sección sobre Cómo administrar el ciclo de vida de un servicio.
Cómo crear un servicio enlazado
Un servicio vinculado es aquel que permite que los componentes de la aplicación se vinculen a él llamando a bindService()
para crear una conexión duradera.
Por lo general, no permite que los componentes lo inicien llamando a startService()
.
Crea un servicio vinculado cuando quieras interactuar con el servicio desde actividades y otros componentes de tu aplicación, o bien exponer algunas de sus funciones a otras aplicaciones a través de la comunicación entre procesos (IPC).
Para crear un servicio vinculado, implementa el método de devolución de llamada onBind()
para mostrar un IBinder
que defina la interfaz para la comunicación con el servicio. Luego, otros componentes de la aplicación pueden llamar a bindService()
para recuperar la interfaz y comenzar a llamar a métodos en el servicio. El servicio solo existe para entregar el componente de la aplicación que está vinculado a él, por lo que, cuando no hay componentes vinculados al servicio, el sistema lo destruye.
No es necesario que detengas un servicio vinculado de la misma manera que lo debes hacer cuando se inicia a través de onStartCommand()
.
Para crear un servicio vinculado, debes definir la interfaz que especifica cómo un cliente puede comunicarse con el servicio. Esta interfaz entre el servicio y un cliente debe ser una implementación de IBinder
y es lo que tu servicio debe mostrar desde el método de devolución de llamada onBind()
. Después de que el cliente recibe el IBinder
, puede comenzar a interactuar con el servicio a través de esa interfaz.
Se pueden enlazar varios clientes al servicio a la vez. Cuando un cliente termina de interactuar con el servicio, llama a unbindService()
para desvincularse.
Cuando ya no hay clientes enlazados con el servicio, el sistema lo destruye.
Existen varias formas de implementar un servicio vinculado, y la implementación es más complicada que la de un servicio iniciado. Por estos motivos, el análisis de los servicios vinculados aparece en un documento independiente sobre los Servicios Vinculados.
Enviar notificaciones al usuario
Cuando un servicio se está ejecutando, puede notificar al usuario sobre eventos con notificaciones de la barra de notificaciones o notificaciones de la barra de estado.
Una notificación de la barra de notificaciones es un mensaje que aparece en la superficie de la ventana actual solo por un momento antes de desaparecer. Una notificación de la barra de estado proporciona un ícono en la barra de estado con un mensaje que el usuario puede seleccionar para realizar una acción (como iniciar una actividad).
Por lo general, una notificación de la barra de estado es la mejor técnica para usar cuando se completa una tarea en segundo plano, como una descarga de archivo, y el usuario ahora puede realizar acciones en función de ella. Cuando el usuario selecciona la notificación de la vista expandida, esta puede iniciar una actividad (como mostrar el archivo descargado).
Administrar el ciclo de vida de un servicio
El ciclo de vida de un servicio es mucho más simple que el de una actividad. Sin embargo, es aún más importante que prestes mucha atención a cómo se crea y destruye tu servicio, ya que un servicio puede ejecutarse en segundo plano sin que el usuario lo sepa.
El ciclo de vida del servicio, desde que se crea hasta que se destruye, puede seguir cualquiera de estas dos rutas:
- Un servicio iniciado
El servicio se crea cuando otro componente llama a
startService()
. Luego, el servicio se ejecuta de forma indefinida y debe detenerse llamando astopSelf()
. Otro componente también puede detener el servicio llamando astopService()
. Una vez que se detiene el servicio, el sistema lo destruye. - Un servicio enlazado
El servicio se crea cuando otro componente (un cliente) llama a
bindService()
. Luego, el cliente se comunica con el servicio a través de una interfazIBinder
. El cliente puede cerrar la conexión llamando aunbindService()
. Varios clientes pueden vincularse al mismo servicio y, cuando todos se desvinculan, el sistema destruye el servicio. El servicio no se debe detener.
Estas dos rutas no están completamente separadas. Puedes vincularte a un servicio que ya se inició con startService()
. Por ejemplo, puedes iniciar un servicio de música en segundo plano llamando a startService()
con un Intent
que identifique la música que se reproducirá. Más adelante, posiblemente cuando el usuario quiera ejercer algún control sobre el reproductor o obtener información sobre la canción actual, una actividad puede vincularse al servicio llamando a bindService()
. En casos como este, stopService()
o stopSelf()
no detienen el servicio hasta que se desvinculan todos los clientes.
Implementar devoluciones de llamada del ciclo de vida
Al igual que una actividad, un servicio tiene métodos de devolución de llamada de ciclo de vida que puedes implementar para supervisar los cambios en el estado del servicio y realizar tareas en los momentos adecuados. En el siguiente servicio de esqueleto, se muestra cada uno de los métodos del ciclo de vida:
Kotlin
class ExampleService : Service() { private var startMode: Int = 0 // indicates how to behave if the service is killed private var binder: IBinder? = null // interface for clients that bind private var allowRebind: Boolean = false // indicates whether onRebind should be used override funonCreate
() { // The service is being created } override funonStartCommand
(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind
(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind
(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind
(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy
() { // The service is no longer used and is being destroyed } }
Java
public class ExampleService extends Service { int startMode; // indicates how to behave if the service is killed IBinder binder; // interface for clients that bind boolean allowRebind; // indicates whether onRebind should be used @Override public voidonCreate
() { // The service is being created } @Override public intonStartCommand
(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()
return startMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return binder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return allowRebind; } @Override public voidonRebind
(Intent intent) { // A client is binding to the service withbindService()
, // after onUnbind() has already been called } @Override public voidonDestroy
() { // The service is no longer used and is being destroyed } }
Nota: A diferencia de los métodos de devolución de llamada del ciclo de vida de la actividad, no es necesario que llames a la implementación de la superclase de estos métodos de devolución de llamada.
En la figura 2, se ven los métodos de devolución de llamada habituales de un servicio. Aunque la figura separa los servicios que crea startService()
de los que crea bindService()
, ten en cuenta que cualquier servicio, independientemente de cómo se inicie, puede permitir que los clientes se vinculen a él.
Un servicio que se inició inicialmente con onStartCommand()
(a través de un cliente que llama a startService()
) aún puede recibir una llamada a onBind()
(cuando un cliente llama a bindService()
).
Si implementas estos métodos, puedes supervisar estos dos bucles anidados del ciclo de vida del servicio:
- La vida útil completa de un servicio ocurre entre el momento en que se llama a
onCreate()
y el momento en que se muestraonDestroy()
. Al igual que una actividad, un servicio realiza su configuración inicial enonCreate()
y libera todos los recursos restantes enonDestroy()
. Por ejemplo, un servicio de reproducción de música puede crear el subproceso en el que se reproduce la música enonCreate()
y, luego, detenerlo enonDestroy()
.Nota: Se llama a los métodos
onCreate()
yonDestroy()
para todos los servicios, ya sea que los creestartService()
obindService()
. - La vida activa de un servicio comienza con una llamada a
onStartCommand()
oonBind()
. A cada método se le entrega elIntent
que se pasó astartService()
obindService()
.Si se inicia el servicio, la vida útil activa finaliza al mismo tiempo que finaliza la vida útil completa (el servicio sigue activo incluso después de que se muestra
onStartCommand()
). Si el servicio está vinculado, la vida útil activa finaliza cuando se muestraonUnbind()
.
Nota: Aunque una llamada a stopSelf()
o stopService()
detenga un servicio iniciado, no hay una devolución de llamada respectiva para el servicio (no hay una devolución de llamada a onStop()
). A menos que el servicio esté vinculado a un cliente, el sistema lo destruye cuando se detiene. onDestroy()
es la única devolución de llamada que se recibe.
Para obtener más información sobre cómo crear un servicio que proporcione vinculación, consulta el documento Servicios vinculados, que incluye más información sobre el método de devolución de llamada onRebind()
en la sección sobre Cómo administrar el ciclo de vida de un servicio vinculado.