Skip to content

Most visited

Recently visited

navigation

Servicios enlazados

Un servicio enlazado es el servidor en una interfaz cliente-servidor. Un servicio enlazado permite que los componentes (como actividades) se enlacen con el servicio, envíen solicitudes, reciban respuestas e incluso establezcan comunicación entre procesos (IPC). Un servicio enlazado generalmente solo está activo mientras le preste servicio a otro componente de la aplicación y no se ejecuta en segundo plano indefinidamente.

Este documento te muestra cómo crear un servicio enlazado, además de cómo establecer un enlace con el servicio desde otros componentes de la aplicación. Sin embargo, también debes leer el documento Servicios para obtener información adicional acerca de los servicios en general; por ejemplo, cómo enviar notificaciones desde un servicio, cómo configurar el servicio para que se ejecute en primer plano, etc.

Conceptos básicos

Un servicio enlazado es una implementación de la clase Service que permite que otras aplicaciones se enlacen e interactúen con el mismo. Para enlazar un servicio, debes implementar el método callback onBind(). Este método devuelve un objeto IBinder que define la interfaz de programación que los clientes pueden usar para interactuar con el servicio.

Un cliente se puede enlazar con el servicio llamando a bindService(). Cuando lo hace, debe implementar ServiceConnection, que controla la conexión con el servicio. El método bindService() se muestra de inmediato sin un valor, pero cuando el sistema Android crea la conexión entre el cliente y el servicio, llama a onServiceConnected() en la ServiceConnection, para entregar el IBinder que el cliente puede usar para comunicarse con el servicio.

Se pueden conectar muchos clientes con el servicio al mismo tiempo. No obstante, el sistema llama al método onBind() de tu servicio para recuperar el IBinder solo cuando el primer cliente se enlaza. Luego, el sistema entrega el mismo IBinder a los demás clientes que establezcan enlaces, sin llamar nuevamente a onBind().

Cuando el último cliente se desenlaza del servicio, el sistema destruye el servicio (a menos que el servicio también haya sido iniciado por startService()).

Cuando implementas tu servicio enlazado, la parte más importante es definir la interfaz que devolverá tu método callback onBind(). Existen algunas maneras en las que puedes definir la interfaz IBinder de tu servicio, y en la siguiente sección se explican cada una de las técnicas.

Creación de un servicio enlazado

Al crear un servicio que proporciona la capacidad de crear un enlace, 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 tres maneras:

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), deberías crear 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 incluso en el Service.

Esta es la técnica preferida cuando tu servicio es solo un trabajador en segundo plano para tu propia aplicación. El único motivo por el que no deberías crear tu interfaz de esta manera es porque a tu servicio lo usan otras aplicaciones o se usa entre procesos independientes.

Utilizar un mensajero (Messenger)
Si necesitas que tu interfaz funcione en diferentes procesos, puedes crear una interfaz 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 usando 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 de modo que no tengas que diseñar tu servicio a fin de que sea seguro para subprocesos.

Utilizar AIDL
El idioma de definición de la interfaz de Android (AIDL) realiza todo el trabajo de descomposición de objetos en primitivas que el sistema operativo puede comprender y ordenar entre procesos para establecer IPC. La técnica anterior, que utiliza un Messenger, se basa en AIDL como su estructura subyacente. Como se indicó anteriormente, el Messenger crea una cola de todas las solicitudes del cliente de modo que el servicio reciba las solicitudes de a una. Sin embargo, si quieres que tu servicio maneje múltiples solicitudes de forma simultánea, puedes usar AIDL directamente. En este caso, tu servicio debe poder ejecutar múltiples subprocesos y ser seguro para los subprocesos.

Para usar el AIDL de forma directa, debes crear un archivo .aidl que defina la interfaz de programación. Las herramientas del Android SDK usan ese archivo para generar una clase abstracta que implementa la interfaz y manipula la IPC, que luego puedes extender en tu servicio.

Nota: La mayoría de las aplicaciones no deben usar AIDL para crear un servicio enlazado, ya que podría requerir capacidades de ejecución de múltiples subprocesos y puede dar lugar a una implementación más complicada. Como tal, AIDL no es conveniente para la mayoría de las aplicaciones, y este documento no aborda cómo usarlo en tu servicio. Si estás seguro de que necesitas usar AIDL de forma directa, lee el documento AIDL .

Extender la clase Binder

Si a tu servicio solo lo usa la aplicación local y no necesita ejecutarse en diferentes procesos, puedes implementar tu propia clase de Binder, que le proporciona al 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 funcionaría bien para una aplicación de música que necesite enlazar una actividad con su propio servicio que reproduce música en segundo plano.

Aquí te mostramos cómo configurarlo:

  1. En tu servicio, crea una instancia de Binder que haga lo siguiente:
    • contener métodos públicos que el cliente pueda llamar;
    • devolver la instancia Service actual, que tiene métodos públicos que el cliente puede llamar;
    • o que devuelva una instancia de otra clase alojada por el servicio con métodos públicos que el cliente pueda llamar.
  2. Muestra esta instancia Binder desde el método de callback onBind().
  3. En el cliente, recibe Binder del método de callback onServiceConnected() y realiza llamadas al servicio enlazado 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 devuelto 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 tipo de ordenamiento entre procesos.

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

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = 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 mBinder;
    }

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

El 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 enlaza a LocalService y llama a getRandomNumber() cuando se hace clic en un botón:

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, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            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 were something that might hang, then this request should
            // occur 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 mConnection = 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 la manera en que el cliente establece un enlace con el servicio usando una implementación de ServiceConnection y el callback onServiceConnected(). La siguiente sección proporciona más información acerca de este proceso de enlace con el servicio.

Nota: En el ejemplo anterior, el método onStop() desvincula al cliente del servicio. Los clientes se deben desvincular de los servicios en el momento apropiado, como se discute en Notas adicionales.

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

Utilizar un mensajero (Messenger)

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

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

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:

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.
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * 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();
        return mMessenger.getBinder();
    }
}

Observa que el método handleMessage() en el 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 mostrado por el servicio y enviar un mensaje con send(). Por ejemplo, esta es una actividad simple que se enlaza con el servicio y le envía el mensaje MSG_SAY_HELLO:

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 mBound;

    /**
     * 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);
            mBound = 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;
            mBound = false;
        }
    };

    public void sayHello(View v) {
        if (!mBound) 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 (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

Ten en cuenta que este ejemplo no muestra cómo el servicio puede responderle al cliente. Si quieres que el servicio responda, necesitarás crear también un Messenger en el cliente. Luego, cuando el cliente reciba el callback onServiceConnected(), enviará un Message al servicio que incluirá 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 MessengerService.java (servicio) y MessengerServiceActivities.java (cliente).

Enlazar a un servicio (Service)

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

El enlace es asíncrono. De inmediato, se devuelve bindService() y no se devuelve el IBinder al cliente. Para recibir el IBinder, el cliente debe crear una instancia de ServiceConnection y pasarla a bindService(). La ServiceConnection incluye un método callback al que el sistema llama para enviar el IBinder.

Nota: Solo las actividades, los servicios y los proveedores de contenido pueden establecer enlaces con un servicio; no puedes establecer un enlace con un servicio desde un receptor de mensajes.

Por lo tanto, para establecer un enlace con un servicio desde tu cliente, debes hacer lo siguiente:

  1. Implementa ServiceConnection.

    Tu implementación debe sobrescribir dos métodos de callback:

    onServiceConnected()
    El sistema lo llama para enviar el IBinder devuelto por el métodoonBind() del servicio.
    onServiceDisconnected()
    El sistema Android lo llama cuando se pierde de forma inesperada la conexión con el servicio, como cuando el servicio falla o se desactiva. No se lo llama cuando el cliente se desenlaza.
  2. Llama a bindService() y pasa la implementación de ServiceConnection.
  3. Cuando el sistema llama tu método callback onServiceConnected(), puedes comenzar a realizar llamadas al servicio usando los métodos definidos por la interfaz.
  4. Para la desconexión del servicio, llama a unbindService().

    Si tu cliente aún está vinculado a un servicio cuando tu app destruye al cliente, la destrucción hace que el cliente se desvincule. La práctica recomendada es desvincular al cliente tan pronto como se acabe la interacción con el servicio. Hacer eso permite que el servicio inactivo se cierre. Si deseas obtener más información sobre momentos apropiados para la vinculación y desvinculación, consulta Notas adicionales.

Por ejemplo, el siguiente fragmento de código conecta al cliente con el servicio antes creado extendiendo la clase Binder; por lo tanto, lo único que debe hacer es transmitir el IBinder mostrado en la clase LocalService y solicitar la instancia LocalService:

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 esta ServiceConnection, el cliente puede establecer un enlace con un servicio pasándolo a bindService(). Por ejemplo:

Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

Notas adicionales

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

Para acceder a otros ejemplos de código en los que se muestre la manera de establecer un enlace con un servicio, lee la clase RemoteService.java en ApiDemos.

Administración del ciclo de vida de un servicio enlazado

Cuando se desenlaza un servicio de todos los clientes, el sistema Android lo destruye (a menos que también se haya iniciado con onStartCommand()). De este modo, no necesitas administrar el ciclo de vida de tu servicio si se trata puramente de un servicio de enlace; el sistema Android lo administra por ti en función de si está enlazado a algún cliente.

No obstante, si decides implementar el método callback onStartCommand(), debes detener el servicio de forma explícita ya que el servicio 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é enlazado o no a algún cliente.

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

Figura 1: Ciclo de vida para un servicio que se inicia y también admite enlaces.

Para obtener más información acerca del ciclo de vida de un servicio iniciado, lee el documento Servicios.

This site uses cookies to store your preferences for site-specific language and display options.

Hooray!

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.