lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

Serviços vinculados

Um serviço vinculado é o servidor em uma interface cliente-servidor. Um serviço vinculado permite que componentes (como atividades) sejam vinculados ao serviço, enviem solicitações, recebam respostas e até estabeleçam comunicação entre processos (IPC). Um serviço vinculado geralmente existe somente enquanto serve a outro componente do aplicativo e não é executado em segundo plano indefinidamente.

Este documento mostra como criar um serviço vinculado, inclusive como criar vínculos com o serviço em outros componentes do aplicativo. No entanto, você também deve consultar a documentação Serviços para obter informações adicionais sobre serviços de forma geral, por exemplo, como enviar notificações de um serviço, como definir o serviço a ser executado em primeiro plano etc.

Conceitos básicos

Um serviço vinculado é uma implementação da classe Service que permite que outros aplicativos sejam vinculados e interajam com ele. Para fornecer a vinculação a um serviço, você deve implementar o método de retorno de chamada onBind(). Esse método retorna um objeto IBinder que define a interface de programação que os clientes podem usar para interagir com o serviço.

Um cliente pode se associar ao serviço chamando bindService(). Quando isso ocorre, é preciso fornecer uma implementação de ServiceConnection, que monitora a conexão com o serviço. O método bindService() retorna imediatamente sem um valor, mas, quando o sistema Android cria a conexão entre o cliente e o serviço, ele chama onServiceConnected() em ServiceConnection para fornecer o IBinder que o cliente pode usar para se comunicar com o serviço.

Vários clientes podem se conectar ao serviço de uma vez. No entanto, o sistema chama o método onBind() do serviço para recuperar o IBinder somente quando o primeiro cliente é vinculado. Em seguida, o sistema entrega o mesmo IBinder para quaisquer clientes adicionais que sse vincularem, sem chamar onBind() novamente.

Quando o último cliente se desvincular do serviço, o sistema destruirá o serviço (a não ser que ele também seja iniciado por startService()).

Ao implementar o serviço vinculado, o mais importante é definir a interface que o método de retorno de chamada onBind() retornará. Há algumas formas de definir a interface IBinder do serviço e a seção a seguir discute cada técnica.

Criação de um serviço vinculado

Ao criar um serviço que fornece vinculação, você deve fornecer um IBinder que ofereça a interface de programação que os clientes podem usar para interagir com o serviço. Há três maneiras possíveis de definir a interface:

Extensão da classe Binder
Se o serviço é privado para o próprio aplicativo e executado no mesmo processo que o cliente (o que é comum), deve-se criar a interface estendendo a classe Binder e retornando uma instância dela de onBind(). O cliente receberá Binder e poderá usá-lo para acessar os métodos públicos disponíveis na implementação de Binder ou até em Service diretamente.

Essa é a técnica preferencial quando o serviço é meramente um trabalhador de segundo plano para o aplicativo. O único motivo pelo qual não se criaria a interface dessa maneira é porque o serviço está sendo usado por outros aplicativos ou em processos separados.

Uso de um mensageiro
Caso precise que a interface funcione em diferentes processos, é possível criar uma interface para o serviço com Messenger. Dessa maneira, o serviço define um Handler que responde a diferentes tipos de objetos Message. Esse Handler é a base para Messenger, que pode então compartilhar um IBinder com o cliente, permitindo que ele envie comandos ao serviço usando objetos Message. Além disso, o cliente pode definir o próprio Messenger para que o serviço possa enviar as mensagens de volta.

Essa é a maneira mais simples de estabelecer comunicação entre processos (IPC), pois o Messenger coloca todas as solicitações em fila em um único encadeamento para que você não precise projetar o serviço de modo que seja seguro para encadeamentos.

Uso de AIDL
A AIDL (Android Interface Definition Language, linguagem de definição de interface do Android) realiza todo o trabalho de decomposição de objetos em primitivos para que o sistema operacional possa entendê-los e dispô-los em processos para realizar IPC. A técnica anterior, usando o Messenger, tem base em AIDL como a estrutura subjacente. Como mencionado acima, o Messenger cria uma fila de todas as solicitações de cliente em um único encadeamento para que o serviço receba uma solicitação por vez. Se, no entanto, você quiser que o serviço lide com várias solicitações simultaneamente, é possível usar a AIDL diretamente. Nesse caso, o serviço deverá ser capaz de realizar vários encadeamentos e ser programado de forma segura para encadeamentos.

Para usar a AIDL diretamente, deve-se criar um arquivo .aidl que defina a interface de programação. As ferramentas do Android SDK usam esse arquivo para gerar uma classe abstrata que implementa a interface e lida com a IPC, que pode ser estendida dentro do serviço.

Observação: A maioria dos aplicativos não deve usar a AIDL para criar um serviço vinculado, pois isso requer a capacidade de trabalhar com vários encadeamentos e pode resultar em uma implementação mais complicada. Portanto, a AIDL não é adequada para a maioria dos aplicativos e este documento não discute seu uso para o serviço. Caso tenha certeza de que precisa usar a AIDL diretamente, consulte a documentação AIDL.

Extensão da classe Binder

Se o serviço for usado somente pelo aplicativo local e não precisar trabalhar entre processos, será possível implementar a própria classe Binder que fornece ao cliente acesso direto aos métodos públicos no serviço.

Observação: Isso funciona somente se o cliente e o serviço estão no mesmo aplicativo e processo, o que é muito comum. Por exemplo, isso funcionaria bem para um aplicativo de música que precise vincular uma atividade ao próprio serviço que está reproduzindo música em segundo plano.

Como configurar:

  1. No serviço, crie uma instância de Binder que:
    • contenha métodos públicos que o cliente possa chamar
    • retorne ao cliente a instância Service, que tenha métodos públicos que ele possa chamar
    • ou retorne uma instância de outra classe hospedada pelo serviço com métodos públicos que o cliente possa chamar
  2. Retorne essa instância de Binder do método de retorno de chamada onBind().
  3. No cliente, receba o Binder do método de retorno de chamada onServiceConnected() e faça chamadas para o serviços vinculados usando os métodos fornecidos.

Observação: O motivo pelo qual o serviço e o cliente devem estar no mesmo aplicativo é para que o cliente possa lançar o objeto retornado e chamar as APIs adequadamente. O serviço e o cliente também devem estar no mesmo processo, pois essa técnica não têm nenhuma ingerência entre processos.

Por exemplo, a seguir há um serviço que fornece aos clientes acesso aos métodos no serviço por meio de uma implementação de 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);
    }
}

O LocalBinder fornece o método getService() para que os clientes recuperem a instância atual de LocalService. Isso permite que os clientes chamem métodos públicos no serviço. Por exemplo, eles podem chamar getRandomNumber() do serviço.

Eis uma atividade que se vincula a LocalService e chama getRandomNumber() quando um botão é pressionado:

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

O exemplo acima mostra como o cliente vincula um serviço usando uma implementação de ServiceConnection e o retorno de chamada onServiceConnected(). A próxima seção fornece mais informações sobre esse processo de vinculação ao serviço.

Observação: No exemplo acima, o método onStop() desvincula o cliente do serviço. Os clientes devem ser desvinculados de serviços em momentos apropriados, conforme é discutido nas Observações adicionais.

Para obter mais códigos de exemplo, consulte as classes LocalService.java e LocalServiceActivities.java no ApiDemos.

Uso de um mensageiro

Caso precise que o serviço se comunique com processos remotos, é possível usar o Messenger para fornecer a interface ao serviço. Essa técnica permite estabelecer comunicação entre processos (IPC) sem precisar usar a AIDL.

A seguir há um resumo sobre como usar um Messenger:

Dessa forma, não há "métodos" para o cliente chamar no serviço. Em vez disso, o cliente envia "mensagens" (objetos Message) que o serviço recebe no Handler.

Abaixo há um exemplo simples de serviço que usa uma interface 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();
    }
}

Observe que o método handleMessage() no Handler é onde o serviço recebe a Message e decide o que fazer com base no membro what.

Tudo que o cliente precisa fazer é criar um Messenger com base no IBinder retornado pelo serviço e enviar uma mensagem usando send(). Por exemplo, a seguir há uma atividade simples que se vincula ao serviço e envia a mensagem MSG_SAY_HELLO a ele:

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

Observe que esse exemplo não mostra como o serviço pode responder ao cliente. Caso queira que o serviço responda, é necessário criar um Messenger também no cliente. Em seguida, quando o cliente receber o retorno de chamada de onServiceConnected(), ele enviará uma Message para o serviço que inclui o Messenger no parâmetro replyTo do método send().

É possível ver um exemplo de como fornecer mensagens bidirecionais nos exemplos MessengerService.java (serviço) e MessengerServiceActivities.java (cliente).

Vinculação a um serviço

Um componente de aplicativo (cliente) pode se vincular a um serviço chamando bindService(). O sistema Android, em seguida, chama o método onBind() do serviço, que retorna um IBinder para interagir com o serviço.

A vinculação é assíncrona. bindService() retorna imediatamente e não retorna o IBinder ao cliente. Para receber IBinder, o cliente deve criar uma instância de ServiceConnection e passá-la para bindService(). O ServiceConnection inclui um método de retorno de chamada que o sistema chama para entregar o IBinder.

Observação: Somente atividades, serviços e provedores de conteúdo podem se vincular a um serviço — você não pode fazer isso em um receptor de transmissão.

Portanto, para se vincular a um serviço no cliente, é preciso:

  1. Implementar ServiceConnection.

    Sua implementação deve modificar dois métodos de retorno de chamada:

    onServiceConnected()
    O sistema chama isso para entregar o IBinder retornado pelo método onBind() do serviço.
    onServiceDisconnected()
    O sistema Android chama isso quando a conexão ao serviço é perdida inesperadamente, como quando o serviço apresenta problemas ou é fechado de forma repentina. Isso não é chamado quando o cliente desfaz o vínculo.
  2. Chame bindService(), passando a implementação ServiceConnection.
  3. Quando o sistema chama o método de retorno de chamada onServiceConnected(), é possível fazer chamadas para o serviço usando os métodos definidos pela interface.
  4. Para se desconectar de um serviço, chame unbindService().

    Se seu cliente ainda estiver vinculado a um serviço quando o aplicativo o destruir, a destruição fará com que o cliente seja desvinculado. É recomendável desvincular o cliente assim que ele terminar de interagir com o serviço. Isso permite a desativação do serviço ocioso. Para saber mais sobre os momentos apropriados para vincular e desvincular, consulte as Observações adicionais.

Por exemplo, o snippet a seguir conecta o cliente ao serviço criado acima estendendo a classe Binder para que tudo que ele tenha que fazer seja lançar o IBinder retornado para a classe LocalService e solicitar a instância de 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;
    }
};

Com esse ServiceConnection, o cliente pode se vincular a um serviço passando-o para bindService(). Por exemplo:

Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
  • O primeiro parâmetro de bindService() é uma Intent que nomeia explicitamente o serviço que será vinculado (apesar de o intent poder ser implícito).
  • O segundo parâmetro é o objeto ServiceConnection.
  • O terceiro parâmetro é um sinalizador que indica as opções de vinculação. Geralmente, ele deve ser BIND_AUTO_CREATE para criar o serviço se não estiver ativo ainda. Outros possíveis valores são BIND_DEBUG_UNBIND e BIND_NOT_FOREGROUND ou 0 para nada.

Observações adicionais

A seguir, há algumas observações importantes sobre a vinculação com um serviço:

  • Deve-se sempre capturar exceções DeadObjectException, que são lançadas quando a conexão apresenta erros. Essa é a única exceção lançada por métodos remotos.
  • Objetos são referências contadas entre processos.
  • Geralmente, alterna-se entre a vinculação e a desvinculação durante os momentos crescentes e decrescentes do ciclo de vida do cliente. Por exemplo:
    • Se precisar interagir com o serviço enquanto a atividade estiver visível, será necessário vincular durante onStart() e desvincular durante onStop().
    • Caso queira que a atividade receba mensagens mesmo quando for interrompida em segundo plano, é possível vincular durante onCreate() e desvincular durante onDestroy(). Cuidado, pois isso significa que a atividade precisa usar o serviço durante todo o tempo de execução (mesmo em segundo plano). Portanto, se o serviço estiver em outro processo, o peso do processo será aumentado e é mais provável que o sistema o elimine.

    Observação: Geralmente, não se realiza o vínculo e seu rompimento durante o onResume() e o onPause() da atividade, pois esses retornos de chamada ocorrem em todas as transições do ciclo de vida e deve-se usar o mínimo de processamento nessas transações. Além disso, se várias atividades no aplicativo se vincularem ao mesmo serviço e houver uma transação entre duas dessas atividades, o serviço poderá ser destruído e recriado à medida que a atividade se desvincula (durante a pausa), antes do próximo vínculo (durante a retomada). (Essa transição de atividade para como as atividades coordenam os ciclos de vida é descrita no documento Atividades ).

Para obter mais códigos de exemplo mostrando como vincular a um serviço, consulte a classe RemoteService.java no ApiDemos.

Gerenciamento do ciclo de vida de um serviço vinculado

Quando um serviço é desvinculado de todos os clientes, o sistema Android o destrói (a não ser que ele também tenha sido inicializado com onStartCommand()). Portanto, não é necessário gerenciar o ciclo de vida do serviço se ele for puramente um serviço vinculado — o sistema Android o gerencia com base nos vínculos com os clientes.

No entanto, se você escolher implementar o método de retorno de chamada onStartCommand(), interrompa o serviço explicitamente, pois o serviço já terá sido considerado como iniciado. Nesse caso, o serviço permanece em execução até ser interrompido com stopSelf() ou outras chamadas de componente stopService() independentemente de estar vinculado a qualquer cliente.

Além disso, se o serviço for iniciado e aceitar associação, quando o sistema chamar o método onUnbind(), será possível retornar true opcionalmente se você quiser receber uma chamada de onRebind() na próxima vez em que um cliente se associar ao serviço. onRebind() retorna vazio, mas o cliente ainda recebe IBinder no retorno de chamada onServiceConnected(). Abaixo, a figura 1 ilustra a lógica para esse tipo de ciclo de vida.

Figura 1. Ciclo de vida para um serviço que é iniciado e também permite vínculos.

Para obter mais informações sobre o ciclo de vida de um serviço iniciado, consulte o documento Serviços.