Visão geral dos serviços vinculados

Um serviço vinculado é o servidor em uma interface cliente-servidor. Isso permite que componentes (como atividades) sejam vinculados ao serviço, enviem solicitações, recebam respostas e 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 descreve como criar um serviço vinculado, inclusive como realizar a vinculação ao serviço em outros componentes do aplicativo. Para ver mais informações sobre serviços de forma geral, por exemplo, como enviar notificações em um serviço e como definir o serviço a ser executado em primeiro plano, consulte a documento Serviços.

Noções básicas

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ê precisa implementar o método de callback 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.

Vinculação a um serviço iniciado

Como discutido no documento Serviços, é possível criar um serviço que já tenha sido iniciado e vinculado. Ou seja, é possível iniciar um serviço chamando startService(), que permite que ele permaneça em execução indefinidamente e também que um cliente se vincule a ele chamando bindService().

Se você permitir que o serviço seja iniciado e vinculado, quando ele for iniciado, o sistema não vai destruí-lo quando todos os clientes forem desvinculados. Em vez disso, interrompa o serviço explicitamente chamando stopSelf() ou stopService().

Apesar de normalmente você implementar onBind() ou onStartCommand(), às vezes é necessário implementar ambos. Por exemplo, um player de música pode achar útil permitir que seu serviço permaneça em execução indefinidamente, além de fornecer a vinculação. Desta forma, uma atividade pode iniciar o serviço para reproduzir algumas músicas. O áudio continuará em reprodução mesmo quando o usuário sair do aplicativo. Em seguida, quando o usuário voltar ao aplicativo, a atividade poderá ser vinculada ao serviço para retomar o controle da reprodução.

Para ver mais informações sobre o ciclo de vida do serviço ao adicionar a vinculação a um serviço iniciado, consulte Como gerenciar o ciclo de vida de um serviço vinculado.

O cliente poderá vincular-se a um serviço chamando bindService(). Quando isso ocorre, é preciso fornecer uma implementação de ServiceConnection, que monitora a conexão com o serviço. O valor de retorno de bindService() indica se o serviço solicitado existe e se o cliente tem permissão para acessá-lo. Quando o sistema Android cria a conexão entre o cliente e o serviço, ele chama onServiceConnected() em ServiceConnection. O método onServiceConnected() inclui um argumento IBinder, usado pelo cliente para se comunicar com o serviço vinculado.

Você pode conectar vários clientes a um serviço simultaneamente. No entanto, o sistema armazena em cache o canal de comunicação do serviço IBinder. Em outras palavras, o sistema chama o método onBind() do serviço para gerar o IBinder somente quando o primeiro cliente é vinculado. Assim, o sistema entrega o mesmo IBinder a todos os outros clientes vinculados ao mesmo serviço, sem chamar onBind() novamente.

Quando o último cliente se desvincula do serviço, o sistema o destrói, a menos 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 callback onBind() retornará. A seção a seguir discute diferentes maneiras de definir a interface IBinder do seu serviço.

Como criar um serviço vinculado

Ao criar um serviço que fornece vinculação, você precisa 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:

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

Essa é a técnica mais recomendada quando o serviço é meramente um worker de segundo plano para o próprio 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.

Como usar um mensageiro
Caso você precise que a interface funcione em diferentes processos, é possível criar uma interface para o serviço com um 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 a comunicação entre processos (IPC), já que o Messenger coloca todas as solicitações em fila em uma única linha de execução para que você não precise projetar o serviço para que seja seguro para linhas de execução.

Como usar AIDL
A Linguagem de definição de interface do Android (AIDL) decompõe os objetos em primitivos que o sistema operacional possa entender e os organiza em processos para realizar a IPC. A técnica anterior, usando o Messenger, tem base na AIDL como a estrutura subjacente. Como mencionado acima, o Messenger cria uma fila de todas as solicitações de cliente em uma única linha de execução para que o serviço receba uma solicitação por vez. No entanto, se você quiser que o serviço processe várias solicitações simultaneamente, poderá usar a AIDL diretamente. Nesse caso, seu serviço precisa ser seguro para linhas de execução e ser compatível com vários delas.

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

Observação: a maioria dos aplicativos não precisa usar a AIDL para criar um serviço vinculado, porque isso requer a capacidade de usar várias linhas de execução 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 o documento AIDL.

Como estender a classe Binder

Se o serviço for usado somente pelo aplicativo local e não precisar funcionar em outros 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 funcionará somente se o cliente e o serviço estiverem 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 áudio em segundo plano.

Veja aqui como configurar esse recurso:

  1. No seu serviço, crie uma instância de Binder que cumpra uma das seguintes condições:
    • Contenha métodos públicos que o cliente possa chamar.
    • Retorne ao cliente a instância Service atual, que tenha métodos públicos que ele possa chamar.
    • 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 callback onBind().
  3. No cliente, receba o Binder do método de callback onServiceConnected() e faça chamadas para o serviço vinculado usando os métodos fornecidos.

Observação: o serviço e o cliente precisam estar no mesmo aplicativo para que o cliente possa transmitir o objeto retornado e chamar as APIs adequadamente. O serviço e o cliente também precisam estar no mesmo processo, já que essa técnica não realiza o marshaling entre processos.

Por exemplo, veja um serviço que fornece aos clientes acesso aos métodos com uma implementação de 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);
    }
}

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() no serviço.

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

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 were something that might hang, then this request should
            // occur 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 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 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;
        }
    };
}

O exemplo acima mostra como o cliente vincula-se a um serviço usando uma implementação de ServiceConnection e o callback 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 precisam ser desvinculados de serviços em momentos adequados, conforme discutido nas Observações adicionais.

Para ver mais exemplos de código, consulte as classes LocalService.java e LocalServiceActivities.java em ApiDemos.

Como usar um mensageiro

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

Usar um Messenger para sua interface é mais fácil que usar a AIDL, já que Messenger cria uma fila com todas as chamadas para o serviço. Uma interface AIDL pura envia solicitações simultâneas para o serviço, que precisará gerenciar várias linhas de execução.

Para a maioria dos aplicativos, o serviço não precisa lidar com várias linhas de execução. Portanto, o uso de Messenger permite que ele lide com uma chamada por vez. Caso seja importante que o serviço seja compatível com várias linhas de execução, use a AIDL para definir a interface.

Veja a seguir um resumo sobre como usar um Messenger.

  1. O serviço implementa um Handler que recebe um callback para cada chamada de um cliente.
  2. O serviço usa o Handler para criar um objeto Messenger (que é uma referência para Handler).
  3. O Messenger cria um IBinder que o serviço retorna aos clientes de onBind().
  4. Os clientes usam IBinder para instanciar o Messenger (que faz referência ao Handler do serviço), que usam para enviar objetos Message para o serviço.
  5. O serviço recebe cada Message no respectivo Handler, especificamente, no método handleMessage().

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.

Veja a seguir um exemplo simples de serviço que usa uma interface 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();
    }
}

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

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

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

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

Veja um exemplo de como fornecer mensagens bidirecionais nas amostras MessengerService.java (serviço) e MessengerServiceActivities.java (cliente).

Vinculação a um serviço

Componentes de aplicativo (clientes) podem 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, e bindService() é retornado imediatamente sem retornar IBinder ao cliente. Para receber o IBinder, o cliente precisa criar uma instância de ServiceConnection e transmiti-la para bindService(). O ServiceConnection inclui um método de callback que o sistema chama para enviar o IBinder.

Observação: somente atividades, serviços e provedores de conteúdo podem se vincular a um serviço. Isso não é possível em um broadcast receiver.

Para vinculação a um serviço no seu cliente, siga estas etapas:

  1. Implemente ServiceConnection.

    Sua implementação precisa substituir dois métodos de callback:

    onServiceConnected()
    O sistema chama isso para enviar o IBinder retornado pelo método onBind() do serviço.
    onServiceDisconnected()
    O sistema Android faz essa chamada quando a conexão ao serviço é perdida inesperadamente, por exemplo, quando o serviço falha ou é fechado de forma repentina. Isso não é chamado quando o cliente desfaz a vinculação.
  2. Chame bindService(), transmitindo a implementação ServiceConnection.

    Observação: se o método retornar “falso”, seu cliente não terá uma conexão válida com o serviço. No entanto, seu cliente ainda precisará chamar unbindService(). Caso contrário, seu cliente impedirá que o serviço seja desligado quando estiver ocioso.

  3. Quando o sistema chama o método de callback 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 o cliente ainda estiver vinculado a um serviço quando o app 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 adequados para realizar a vinculação e desvinculação, consulte Outras observações.

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

Com esse ServiceConnection, o cliente pode se vincular a um serviço transmitindo-o para bindService(), como mostrado neste exemplo:

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);
  • O primeiro parâmetro de bindService() é um Intent que nomeia explicitamente o serviço que será vinculado.

    Cuidado: se você usar uma intent para vinculação a um Service, use uma intent explícita para verificar se o app é seguro. O uso de uma intent implícita para iniciar um serviço representa um risco de segurança, porque não é possível determinar qual serviço responderá à intent, e o usuário não poderá ver qual serviço será iniciado. A partir do Android 5.0 (API de nível 21), o sistema gera uma exceção se você chama bindService() com uma intent implícita.

  • O segundo parâmetro é o objeto ServiceConnection.
  • O terceiro parâmetro é uma sinalização que indica as opções de vinculação. Normalmente, ela precisa ser BIND_AUTO_CREATE para criar o serviço, se ainda não estiver ativo. Outros valores possíveis são BIND_DEBUG_UNBIND e BIND_NOT_FOREGROUND ou 0, se não houver nenhum.

Outras observações

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

  • É sempre necessário capturar exceções DeadObjectException, que são geradas 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, é necessário parear a vinculação e a desvinculação durante os momentos crescentes e decrescentes do ciclo de vida do cliente, conforme descrito nos exemplos a seguir.
    • Se precisar interagir com o serviço enquanto a atividade estiver visível, será necessário realizar a vinculação durante onStart() e a desvinculação durante onStop().
    • Caso você queira que a atividade receba respostas mesmo quando for interrompida em segundo plano, é possível realizar a vinculação durante onCreate() e a desvinculação durante onDestroy(). Cuidado, porque 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: em geral, não se realiza a vinculação e desvinculação durante onResume() e onPause() da atividade. Isso porque esses callbacks ocorrem em todas as transições do ciclo de vida, e é preciso usar o mínimo de processamento nessas transições. Além disso, se várias atividades no aplicativo se vincularem ao mesmo serviço e houver uma transição entre duas dessas atividades, o serviço poderá ser destruído e recriado à medida que a atividade atual se desvincula (durante a pausa), antes da próxima vinculação (durante a retomada). Essa transição de atividade para como as atividades coordenam os ciclos de vida é descrita no documento Atividades.

Para ver mais exemplos de código mostrando como realizar a vinculação a um serviço, consulte a classe RemoteService.java em ApiDemos.

Como gerenciar o ciclo de vida de um serviço vinculado

Quando um serviço é desvinculado de todos os clientes, o sistema Android o destrói (a menos que ele também tenha sido inicializado com uma chamada startService()). Portanto, não é necessário gerenciar o ciclo de vida do serviço se ele é puramente um serviço vinculado. O sistema Android o gerencia com base nas vinculações com os clientes.

No entanto, se você escolher implementar o método de callback onStartCommand(), interrompa o serviço explicitamente, porque ele já terá sido considerado iniciado. Nesse caso, o serviço permanecerá em execução até ser interrompido com stopSelf() ou que outro componente chame stopService(), independentemente de estar ou não vinculado a qualquer cliente.

Além disso, se o serviço for iniciado e aceitar vinculação, quando o sistema chamar seu método onUnbind(), você poderá retornar true se quiser receber uma chamada para onRebind() na próxima vez que um cliente se vincular ao serviço. onRebind() retorna "void", mas o cliente ainda recebe o IBinder no callback onServiceConnected(). A figura a seguir ilustra a lógica desse tipo de ciclo de vida.

Figura 1. O ciclo de vida de um serviço que é iniciado e também permite vinculação.

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