Descripción general de los servicios

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 que se inicia, 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 e incluso establecer 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 hosting; el servicio no crea su propio subproceso y no se ejecuta en un proceso separado, a menos que especifiques lo contrario. Debes ejecutar las operaciones de bloqueo en un subproceso separado dentro del servicio para evitar errores de Aplicación no responde (ANR).

Tipos de objetos Service

Estos son los tres tipos diferentes de servicios:

Primer plano

Un servicio en primer plano realiza una operación que el usuario puede notar. 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 deja de interactuar con la app.

Cuando usas un servicio en primer plano, debes mostrar una notificación para que los usuarios sepan de forma activa que se está ejecutando el servicio. Esta notificación no se puede descartar, a menos que el servicio se detenga o se quite del primer plano.

Obtén más información para configurar los servicios en primer plano de tu app.

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

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 está orientada al nivel de API 26 o superior, 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 debes acceder a la información de ubicación en segundo plano. En su lugar, programa las tareas con WorkManager.

Enlace
Un servicio está vinculado 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 todos los procesos con comunicación entre procesos (IPC). Un servicio vinculado se ejecuta solo mientras otro componente de aplicación esté vinculado a él. Se pueden enlazar varios componentes con el servicio a la vez, pero cuando todos se desenlazan, el servicio se destruye.

Si bien, por lo general, en esta documentación se analizan los servicios iniciados y vinculados por separado, tu servicio puede funcionar en ambos sentidos: puede iniciarse (para ejecutarse de forma indefinida) y, además, permitir la vinculación. Solo es 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 tu servicio está iniciado, vinculado o ambos, cualquier componente de la aplicación puede usarlo (incluso desde una aplicación independiente) de la misma manera que cualquier componente puede usar una actividad: al iniciarla 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 explica con más detalle en la sección 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 está interactuando con tu aplicación, por lo que solo debes crear un servicio si eso es lo que necesitas.

Si debes realizar trabajos fuera del 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(). Además, considera usar conjuntos de subprocesos y ejecutores del paquete java.util.concurrent o corrutinas de Kotlin en lugar de la clase Thread tradicional. Consulta el documento Cómo ejecutar subprocesos en Android si quieres obtener más información para mover la ejecución a subprocesos en segundo plano.

Recuerda que, si usas un servicio, este se ejecuta en el subproceso principal de tu aplicación de forma predeterminada, por lo que debes crear un subproceso nuevo dentro del servicio si este 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 manejen aspectos clave del ciclo de vida del servicio y proporcionar un mecanismo que permita que los componentes se vinculen al servicio, si corresponde. Estos son los métodos de devolución de llamada más importantes que debes anular:

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, el servicio se inicia y se puede ejecutar en segundo plano de forma indefinida. Si implementas esto, es tu responsabilidad detener el servicio cuando su trabajo esté completo. Para ello, llama a stopSelf() o stopService(). Si solo deseas proporcionar vinculaciones, no necesitas implementar este método.
onBind()
El sistema invoca a este método llamando a bindService() cuando otro componente quiere vincularse con el servicio (por ejemplo, para realizar RPC). En la implementación de este método, debes proporcionar una interfaz que los clientes usen para comunicarse con el servicio mostrando un IBinder. Siempre debes implementar este método; sin embargo, si no deseas permitir los enlaces, debes mostrar un valor nulo.
onCreate()
El sistema invoca a este método para realizar procedimientos de configuración únicos cuando el servicio se crea por primera vez (antes de llamar a onStartCommand() o onBind()). Si el servicio ya se está ejecutando, no se llama a este método.
onDestroy()
El sistema invoca a 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 da como resultado una llamada a onStartCommand()), el servicio continúa ejecutándose hasta que se detiene a sí mismo con stopSelf() o hasta que 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. Una vez 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 enfocada en el usuario, es menos probable que finalice. Si se declara que el servicio se ejecuta en primer plano, rara vez se cierra. Si se inicia el servicio y se ejecuta durante mucho tiempo, el sistema baja su posición en la lista de las tareas en segundo plano con el tiempo, y el servicio se vuelve muy susceptible de finalizar. Si se inicia tu servicio, debes diseñarlo para que el sistema controle de forma correcta los reinicios. Si el sistema cierra el servicio, lo reinicia en cuanto los recursos están disponibles. Sin embargo, también depende del valor que muestres desde onStartCommand(). Para obtener más información sobre los casos en los que el sistema puede destruir un servicio, consulta el documento Procesos y subprocesos.

En las siguientes secciones, verás cómo puedes crear los métodos de servicio startService() y bindService(), además de 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, tal como lo haces con las actividades y otros componentes.

Para declarar tu servicio, agrega un elemento <service> como elemento secundario de <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> a fin de definir propiedades, como los permisos necesarios para iniciar el servicio y el proceso en el que se debe ejecutar el servicio. El atributo android:name es el único obligatorio, ya que especifica el nombre de clase del servicio. Después de publicar tu aplicación, no cambies el nombre para evitar el riesgo de romper el código debido a la dependencia de intents explícitos para iniciar o vincular el servicio (lee la entrada de blog Cosas que no pueden cambiar).

Precaución: Para garantizar que tu app sea segura, siempre usa un intent explícito cuando inicies un Service y no declares filtros de intents 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 responde 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.

Si quieres asegurarte de que el servicio esté disponible solo para tu app, incluye el atributo android:exported y configúralo en false. Esto impide que otras apps inicien tu servicio, incluso cuando se usa un intent explícito.

Nota: Los usuarios pueden ver qué servicios se ejecutan en su dispositivo. Si ve un servicio que no reconoce o en el que no confía, puede detenerlo. Para evitar que los usuarios detengan accidentalmente tu servicio, debes agregar el atributo android:description al elemento <service> en el manifiesto de tu app. En la descripción, escribe una oración breve para explicar qué hace el servicio y qué beneficios proporciona.

Crear un servicio iniciado

Un servicio iniciado es un servicio que otro componente inicia llamando a startService(), lo que da como resultado una llamada al método onStartCommand() del servicio.

Cuando se inicia un servicio, este tiene un ciclo de vida independiente del componente que lo inició. El servicio puede ejecutarse en segundo plano de manera indefinida, incluso si se destruye el componente que lo inició. Por lo tanto, el servicio debe detenerse a sí mismo cuando se completa su trabajo mediante una llamada a stopSelf(), o bien otro componente puede detenerlo llamando a stopService().

Un componente de una aplicación, como una actividad, puede iniciar el servicio llamando a startService() y pasando una Intent que especifique el servicio e incluya datos para que este utilice. El servicio recibe este 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 enviar 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 a sí mismo y se destruye.

Precaución: Un servicio se ejecuta en el mismo proceso que la aplicación en la que está declarado 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 desde 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 base para todos los servicios. Cuando extiendes esta clase, es importante que crees un subproceso nuevo, en el que el servicio pueda completar todo su trabajo. El servicio usa el subproceso principal de tu aplicación de forma predeterminada, 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 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, dejará de estar disponible a partir de Android 11. Puedes usar JobIntentService para reemplazar IntentService, que es compatible con las versiones más recientes de Android.

En las siguientes secciones, se describe cómo implementar tu propio servicio personalizado. Sin embargo, debes considerar usar WorkManager en la mayoría de los casos de uso. Consulta la guía para el procesamiento en segundo plano en Android para ver si existe 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 igual que IntentService y procesa todas las solicitudes en serie, una tras otra. Puedes cambiar el código para ejecutar el trabajo en un conjunto de subprocesos, por ejemplo, si quieres ejecutar varias solicitudes simultáneamente.

Ten en cuenta que el método onStartCommand() debe mostrar un número entero. El número entero es un valor que describe la manera en que el sistema debe continuar el servicio en caso de que el sistema lo cierre. El valor que se muestra de onStartCommand() debe ser una de las siguientes constantes:

START_NOT_STICKY
Si el sistema cierra el servicio después de que se muestra onStartCommand(), no vuelvas a crear el servicio, a menos que haya intents pendientes para entregar. Esta es la opción más segura para evitar que tu servicio se ejecute cuando no es necesario y cuando tu aplicación puede simplemente reiniciar los trabajos sin terminar.
START_STICKY
Si el sistema cierra el servicio después de que se muestra onStartCommand(), vuelve a crear el servicio y llama a onStartCommand(), pero no vuelvas a entregar el último intent. En cambio, el sistema llama a onStartCommand() 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 un trabajo.
START_REDELIVER_INTENT
Si el sistema cierra el servicio después de que se muestra onStartCommand(), vuelve a crearlo y llama a onStartCommand() con el último intent que se entregó al servicio. A su vez, se entregarán todas las intents pendientes. Esto es adecuado para servicios que ejecutan activamente un trabajo y deben reanudarse de inmediato, como descargar un archivo.

Para obtener más detalles sobre estos valores que se muestran, consulta la documentación de referencia vinculada de cada constante.

Cómo iniciar un servicio

Puedes 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 qué servicio iniciar.

Nota: Si tu app se orienta a niveles de API 26 o superiores, el sistema impone restricciones sobre el uso o la creación de servicios en segundo plano, a menos que la app misma se encuentre 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 le indica al sistema que el servicio se promocionará en primer plano. Una vez que se crea el servicio, debe llamar a su método startForeground() en los siguientes cinco segundos.

Por ejemplo, una actividad puede iniciar el servicio de ejemplo de la sección anterior (HelloService) utilizando 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));

Se muestra inmediatamente el método startService(), 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 no proporciona también la 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 devuelva 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 utilizar la transmisión para entregar un resultado.

Cuando se realizan múltiples solicitudes para iniciar el servicio, se generan varias llamadas correspondientes al onStartCommand() del servicio. Sin embargo, solo se necesita una solicitud de detención del servicio (con stopSelf() o stopService()) para detenerlo.

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 memoria del sistema, y el servicio continúa ejecutándose después de que se muestra onStartCommand(). El servicio debe detenerse a sí mismo llamando a stopSelf(), o bien otro componente puede detenerlo llamando a stopService().

Una vez que se solicita la detención 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 detenerlo cuando termines de procesar una solicitud de inicio, ya que podrías haber recibido una nueva (la detención al final de la primera solicitud interrumpiría la segunda). Para evitar este problema, puedes usar stopSelf(int) a fin de 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 entregado 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 coincidirá y el servicio no se detendrá.

Precaución: Para evitar desperdiciar recursos del sistema y consumir energía de la batería, asegúrate de que la aplicación detenga sus servicios cuando haya terminado 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 detener el servicio por tu cuenta si alguna vez recibe una llamada a onStartCommand().

Para obtener más información sobre el ciclo de vida de un servicio, consulta la sección Cómo administrar el ciclo de vida de un servicio que aparece a continuación.

Cómo crear un servicio enlazado

Un servicio vinculado es un servicio que permite que los componentes de la aplicación se vinculen con él llamando a bindService() para crear una conexión a largo plazo. Por lo general, no permite que los componentes lo inician llamando a startService().

Crea un servicio vinculado cuando desees interactuar con el servicio desde las actividades y otros componentes de tu aplicación o exponer algunas de las funciones de tu aplicación 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() a fin de 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 los métodos en el servicio. El servicio solo está activo para entregar el componente de la aplicación que está vinculado a él; por lo tanto, cuando no hay componentes vinculados al servicio, el sistema lo destruye. No es necesario que detengas un servicio vinculado de la misma manera que debes hacerlo cuando el servicio 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 el 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, la discusión de los servicios vinculados aparece en otro documento sobre Servicios vinculados.

Enviar notificaciones al usuario

Cuando se está ejecutando un servicio, puede notificar al usuario sobre eventos mediante 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 durante 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 (por ejemplo, iniciar una actividad).

Por lo general, una notificación de la barra de estado es la mejor técnica para usar cuando se completa el trabajo en segundo plano, como la descarga de un archivo, y el usuario ahora puede usarla. Cuando el usuario selecciona la notificación desde la vista expandida, la notificación puede iniciar una actividad (por ejemplo, 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 la forma en que se crea y se destruye tu servicio, ya que un servicio se puede ejecutar en segundo plano sin que el usuario esté al tanto.

El ciclo de vida del servicio, desde el momento en que se crea hasta cuando se destruye, puede seguir cualquiera de estas dos rutas de acceso:

  • Un servicio iniciado

    El servicio se crea cuando otro componente llama a startService(). Luego, el servicio se ejecuta de forma indefinida y debe detenerse a sí mismo llamando a stopSelf(). Otro componente también puede detener el servicio llamando a stopService(). 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 interfaz IBinder. El cliente puede cerrar la conexión llamando a unbindService(). Se pueden enlazar varios clientes al mismo servicio y, cuando todos ellos se desenlazan, el sistema destruye el servicio. El servicio no necesita detenerse a sí mismo.

Estas dos rutas no son completamente independientes. Puedes establecer una vinculación con un servicio que ya se haya iniciado 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 controlar 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 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 trabajos en los momentos adecuados. En el siguiente servicio básico, 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 fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return startMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return binder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return allowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // 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 onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return startMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return allowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // 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.

Figura 2: El ciclo de vida de un servicio. En el diagrama de la izquierda, se muestra el ciclo de vida cuando se crea el servicio con startService(), y en el de la derecha, se muestra el ciclo de vida cuando el servicio se crea con bindService().

En la figura 2, se ven los métodos de devolución de llamada habituales de un servicio. Aunque en la figura se separan los servicios que crea startService() de los que crea bindService(), ten en cuenta que cualquier servicio, sin importar cómo se inicie, puede permitir que los clientes se vinculen a él. Un servicio que se inició en un principio con onStartCommand() (por 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 completa de un servicio ocurre entre el momento en el que se llama a onCreate() y el momento en que se muestra onDestroy(). Al igual que una actividad, un servicio realiza 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 subproceso en el que se reproduce la música en onCreate() y, luego, puede detenerlo en onDestroy().

    Nota: Se llama a los métodos onCreate() y onDestroy() para todos los servicios, ya sea que los haya creado startService() o bindService().

  • El ciclo de vida activo de un servicio comienza con una llamada a onStartCommand() o onBind(). Cada método recibe el Intent que se pasó a startService() o bindService().

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

Nota: Si bien 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 una devolución de llamada onStop()). A menos que el servicio esté vinculado a un cliente, el sistema lo destruirá cuando el servicio se detenga; onDestroy() es la única devolución de llamada recibida.

Para obtener más información sobre la creación de un servicio que proporciona 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 Cómo administrar el ciclo de vida de un servicio vinculado.