Descripción general de los servicios enlazados

Un servicio vinculado es el servidor de una interfaz cliente-servidor. Permite que componentes, como las actividades, se vinculen al servicio, envíen solicitudes, reciban respuestas y realicen comunicaciones 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. Para obtener información adicional sobre los servicios en general, como la forma de enviar notificaciones desde un servicio y configurarlo 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 a él y que interactúen con él. Para proporcionar vinculación para 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.

Cómo vincularse a un servicio iniciado

Como se indica en la Descripción general de los servicios, puedes crear un servicio que se inicie y se vincule. Es decir, puedes iniciar un servicio llamando a startService(), lo que permite que el servicio se ejecute de forma indefinida. También puedes permitir que un cliente se vincule al servicio llamando a bindService().

Si permites que tu servicio se inicie y vincule, cuando se inicie, el sistema no lo destruirá cuando todos los clientes se desvinculen. 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, un reproductor de música podría considerar útil permitir que su servicio se ejecute de forma indefinida y también proporcionar vinculación. De esta manera, una actividad puede iniciar el servicio para reproducir música, y la música se seguirá reproduciendo 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 sobre el ciclo de vida del servicio cuando se agrega 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 el último cliente se desvincula del servicio, el sistema lo destruye, a menos que 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.

Crea 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:

Extiende la clase Binder
Si tu servicio es privado para tu propia aplicación y se ejecuta en el mismo proceso que el cliente, lo cual es común, crea tu interfaz extendiendo la clase Binder y devolviendo 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 o procesos independientes usan tu servicio.

Usa un 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 de un Messenger que, luego, puede compartir un IBinder con el cliente, lo que le permite enviar comandos al servicio con objetos Message. Además, el cliente puede definir un Messenger propio, de modo 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 organiza en procesos para realizar la IPC. La técnica anterior, que utiliza un Messenger, usa AIDL como estructura subyacente.

Como se mencionó en la sección anterior, el Messenger crea una cola de todas las solicitudes de clientes en un solo subproceso, por lo que el servicio recibe las solicitudes de una en una. Sin embargo, si quieres que tu servicio administre varias solicitudes de forma simultánea, puedes usar AIDL directamente. En este caso, tu servicio debe tener protección de subprocesos y ser capaz de realizar subprocesamiento múltiple.

Para usar AIDL directamente, 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, AIDL no es la mejor opción para crear un servicio vinculado, ya que puede requerir capacidades de varios subprocesos y puede dar como resultado una implementación más complicada. Por lo tanto, en este documento no se analiza cómo usarlo para tu servicio. Si tienes la certeza de que necesitas usar AIDL directamente, consulta el documento AIDL.

Extiende la clase Binder

Si solo la aplicación local usa tu servicio y no necesita funcionar en varios procesos, puedes implementar tu propia clase Binder que proporcione a tu cliente acceso directo a los métodos públicos del 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 a 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 haga lo siguiente:
    • 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 ninguna serialización 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 que los clientes llamen 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 var mService: LocalService? = null
    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) {
            mService = null
            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)
        // Release the reference so the service can be garbage-collected once it's
        // destroyed. onServiceDisconnected() isn't called when the client unbinds.
        mService = null
        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 ?: return
            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);
        // Release the reference so the service can be garbage-collected once it's
        // destroyed. onServiceDisconnected() isn't called when the client unbinds.
        mService = null;
        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) {
            mService = null;
            mBound = false;
        }
    };
}

En el ejemplo anterior, se muestra cómo el cliente se vincula al servicio con 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 el cliente del servicio y libera la referencia del cliente a él. Desvincula 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.

Usa un mensajero

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 realizar una comunicación entre procesos (IPC) sin 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 AIDL pura envía solicitudes simultáneas al servicio, que luego debe controlar los subprocesos múltiples.

En la mayoría de las aplicaciones, el servicio no necesita realizar varios subprocesos, por lo que el uso de un Messenger permite que el servicio controle una llamada a la vez. Si es importante que tu servicio sea de 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.

A continuación, se muestra un ejemplo 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, según el miembro 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 entrega 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)
            mService = null
            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);
            mService = null;
            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).

Cómo vincularse 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 una vinculación 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 enviar el IBinder que muestra el método onBind() del servicio.
    onServiceDisconnected()
    El sistema Android llama a este método cuando la conexión con el servicio se pierde de forma inesperada, como cuando el servicio falla o se cierra. 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, llama a unbindService() en tu cliente. De lo contrario, el cliente evitará que el servicio se cierre 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. Se recomienda desvincular el cliente en cuanto termine de interactuar con el servicio. De esta manera, se permite que el servicio inactivo se cierre. Para obtener más información sobre los momentos adecuados para vincular y desvincular, consulta la sección Notas adicionales.

En el siguiente ejemplo, se conecta el cliente al servicio creado anteriormente mediante la extensión de la clase Binder, por lo que todo lo que debe hacer es transmitir el IBinder que se muestra a la clase LocalBinder y solicitar la instancia de LocalService:

Kotlin

var mService: LocalService? = null

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")
        mService = null
        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");
        mService = null;
        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 usando 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 responderá 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 las opciones para la vinculación, por lo general, 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 intercepta las excepciones DeadObjectException, que se arrojan cuando se interrumpe 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, vinculas y desvinculas durante los momentos de inicio y finalización correspondientes del ciclo de vida del cliente, como se describe en los siguientes ejemplos:
    • Si necesitas interactuar con el servicio solo mientras tu actividad es visible, realiza la vinculación durante onStart() y la desvinculación durante onStop().
    • Si quieres que tu actividad reciba respuestas incluso mientras se detiene en segundo plano, realiza la vinculación durante onCreate() y la desvinculación durante onDestroy(). Ten en cuenta que esto implica que tu actividad debe usar el servicio todo el tiempo que se esté ejecutando, incluso en segundo plano, por lo que, cuando el servicio está en otro proceso, aumentas el peso del proceso y es más probable que el sistema lo finalice.

    Nota: Por lo general, no vinculas ni desvinculas durante las devoluciones de llamada onResume() y onPause() de tu actividad, ya que estas devoluciones de llamada se producen en cada transición del ciclo de vida. Mantén al mínimo 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, es posible que el servicio se destruya y se vuelva a crear a medida que la actividad actual se desvincula (durante la pausa) antes de que se vincule la siguiente (durante la reanudación). Esta transición de actividad para la forma en que las actividades coordinan sus ciclos de vida se describe en El ciclo de vida de la actividad.

Para ver más código de muestra que ilustre cómo vincular un servicio, consulta la clase RemoteService.java en ApiDemos.

Administra el ciclo de vida de un servicio vinculado

Cuando un servicio se desvincula de todos los clientes, el sistema Android lo destruye (a menos que se haya iniciado con startService()). Por lo tanto, no tienes que administrar el ciclo de vida de tu servicio si es puramente un servicio vinculado. El sistema Android lo administra por ti en función de 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 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(), puedes devolver true de forma opcional si quieres recibir una llamada a onRebind() la próxima vez que un cliente se vincule al 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.

Ciclo de vida de un servicio iniciado y vinculado: se llama a onStartCommand() y onBind(); cuando todos los clientes se desvinculan, se llama a onUnbind(); en la siguiente vinculación, se llama a onRebind() si onUnbind() devolvió true, de lo contrario, se llama a onBind(); después de que se detiene el servicio, se llama a onDestroy().
Figura 1: Ciclo de vida de un servicio que se inicia y también permite la 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.