Resumen de servicios

Un Servicecomponente de aplicación que puede realizar operaciones de larga duración en segundo plano. No proporciona una interfaz de usuario. En principio, un servicio puede seguir ejecutándose durante algún 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 e incluso realizar comunicaciones entre procesos (IPC). Por ejemplo, un servicio puede manejar transacciones de red, reproducir música, realizar E/S de archivos o interactuar con un proveedor de contenidos, todo desde el fondo.

Precaución: Un servicio se ejecuta en el hilo principal de su proceso de alojamiento; el servicio no crea su propio hilo y no se ejecuta en un proceso separado a menos que se especifique lo contrario. Debe ejecutar cualquier operación de bloqueo en un hilo separado dentro del servicio para evitar errores de ApplicationNot Responding (ANR).

Tipos de servicios

Estos son los tres tipos diferentes de servicios:

Primer plano

Un servicio en primer plano realiza alguna operación que es perceptible para el usuario. Por ejemplo, una aplicación de audio utilizarí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 está interactuando con la aplicación.

Cuando se utiliza un servicio en primer plano, se debe mostrar una notificación para que los usuarios sean conscientes de que el servicio se está ejecutando. Esta notificación no puede ser descartada a menos que el servicio se detenga o se elimine del primer plano.

Aprenda más sobre cómo configurar los servicios en primer plano en su aplicación.

Nota: La API de WorkManager ofrece una forma flexible de programar tareas, y es capaz de ejecutar estos trabajos como servicios en primer plano si es necesario. En muchos casos, el uso de WorkManager es preferible a utilizar los servicios en primer plano directamente.

En segundo plano Un servicio en segundo plano realiza una operación que no es percibida directamente por el usuario. Por ejemplo, si una aplicación utiliza un servicio para compactar su almacenamiento, que por lo general sería un servicio de fondo.

Nota: Si su aplicación tiene como objetivo el nivel de API 26 o superior, el sistema impone restricciones a la ejecución de servicios en segundo plano cuando la propia aplicación no está en primer plano. En la mayoría de las situaciones, por ejemplo, no deberías acceder a la información de localización desde el fondo. En su lugar, programe las tareas utilizando el WorkManager.

Vinculado Un servicio está vinculado cuando un componente de la aplicación se vincula a él llamando abindService(). Un servicio vinculado ofrece una interfaz cliente-servidor que permite que los componentes interactúen con el servicio, envíen solicitudes, reciban resultados e incluso lo hagan a través de procesos con comunicación interproceso (IPC). Un servicio vinculado sólo se ejecuta mientras otro componente de la aplicación esté vinculado a él. Múltiples componentes pueden vincularse al servicio a la vez, pero cuando todos ellos se desvinculan, el servicio se destruye.

Aunque esta documentación generalmente discute los servicios iniciados y vinculados por separado, su servicio puede funcionar de ambas maneras – puede ser iniciado (para ejecutarse indefinidamente) y también permitir la vinculación. Es simplemente una cuestión 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 su servicio se inicia, se vincula, o ambos, cualquier componente de la aplicación puede utilizar el servicio (incluso desde una aplicación independiente) de la misma manera que cualquier componente puede utilizar una actividad, iniciándola con un Intent. Sin embargo, puede declarar el servicio como privado en el archivo de manifiesto y bloquear el acceso de otras aplicaciones.Esto se discute más en la sección sobre Declarar el servicio en el manifiesto.

Elegir entre un servicio y un hilo

Un servicio es simplemente un componente que puede ejecutarse en segundo plano, incluso cuando el usuario no está interactuando con su aplicación, por lo que debe crear un servicio sólo si eso es lo que necesita.

Si debes realizar un trabajo fuera de tu hilo principal, pero sólo mientras el usuario está interactuando con tu aplicación, debes crear un nuevo hilo en el contexto de otro componente de la aplicación. Por ejemplo, si quieres reproducir algo de música, pero sólo mientras tu actividad se está ejecutando, podrías crear un hilo en onCreate(), comenzar a ejecutarlo en onStart(), y detenerlo en onStop().Considera también el uso de pools de hilos y ejecutores del paquete java.util.concurrent o coroutines de Kotlin en lugar de la clase tradicionalThread. Consulte el documentoThreading on Android para obtener más información sobre el traslado de la ejecución a los hilos de fondo.

Recuerde que si usted utiliza un servicio, todavía se ejecuta en el hilo principal de su aplicación por defecto, por lo que debe crear un nuevo hilo dentro del servicio si realiza operaciones intensivas o de bloqueo.

Los fundamentos

Para crear un servicio, debe crear una subclase de Service o utilizar una de sus subclases existentes. En su implementación, debe anular algunos métodos de devolución de llamada que manejan los aspectos clave del ciclo de vida del servicio y proporcionar un mecanismo que permite a los componentes para enlazar con el servicio, en su caso. Estos son los métodos de devolución de llamada más importantes que debes anular:

onStartCommand()El sistema invoca este método llamando astartService()cuando otro componente (como una actividad) solicita que se inicie el servicio.Cuando este método se ejecuta, el servicio se inicia y puede funcionar en segundo plano indefinidamente. Si implementas esto, es tu responsabilidad detener el servicio cuando su trabajo esté completo llamando astopSelf()ostopService(). Si sólo desea proporcionar la vinculación, no necesita implementar este método.onBind()El sistema invoca este método llamando abindService()cuando otro componente quiere enlazar con el servicio (como para realizar RPC).En su implementación de este método, debe proporcionar una interfaz que los clientes utilizan para comunicarse con el servicio devolviendo unIBinder. Siempre debe implementar este método; sin embargo, si no quiere permitir la vinculación, debe devolvernull.onCreate()El sistema invoca este método para realizar procedimientos de configuración de una sola vez cuando el servicio se crea inicialmente (antes de llamar aonStartCommand()oonBind()). Si el servicio ya se está ejecutando, este método no se llama.onDestroy()El sistema invoca este método cuando el servicio ya no se utiliza y está siendo destruido.Su servicio debe implementar esto para limpiar cualquier recurso como hilos, oyentes registrados o receptores. Esta es la última llamada que recibe el servicio.

Si un componente inicia el servicio llamando a startService() (lo que resulta en una llamada a onStartCommand()), el servicio continúa ejecutándose hasta que se detenga a sí mismo con stopSelf() u otro componente lo detenga llamando a stopService().

Si un componente llama a bindService() para crear el servicio y no se llama a onStartCommand(), el servicio se ejecuta sólo 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 sólo cuando la memoria es baja y debe recuperar los recursos del sistema para la actividad que tiene el foco del usuario. Si el servicio está vinculado a una actividad que tiene el foco del usuario, es menos probable que sea eliminado; si el servicio está declarado para ejecutarse en primer plano, rara vez es eliminado.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 altamente susceptible de ser eliminado-si su servicio se inicia, debe diseñarlo para manejar con gracia los reinicios por el sistema. Si el sistema mata su servicio, lo reinicia tan pronto como los recursos estén disponibles, pero esto también depende del valor que usted devuelva de onStartCommand(). Para más información sobre cuándo el sistema puede destruir un servicio, consulte el documento Processes and Threading.

En las siguientes secciones, verá cómo puede crear los métodos de serviciostartService() ybindService(), así como cómo utilizarlos 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 haces con las actividades y otros componentes.

Para declarar tu servicio, añade un elemento <service>como hijo del elemento <application>. Este es un ejemplo:

<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application></manifest>

Consulte la referencia del elemento <service> para obtener más información sobre cómo declarar su servicio en el manifiesto.

Hay otros atributos que puede incluir en el elemento <service> para definir propiedades como los permisos que se requieren para iniciar el servicio y el proceso en el que el servicio debe ejecutarse. El atributo android:name es el único necesario: especifica el nombre de la clase del servicio. Después de publicar su aplicación, deje este nombre sin cambios para evitar el riesgo de romper el código debido a la dependencia de las intenciones explícitas para iniciar o enlazar el servicio (lea la entrada del blog, ThingsThat Cannot Change).

Precaución: Para garantizar la seguridad de tu aplicación, utiliza siempre una intent explícita al iniciar un Service y no declares filtros de intent para tus servicios. El uso de una intención implícita para iniciar un servicio es un peligro para la seguridad porque no puedes estar seguro del servicio que responde a la intención, y el usuario no puede ver qué servicio se inicia. A partir de Android 5.0 (nivel de API 21), el sistema lanza una excepción si llamas a bindService() con una intención implícita.

Puedes asegurarte de que tu servicio esté disponible sólo para tu aplicación incluyendo el atributo android:exported y estableciéndolo en false. Esto impide que otras aplicaciones inicien su servicio, incluso cuando se utiliza una intención explícita.

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 detener el servicio. Para evitar que los usuarios detengan accidentalmente tu servicio, debes añadir el atributo android:description al elemento <service> del manifiesto de tu aplicación. En la descripción, proporciona una breve frase que explique qué hace el servicio y qué beneficios proporciona.

Crear un servicio iniciado

Un servicio iniciado es aquel que otro componente inicia llamando a startService(), lo que resulta en una llamada al método del servicioonStartCommand().

Cuando se inicia un servicio, tiene un ciclo de vida que es independiente del componente que lo inició. El servicio puede ejecutarse en segundo plano indefinidamente, incluso si el componente que lo inició se destruye. Como tal, el servicio debe detenerse cuando su trabajo está completo llamando a stopSelf(), u 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 especifica el servicio e incluye cualquier dato para el servicio a utilizar. El servicio recibe este Intent en el método onStartCommand().

Por ejemplo, supongamos que una actividad necesita guardar algunos datos en una base de datos en línea. La actividad puede iniciar un servicio compañero y entregarle los datos a guardar pasando una intención a startService(). El servicio recibe la intención en onStartCommand(), se conecta a Internet y realiza la transacción de la base de datos. Cuando la transacción se completa, el servicio se detiene y se destruye.

Precaución: Un servicio se ejecuta en el mismo proceso que la aplicaciónen la que se declara y en el hilo principal de esa aplicación por defecto. Si su 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 el impacto en el rendimiento de la aplicación, inicie un nuevo hilo dentro del servicio.

La clase Service es la clase base para todos los servicios. Cuando extiendas esta clase, es importante crear un nuevo hilo en el que el servicio pueda completar todo su trabajo; el servicio utiliza el hilo principal de tu aplicación por defecto, lo que puede ralentizar el rendimiento de cualquier actividad que tu aplicación esté ejecutando.

El framework de Android también proporciona la subclase IntentService de Service que utiliza un hilo de trabajo para manejar todas las peticiones de inicio, una a una. El uso de esta clase no se recomienda para las nuevas aplicaciones, 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, está obsoleta a partir de Android 11.Puedes utilizar JobIntentService como reemplazo de IntentService que es compatible con las versiones más nuevas de Android.

Las siguientes secciones describen cómo puedes implementar tu propio servicio personalizado, sin embargo, deberías considerar fuertemente el uso de WorkManager en su lugar para la mayoría de los casos de uso. Consulte la guía de procesamiento en segundo plano en Androidpara ver si hay una solución que se adapte a sus necesidades.

Extender la clase Service

Puede extender la clase Servicepara manejar cada intención entrante. Así es como podría verse 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 maneja todas las llamadas entrantes en onStartCommand()y envía el trabajo a un Handler que se ejecuta en un hilo de fondo. Funciona como un IntentService y procesa todas las solicitudes en serie, una tras otra.Podría cambiar el código para ejecutar el trabajo en un grupo de hilos, por ejemplo, si desea ejecutar múltiples solicitudes simultáneamente.

Nótese que el método onStartCommand() debe devolver un entero. El entero es un valor que describe cómo el sistema debe continuar el servicio en el caso de que el sistema lo mate. El valor de retorno de onStartCommand() debe ser una de las siguientes constantes:

START_NOT_STICKYSi el sistema mata el servicio después de queonStartCommand()retorne, no se debe recrear el servicio a menos que haya intentos pendientes de entregar. Esta es la opción más segura para evitar la ejecución de su servicio cuando no es necesario y cuando su aplicación puede simplemente reiniciar cualquier trabajo inacabado.START_STICKYSi el sistema mata el servicio después de que regreseonStartCommand(), vuelva a crear el servicio y llame aonStartCommand(), pero no vuelva a entregar la última intención.En su lugar, el sistema llama aonStartCommand()con una intención nula a menos que haya intenciones pendientes para iniciar el servicio. En ese caso, esas intenciones se entregan. Esto es adecuado para los reproductores de medios (o servicios similares) que no están ejecutando comandos, sino que se ejecutan indefinidamente y esperan un trabajo.START_REDELIVER_INTENTSi el sistema mata el servicio después de queonStartCommand()regrese, vuelva a crear el servicio y llame aonStartCommand()con la última intención que se entregó al servicio. Cualquier intento pendiente se entrega a su vez. Esto es adecuado para los servicios que están realizando activamente un trabajo que debe ser reanudado inmediatamente, como la descarga de un archivo.

Para más detalles sobre estos valores de retorno, consulte la documentación referenciada vinculada para cada constante.

Iniciar un servicio

Puede iniciar un servicio desde una actividad u otro componente de la aplicación pasando un Intent a startService() o startForegroundService(). El sistema Android llama al método onStartCommand() del servicio y le pasa el Intent, que especifica el servicio que debe iniciarse.

Nota: Si su aplicación tiene como objetivo el nivel 26 de la API o superior, el sistema impone restricciones en el uso o la creación de servicios en segundo plano a menos que la propia aplicación esté en primer plano. Si una aplicación necesita crear un servicio en primer plano, debe llamar a startForegroundService(). Ese método crea un servicio en segundo plano, pero el método señala al sistema que el servicio se promoverá a sí mismo al primer plano. Una vez creado el servicio, éste debe llamar a su método startForeground() antes de cinco segundos.

Por ejemplo, una actividad puede iniciar el servicio de ejemplo de la sección anterior (HelloService) utilizando una intención explícita con startService(), como se muestra aquí:

Kotlin

Intent(this, HelloService::class.java).also { intent -> startService(intent)}

Java

Intent intent = new Intent(this, HelloService.class);startService(intent);

El método startService() regresa inmediatamente, y el sistema Android llama al método onStartCommand() del servicio. Si el servicio no se está ejecutando, el sistema primero llama a onCreate(), y luego llama a onStartCommand().

Si el servicio no proporciona también vinculación, la intención 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 quieres que el servicio envíe un resultado de vuelta, el cliente que inicia el servicio puede crear un PendingIntent para una difusión (con getBroadcast()) y entregarlo al servicio en el Intent que inicia el servicio. El servicio puede entonces utilizar el broadcast para entregar un resultado.

Múltiples solicitudes para iniciar el servicio resultan en múltiples llamadas correspondientes al onStartCommand() del servicio. Sin embargo, sólo se requiere una solicitud para detener el servicio (con stopSelf() o stopService()) para detenerlo.

Detener un servicio

Un servicio iniciado debe gestionar su propio ciclo de vida. Es decir, el sistema no se detiene para destruir el servicio a menos que deba recuperar la memoria del sistema y el servicio continúa ejecutándose después de que onStartCommand() regrese. El servicio debe detenerse por sí mismo llamando a stopSelf(), u otro componente puede detenerlo llamando a stopService().

Una vez solicitada la detención con stopSelf() o stopService(), el sistema destruye el servicio tan pronto como sea posible.

Si su servicio maneja múltiples solicitudes a onStartCommand() concurrentemente, no debe detener el servicio cuando termine de procesar una solicitud de inicio, ya que podría haber recibido una nueva solicitud de inicio (parar al final de la primera solicitud terminaría la segunda). Para evitar este problema, puedes utilizar stopSelf(int) para asegurarte de que tu petición de parar el servicio se basa siempre en la petición de inicio más reciente. Es decir, cuando se llama a stopSelf(int), se pasa el ID de la solicitud de inicio (el startIdentregado a onStartCommand()) al que corresponde la solicitud de parada. Entonces, si el servicio recibe una nueva solicitud de inicio antes de que usted pueda llamar a stopSelf(int), el ID no coincide y el servicio no se detiene.

Atención: Para evitar el desperdicio de recursos del sistema y el consumo de energía de la batería, asegúrese de que su aplicación detenga sus servicios cuando haya terminado de trabajar.Si es necesario, otros componentes pueden detener el servicio llamando a stopService(). Incluso si habilita la vinculación para el servicio, siempre debe detener el servicio usted mismo si alguna vez recibe una llamada a onStartCommand().

Para obtener más información sobre el ciclo de vida de un servicio, consulte la sección a continuación sobre la gestión del ciclo de vida de un servicio.

Creación de un servicio vinculado

Un servicio vinculado es uno que permite que los componentes de la aplicación se vinculen a él llamando a bindService() para crear una conexión de larga duración.Por lo general, no permite que los componentes lo inicien llamando a startService().

Cree un servicio enlazado cuando desee interactuar con el servicio desde las actividades y otros componentes de su aplicación o para exponer parte de la funcionalidad de su aplicación a otras aplicaciones a través de la comunicación entre procesos (IPC).

Para crear un servicio enlazado, implemente el método de devolución de llamada onBind() para devolver un IBinder que defina la interfaz para la comunicación con el servicio. Otros componentes de la aplicación pueden entonces llamar a bindService() para recuperar la interfaz y comenzar a llamar a los métodos del servicio. El servicio vive sólo para servir al componente de aplicación que está vinculado a él, por lo que cuando no hay componentes vinculados al servicio, el sistema lo destruye.No es necesario detener un servicio vinculado de la misma manera que cuando el servicio se inicia a través de onStartCommand().

Para crear un servicio vinculado, debe 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 su servicio debe devolver 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.

Múltiples clientes pueden vincularse al servicio simultáneamente. Cuando un cliente ha terminado de interactuar con el servicio, llama a unbindService() para desvincularse.Cuando no hay clientes vinculados al servicio, el sistema destruye el servicio.

Hay múltiples formas de implementar un servicio vinculado, y la implementación es más complicada que un servicio iniciado. Por estas razones, la discusión del servicio vinculado aparece en un documento separado sobre los servicios vinculados.

Envío de notificaciones al usuario

Cuando un servicio se está ejecutando, puede notificar al usuario de eventos utilizando notificaciones Toast o notificaciones de la barra de estado.

Una notificación Toast es un mensaje que aparece en la superficie de la ventana actual por sólo un momento antes de desaparecer. Una notificación de la barra de estado proporciona un icono en la barra de estado con un mensaje, que el usuario puede seleccionar para realizar una acción (como el inicio de una actividad).

Por lo general, una notificación de la barra de estado es la mejor técnica para utilizar cuando el trabajo de fondo como una descarga de archivos ha terminado, y el usuario ahora puede actuar en él. Cuando el usuario selecciona la notificación desde la vista expandida, la notificación puede iniciar una actividad (como mostrar el archivo descargado).

Consulte las guías para desarrolladores de las notificaciones Toast o las notificaciones de la barra de estado para obtener más información.

Gestión del ciclo de vida de un servicio

El ciclo de vida de un servicio es mucho más sencillo que el de una actividad. Sin embargo, es aún más importante que preste atención a cómo se crea y se destruye su 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 estos dos caminos:

  • Un servicio iniciado

    El servicio se crea cuando otro componente llama a startService(). El servicio se ejecuta entonces indefinidamente y debe detenerse por sí mismo llamando a stopSelf(). Otro componente también puede detener el servicio llamando a stopService(). Cuando el servicio se detiene, el sistema lo destruye.

  • Un servicio vinculado

    El servicio se crea cuando otro componente (un cliente) llama a bindService(). El cliente se comunica con el servicio a través de una interfaz IBinder. El cliente puede cerrar la conexión llamando a unbindService(). Varios clientes pueden conectarse al mismo servicio y cuando todos ellos se desconectan, el sistema destruye el servicio. El servicio no necesita detenerse a sí mismo.

Estos dos caminos no están totalmente separados. Se puede enlazar a un servicio que ya está iniciado con startService(). Por ejemplo, puedes iniciar un servicio de música de fondo llamando a startService() con un Intent que identifique la música a reproducir. Más tarde, posiblemente cuando el usuario quiera ejercer algún control sobre el reproductor u 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 detiene el servicio hasta que todos los clientes se desvinculen.

Implementación de las devoluciones de llamada del ciclo de vida

Al igual que una actividad, un servicio tiene métodos de devolución de llamada del ciclo de vida que puedes implementar para supervisar los cambios en el estado del servicio y realizar el trabajo en los momentos adecuados. El siguiente esqueleto de servicio demuestra 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 fun () { // The service is being created } override fun (intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override fun (intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override fun (intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override fun (intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override fun () { // 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 void () { // The service is being created } @Override public int (Intent intent, int flags, int startId) { // The service is starting, due to a call to  return startMode; } @Override public IBinder (Intent intent) { // A client is binding to the service with  return binder; } @Override public boolean (Intent intent) { // All clients have unbound with  return allowRebind; } @Override public void (Intent intent) { // A client is binding to the service with , // after onUnbind() has already been called } @Override public void () { // The service is no longer used and is being destroyed }}

Nota: A diferencia de los métodos de callback del ciclo de vida de la actividad, no es necesario llamar a la implementación de la superclase de estos métodos de callback.

Figura 2. El ciclo de vida del servicio. El diagrama de la izquierda muestra el ciclo de vida cuando el servicio se crea con startService() y el diagrama de la derecha muestra el ciclo de vida cuando el servicio se crea con bindService().

La figura 2 ilustra los métodos de callback típicos de un servicio. Aunque la figura separa los servicios creados por startService() de los creados por bindService(), hay que tener en cuenta que cualquier servicio, independientemente de cómo se inicie, puede permitir potencialmente que los clientes se vinculen a él.Un servicio que se inició inicialmente con onStartCommand() (por un cliente que llama a startService()) todavía puede recibir una llamada a onBind() (cuando un cliente llama abindService()).

Al implementar estos métodos, se pueden monitorizar estos dos bucles anidados del ciclo de vida del servicio:

  • La vida completa de un servicio ocurre entre el momento en que onCreate() es llamado y el momento en que onDestroy() regresa. Al igual que una actividad, un servicio hace su configuración inicial en onCreate() y libera todos los recursos restantes en onDestroy(). Por ejemplo, un servicio de reproducción de música puede crear el hilo en el que se reproduce la música en onCreate(), y luego puede detener el hilo en onDestroy().

    Nota: Los métodos onCreate()y onDestroy() son llamados para todos los servicios, ya sean creados por startService() o bindService().

  • El tiempo de vida activo de un servicio comienza con una llamada a onStartCommand() o onBind().A cada método se le entrega el Intent que se pasó a startService() o bindService().

    Si el servicio se inicia, el tiempo de vida activo termina al mismo tiempo que el tiempo de vida completo (el servicio sigue activo incluso después de que onStartCommand() regrese). Si el servicio está vinculado, el tiempo de vida activo termina cuando onUnbind() regresa.

Nota: Aunque un servicio iniciado se detiene mediante una llamada a stopSelf() o stopService(), no hay una devolución de llamada respectiva para el servicio (no hay devolución de llamada onStop()). A menos que el servicio esté vinculado a un cliente, el sistema lo destruye cuando el servicio se detiene-onDestroy() es la única devolución de llamada que se recibe.

Para obtener más información sobre la creación de un servicio que proporciona vinculación, consulte el documento Servicios vinculados, que incluye más información sobre el método onRebind()de devolución de llamada en la sección sobre Gestión del ciclo de vida de un servicio vinculado.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.