Descripción general de los servicios enlazados

Un servicio vinculado es el servidor de una interfaz cliente-servidor. Permite que los componentes como las actividades se unan al servicio, envíen solicitudes, reciban respuestas y establezcan comunicación entre procesos (IPC). Un servicio vinculado, por lo general, solo está activo mientras le presta servicio a otro componente de la aplicación y no se ejecuta en segundo plano indefinidamente.

En este documento, se describe cómo crear un servicio vinculado, además de cómo establecer una vinculación con el servicio desde otros componentes de la aplicación. Si quieres obtener información adicional sobre los servicios en general (por ejemplo, cómo enviar notificaciones desde un servicio y configurar el servicio para que se ejecute en primer plano), consulta la Descripción general de los servicios.

Conceptos básicos

Un servicio vinculado es una implementación de la clase Service que permite que otras aplicaciones se vinculen e interactúen con él. Para vincular un servicio, implementa el método de devolución de llamada onBind(). Este método muestra un objeto IBinder que define la interfaz de programación que los clientes pueden usar para interactuar con el servicio.

Vincular a un servicio iniciado

Como se explica en la Descripción general de los servicios, puedes crear un servicio que ya se haya iniciado y vinculado. Es decir, puedes iniciar un servicio llamando a startService(), lo que permite que el servicio se ejecute de forma indefinida. También puedes llamar a bindService() para permitir que un cliente se vincule con el servicio.

Si permites que tu servicio se inicie y se vincule, cuando se inicie, el sistema no lo destruirá cuando se hayan desvinculado todos los clientes. En su lugar, debes detener explícitamente el servicio llamando a stopSelf() o stopService().

Si bien generalmente implementas onBind() o onStartCommand(), a veces es necesario implementar ambos. Por ejemplo, para un reproductor de música, podría ser útil permitir que su servicio se ejecute de manera indefinida y también proporcionar capacidad de creación de vinculaciones. De esta manera, una actividad puede iniciar el servicio para que reproduzca música y que la música continúe reproduciéndose incluso si el usuario sale de la aplicación. Cuando el usuario regrese a la aplicación, la actividad podrá vincularse al servicio para volver a tener el control de la reproducción.

Para obtener más información acerca del ciclo de vida del servicio cuando agregas una vinculación a un servicio iniciado, consulta la sección Cómo administrar el ciclo de vida de un servicio vinculado.

Un cliente se vincula a un servicio llamando a bindService(). Cuando lo hace, debe implementar ServiceConnection, que supervisa la conexión con el servicio. El valor que se muestra de bindService() indica si el servicio solicitado existe y si se le permite al cliente acceder a él.

Cuando el sistema Android crea la conexión entre el cliente y el servicio, llama a onServiceConnected() en ServiceConnection. El método onServiceConnected() incluye un argumento IBinder que el cliente usa para comunicarse con el servicio vinculado.

Puedes conectar varios clientes a un servicio simultáneamente. Sin embargo, el sistema almacena en caché el canal de comunicación del servicio IBinder. En otras palabras, el sistema llama al método onBind() del servicio para generar el IBinder solo cuando se vincula el primer cliente. El sistema entonces entrega el mismo IBinder a todos los clientes adicionales que se vinculan a ese mismo servicio, sin volver a llamar a onBind().

Cuando se desvincula el último cliente del servicio, el sistema destruye el servicio, a menos que este se haya iniciado con startService().

La parte más importante de la implementación de tu servicio vinculado es definir la interfaz que mostrará tu método de devolución de llamada onBind(). En la siguiente sección, se analizan varias formas en las que puedes definir la interfaz IBinder de tu servicio.

Cómo crear un servicio vinculado

Al crear un servicio que proporciona la capacidad de crear una vinculación, debes proporcionar un IBinder que contenga la interfaz de programación que los clientes pueden usar para interactuar con el servicio. Puedes definir la interfaz de las siguientes tres maneras:

Cómo extender la clase Binder
Si tu servicio es privado para tu propia aplicación y se ejecuta en el mismo proceso que el cliente, que es lo común, crea tu interfaz extendiendo la clase Binder y mostrando una instancia de ella desde onBind(). El cliente recibe el Binder y puede usarlo para acceder directamente a métodos públicos disponibles en la implementación de Binder o Service.

Esta es la técnica preferida cuando tu servicio es solo un trabajador en segundo plano de tu propia aplicación. El único caso de uso en el que esta no es la forma preferida de crear tu interfaz es si otras aplicaciones usan tu servicio o se usa entre procesos separados.

Cómo usar Messenger
Si necesitas que tu interfaz funcione en diferentes procesos, puedes crear una para el servicio con un Messenger. De esta manera, el servicio define un Handler que responde a diferentes tipos de objetos Message.

Este Handler es la base para un Messenger que luego pueda compartir un IBinder con el cliente y permitir que el cliente envíe comandos al servicio mediante objetos Message. Además, el cliente puede definir un Messenger propio para que el servicio pueda devolver mensajes.

Esta es la manera más sencilla de establecer comunicación entre procesos (IPC), ya que Messenger pone en cola todas las solicitudes en un solo subproceso a fin de que no debas diseñar tu servicio de modo que sea seguro para subprocesos.

Usa AIDL
El Lenguaje de definición de la interfaz de Android (AIDL) descompone los objetos en primitivas que el sistema operativo puede comprender y los ordena entre procesos para establecer IPC. La técnica anterior, que utiliza un Messenger, usa AIDL como estructura subyacente.

Como se mencionó en la sección anterior, Messenger crea una cola de todas las solicitudes del cliente en un solo subproceso, de modo que el servicio reciba las solicitudes una a la vez. Sin embargo, si quieres que tu servicio administre varias solicitudes de forma simultánea, puedes usar AIDL directamente. En este caso, tu servicio debe ser seguro para los subprocesos y poder realizar varios subprocesos.

Para usar el AIDL de forma directa, crea un archivo .aidl que defina la interfaz de programación. Las herramientas del SDK de Android usan ese archivo para generar una clase abstracta que implemente la interfaz y manipule la IPC, que luego podrás extender en tu servicio.

Nota: En la mayoría de las aplicaciones, el AIDL no es la mejor opción para crear un servicio vinculado, ya que podría requerir capacidades de ejecución de varios subprocesos y dar lugar a una implementación más complicada. Por lo tanto, en este documento no se explica cómo usarlo en tu servicio. Si estás seguro de que necesitas usar AIDL de forma directa, consulta el documento AIDL.

Extiende la clase Binder

Si solo la aplicación local usa tu servicio y no necesita funcionar en todos los procesos, puedes implementar tu propia clase de Binder que le proporcione a tu cliente acceso directo a los métodos públicos incluidos en el servicio.

Nota: Esto funciona únicamente si el cliente y el servicio se encuentran en la misma aplicación y el mismo proceso, que es lo más común. Por ejemplo, esto funciona bien para una aplicación de música que necesita vincular una actividad con su propio servicio que reproduce música en segundo plano.

A continuación, te indicamos cómo configurarlo:

  1. En tu servicio, crea una instancia de Binder que realice una de las siguientes acciones:
    • Contenga métodos públicos que el cliente pueda llamar
    • Muestre la instancia Service actual, que tiene métodos públicos que el cliente puede llamar
    • Muestre una instancia de otra clase alojada por el servicio con métodos públicos que el cliente pueda llamar
  2. Muestre esta instancia Binder desde el método de devolución de llamada onBind()
  3. En el cliente, reciba Binder del método de devolución de llamada onServiceConnected() y realice llamadas al servicio vinculado usando los métodos proporcionados

Nota: El servicio y el cliente deben estar en la misma aplicación para que el cliente pueda convertir el objeto mostrado y llamar a sus API de forma correcta. El servicio y el cliente también deben estar en el mismo proceso, ya que esta técnica no realiza ningún ordenamiento entre procesos.

Por ejemplo, aquí hay un servicio que les brinda a los clientes acceso a métodos del servicio a través de la implementación de un Binder:

Kotlin

class LocalService : Service() {
    // Binder given to clients.
    private val binder = LocalBinder()

    // Random number generator.
    private val mGenerator = Random()

    /** Method for clients.  */
    val randomNumber: Int
        get() = mGenerator.nextInt(100)

    /**
     * Class used for the client Binder. Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    inner class LocalBinder : Binder() {
        // Return this instance of LocalService so clients can call public methods.
        fun getService(): LocalService = this@LocalService
    }

    override fun onBind(intent: Intent): IBinder {
        return binder
    }
}

Java

public class LocalService extends Service {
    // Binder given to clients.
    private final IBinder binder = new LocalBinder();
    // Random number generator.
    private final Random mGenerator = new Random();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods.
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    /** Method for clients. */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

LocalBinder proporciona el método getService() para que los clientes obtengan la instancia actual de LocalService. Esto permite a los clientes llamar a métodos públicos en el servicio. Por ejemplo, los clientes pueden llamar a getRandomNumber() desde el servicio.

A continuación, se proporciona una actividad que se vincula a LocalService y llama a getRandomNumber() cuando se hace clic en un botón:

Kotlin

class BindingActivity : Activity() {
    private lateinit var mService: LocalService
    private var mBound: Boolean = false

    /** Defines callbacks for service binding, passed to bindService().  */
    private val connection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            val binder = service as LocalService.LocalBinder
            mService = binder.getService()
            mBound = true
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            mBound = false
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to LocalService.
        Intent(this, LocalService::class.java).also { intent ->
            bindService(intent, connection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        unbindService(connection)
        mBound = false
    }

    /** Called when a button is clicked (the button in the layout file attaches to
     * this method with the android:onClick attribute).  */
    fun onButtonClick(v: View) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            val num: Int = mService.randomNumber
            Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show()
        }
    }
}

Java

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService.
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
        mBound = false;
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute). */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService(). */
    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

En el ejemplo anterior, se muestra cómo el cliente establece una vinculación con el servicio usando una implementación de ServiceConnection y la devolución de llamada onServiceConnected(). En la siguiente sección, se proporciona más información sobrde este proceso de vinculación con el servicio.

Nota: En el ejemplo anterior, el método onStop() desvincula al cliente del servicio. Desvincular a los clientes de los servicios en los momentos adecuados, como se explica en la sección Notas adicionales

Para acceder a otros ejemplos de código, consulta las clases LocalService.java y LocalServiceActivities.java en ApiDemos.

Cómo usar un objeto Messenger

Si necesitas que tu servicio se comunique con procesos remotos, puedes usar un Messenger a fin de proporcionar la interfaz para tu servicio. Esta técnica te permite establecer comunicación entre procesos (IPC) sin la necesidad de usar AIDL.

El uso de un Messenger para tu interfaz es más sencillo que el uso de AIDL, ya que Messenger pone en cola todas las llamadas al servicio. Una interfaz de AIDL pura envía solicitudes simultáneas al servicio, que luego debe administrar varios subprocesos.

Para la mayoría de las aplicaciones, el servicio no necesita ejecutar varios subprocesos, por lo que el uso de un Messenger permite que el servicio maneje una llamada a la vez. Si es importante que tu servicio ejecute varios subprocesos, usa AIDL para definir tu interfaz.

Aquí te mostramos un resumen de cómo usar un Messenger:

  1. El servicio implementa un Handler que recibe una devolución por cada llamada de un cliente.
  2. El servicio usa el Handler para crear un objeto Messenger (que es una referencia al Handler).
  3. El Messenger crea un IBinder que el servicio muestra a los clientes desde onBind().
  4. Los clientes usan el IBinder para crear instancias del Messenger (que hace referencia al Handler del servicio), que el cliente usa para enviar objetos Message al servicio.
  5. El servicio recibe cada Message en su Handler; específicamente, en el método handleMessage().

De esta manera, no hay métodos que el cliente pueda usar para llamar al servicio. En su lugar, el cliente envía mensajes (objetos Message) que el servicio recibe en su Handler.

Aquí te mostramos un ejemplo sencillo de servicio que usa una interfaz Messenger:

Kotlin

/** Command to the service to display a message.  */
private const val MSG_SAY_HELLO = 1

class MessengerService : Service() {

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    private lateinit var mMessenger: Messenger

    /**
     * Handler of incoming messages from clients.
     */
    internal class IncomingHandler(
            context: Context,
            private val applicationContext: Context = context.applicationContext
    ) : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_SAY_HELLO ->
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show()
                else -> super.handleMessage(msg)
            }
        }
    }

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    override fun onBind(intent: Intent): IBinder? {
        Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show()
        mMessenger = Messenger(IncomingHandler(this))
        return mMessenger.binder
    }
}

Java

public class MessengerService extends Service {
    /**
     * Command to the service to display a message.
     */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    static class IncomingHandler extends Handler {
        private Context applicationContext;

        IncomingHandler(Context context) {
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    Messenger mMessenger;

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        mMessenger = new Messenger(new IncomingHandler(this));
        return mMessenger.getBinder();
    }
}

El método handleMessage() en Handler es donde el servicio recibe el Message entrante y decide qué hacer en función del miembro de what.

Todo lo que el cliente debe hacer es crear un Messenger en función del IBinder que muestra el servicio y enviar un mensaje con send(). Por ejemplo, esta es una actividad que se vincula al servicio y le envía el mensaje MSG_SAY_HELLO:

Kotlin

class ActivityMessenger : Activity() {
    /** Messenger for communicating with the service.  */
    private var mService: Messenger? = null

    /** Flag indicating whether we have called bind on the service.  */
    private var bound: Boolean = false

    /**
     * Class for interacting with the main interface of the service.
     */
    private val mConnection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = Messenger(service)
            bound = true
        }

        override fun onServiceDisconnected(className: ComponentName) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null
            bound = false
        }
    }

    fun sayHello(v: View) {
        if (!bound) return
        // Create and send a message to the service, using a supported 'what' value.
        val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0)
        try {
            mService?.send(msg)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to the service.
        Intent(this, MessengerService::class.java).also { intent ->
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection)
            bound = false
        }
    }
}

Java

public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean bound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            bound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null;
            bound = false;
        }
    };

    public void sayHello(View v) {
        if (!bound) return;
        // Create and send a message to the service, using a supported 'what' value.
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service.
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection);
            bound = false;
        }
    }
}

En este ejemplo, no se muestra cómo el servicio puede responder al cliente. Si quieres que el servicio responda, también deberás crear un Messenger en el cliente. Cuando el cliente recibe la devolución de llamada onServiceConnected(), envía un Message al servicio que incluye el Messenger del cliente en el parámetro replyTo del método send().

Puedes ver la manera de proporcionar un sistema de mensajería bidireccional en los ejemplos de MessengerService.java (servicio) y MessengerServiceActivities.java (cliente).

Vincular a un servicio

Los componentes de la aplicación (clientes) pueden establecer una vinculación con un servicio llamando a bindService(). Luego, el sistema Android llama al método onBind() del servicio, que muestra un IBinder para interactuar con él.

La vinculación es asíncrona, y bindService() se muestra inmediatamente sin mostrarle el IBinder al cliente. Para recibir el IBinder, el cliente debe crear una instancia de ServiceConnection y pasarla a bindService(). ServiceConnection incluye un método de devolución de llamada al que el sistema llama para enviar el IBinder.

Nota: Solo las actividades, los servicios y los proveedores de contenido pueden establecer vinculaciones con un servicio; no puedes establecer vinculaciones con un servicio desde un receptor de emisión.

Para establecer un enlace con un servicio desde tu cliente, debes hacer lo siguiente:

  1. Implementa ServiceConnection.

    Tu implementación debe anular dos métodos de devolución de llamada:

    onServiceConnected()
    El sistema lo llama para entregar el IBinder que muestra el método onBind() del servicio.
    onServiceDisconnected()
    El sistema Android lo llama cuando se pierde de forma inesperada la conexión con el servicio, por ejemplo, cuando el servicio falla o se desactiva. No lo llama cuando se desvincula el cliente.
  2. Llama a bindService() y pasa la implementación de ServiceConnection.

    Nota: Si el método muestra un valor falso, significa que tu cliente no tiene una conexión válida con el servicio. Sin embargo, debes llamar a unbindService() en tu cliente. De lo contrario, el cliente evitará que se cierre el servicio cuando esté inactivo.

  3. Cuando el sistema llama a tu método de devolución de llamada onServiceConnected(), puedes comenzar a realizar llamadas al servicio usando los métodos definidos por la interfaz.
  4. Para desconectarte del servicio, llama a unbindService().

    Si tu cliente aún está vinculado a un servicio cuando tu app destruye el cliente, la destrucción hace que se desvincule el cliente. La práctica recomendada es desvincular al cliente en cuanto termine de interactuar con el servicio. Esto permitirá que se cierre el servicio inactivo. Si deseas obtener más información sobre los momentos apropiados para la vinculación y la desvinculación, consulta la sección Notas adicionales.

En el siguiente ejemplo, se conecta al cliente con el servicio creado antes mediante la extensión de la clase Binder, por lo que lo único que debe hacer es convertir el IBinder mostrado en la clase LocalBinder y solicitar la instancia LocalService:

Kotlin

var mService: LocalService

val mConnection = object : ServiceConnection {
    // Called when the connection with the service is established.
    override fun onServiceConnected(className: ComponentName, service: IBinder) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        val binder = service as LocalService.LocalBinder
        mService = binder.getService()
        mBound = true
    }

    // Called when the connection with the service disconnects unexpectedly.
    override fun onServiceDisconnected(className: ComponentName) {
        Log.e(TAG, "onServiceDisconnected")
        mBound = false
    }
}

Java

LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established.
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    // Called when the connection with the service disconnects unexpectedly.
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mBound = false;
    }
};

Con este ServiceConnection, el cliente puede establecer una vinculación con un servicio pasándolo a bindService(), como se muestra en el siguiente ejemplo:

Kotlin

Intent(this, LocalService::class.java).also { intent ->
    bindService(intent, connection, Context.BIND_AUTO_CREATE)
}

Java

Intent intent = new Intent(this, LocalService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
  • El primer parámetro de bindService() es un Intent que menciona explícitamente el servicio para vincular.

    Precaución: Si utilizas un intent para la vinculación con un Service, asegúrate de que tu app sea segura mediante un intent explícito. 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 (API nivel 21), el sistema lanza una excepción si llamas a bindService() con un intent implícito.

  • El segundo parámetro es el objeto ServiceConnection.
  • El tercer parámetro es una marca que indica opciones para la vinculación, generalmente BIND_AUTO_CREATE, para crear el servicio si aún no está activo. Otros valores posibles son BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND o 0 para ninguno.

Notas adicionales

Aquí te proporcionamos algunas notas importantes acerca de cómo establecer enlaces con un servicio:

  • Siempre atrapan las excepciones DeadObjectException, que se producen cuando se pierde la conexión. Esta es la única excepción que producen los métodos remotos.
  • Los objetos se cuentan como referencia entre procesos.
  • Por lo general, sincronizas la vinculación y la desvinculación durante los momentos de introducción y desmontaje de la coincidencia del ciclo de vida del cliente, como se describe en los siguientes ejemplos:
    • Si necesitas interactuar con el servicio solo mientras tu actividad esté visible, realiza la vinculación durante onStart() y desenlaza durante onStop().
    • Si quieres que tu actividad reciba respuestas incluso mientras está detenida en segundo plano, realiza la vinculación durante onCreate() y desvincúlala durante onDestroy(). Ten en cuenta que esto implica que tu actividad necesita usar el servicio todo el tiempo que se esté ejecutando, incluso en segundo plano; por lo tanto, cuando el servicio se encuentra en otro proceso, aumentas el peso del proceso y es más probable que el sistema lo cierre.

    Nota: Por lo general, no realizas vinculaciones ni desvinculas durante las devoluciones de llamada onResume() y onPause() de tu actividad, ya que esas devoluciones de llamada ocurren en cada transición del ciclo de vida. Minimiza el procesamiento que se produce en estas transiciones.

    Además, si varias actividades de tu aplicación se vinculan al mismo servicio y hay una transición entre dos de esas actividades, el servicio podría destruirse y recrearse a medida que se desvincula la actividad actual (durante una pausa) y antes de que se vincule la siguiente (durante la reanudación). Esta transición de una actividad en relación con cómo las actividades coordinan su ciclo de vida se describe en Ciclo de vida de la actividad.

Para acceder a otros ejemplos de código que muestran cómo establecer una vinculación con un servicio, consulta la clase RemoteService.java en ApiDemos.

Administra el ciclo de vida de un servicio vinculado

Cuando se desvincula un servicio de todos los clientes, el sistema Android lo destruye (a menos que se haya iniciado mediante startService()). De esta manera, no tienes que administrar el ciclo de vida de tu servicio si solo es un servicio vinculado. El sistema Android lo administra por ti según si está vinculado a algún cliente.

Sin embargo, si decides implementar el método de devolución de llamada onStartCommand(), debes detener el servicio de forma explícita, ya que este ahora se considera iniciado. En este caso, el servicio se ejecuta hasta que se detenga por sí mismo con stopSelf() o cuando otro componente llame a stopService(), independientemente de que esté vinculado o no a algún cliente.

Además, si se inicia tu servicio y acepta la vinculación, cuando el sistema llame a tu método onUnbind(), tendrás la opción de mostrar true si deseas recibir una llamada a onRebind() la próxima vez que un cliente establezca una vinculación con el servicio. onRebind() muestra void, pero el cliente de todos modos recibe el IBinder en su devolución de llamada onServiceConnected(). En la figura que aparece a continuación, se ilustra la lógica para este tipo de ciclo de vida.

Figura 1: Ciclo de vida para un servicio iniciado que también admite vinculación

Para obtener más información sobre el ciclo de vida de un servicio iniciado, consulta la Descripción general de los servicios.