Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

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 criar vínculos com o serviço em outros componentes do aplicativo. Para ver 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., consulte a documentação Serviços.

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 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 com um serviço iniciado

Como discutido na documentação Serviços, é possível criar um serviço que já foi iniciado e vinculado. Ou seja, o serviço pode ser iniciado chamando startService(), que permite que permaneça em execução indefinidamente e também que um cliente se vincule a ele com chamada de bindService().

Se você permitir que o serviço seja iniciado e vinculado, quando ele for iniciado, o sistema não o destruirá quando todos os clientes desfizerem a associação. Em vez disso, interrompa o serviço explicitamente chamando stopSelf() ou stopService().

Apesar de normalmente você implementar onBind() ou onStartCommand(), às vezes será necessário implementar ambos. Por exemplo, um reprodutor de música pode achar útil permitir que seu serviço permaneça em execução indefinidamente, além de fornecer associação. Desta forma, uma atividade pode iniciar o serviço para reproduzir algumas músicas e a música continuará em reprodução mesmo quando o usuário sair do aplicativo. Em seguida, quando o usuário voltar ao aplicativo, a atividade poderá se associar 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 Gerenciamento do ciclo de vida de um serviço vinculado.

O cliente poderá vincular 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 do serviço onBind() para gerar IBinder somente quando o primeiro cliente é vinculado. Assim o sistema entrega o mesmo IBinder a todos os clientes adicionais vinculados ao mesmo serviço, 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 callback onBind() retornará. A seção a seguir discute diferentes maneiras de definir a interface IBinder do seu serviço.

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 de Service.

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), já que o Messenger coloca todas as solicitações em fila em um único thread para que você não precise projetar o serviço de modo que seja seguro para encadeamentos.

Uso de AIDL
O AIDL (Android Interface Definition Language) decompõe os objetos em primitivos que o sistema operacional possa entender e organizá-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 thread para que o serviço receba uma solicitação por vez. No entanto, se você quiser que o serviço lide com várias solicitações simultaneamente, será possível usar a AIDL diretamente. Nesse caso, seu serviço precisa ser seguro para threads e ser compatível com vários threads.

Para usar a AIDL diretamente, é preciso 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 se 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 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 música em segundo plano.

Como configurar:

  1. No seu serviço, crie uma instância de Binder que faça o seguinte:
    • 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.
    • 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 lançar 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 tem 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:

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() do 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 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 devem ser desvinculados de serviços em momentos apropriados, conforme é discutido nas Observações adicionais.

Para ver 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.

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 precisa gerenciar vários threads.

Para a maioria dos aplicativos, o serviço não precisa realizar vários threads. Portanto, usar Messenger permite que o serviço lide com uma chamada por vez. Caso seja importante que o serviço realize vários threads, use a AIDL para definir a interface.

A seguir há 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 menciona o Handler do serviço), que usam para enviar objetos Message para o serviço.
  5. O serviço recebe cada Message no 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.

Abaixo há 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 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:

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, será necessário criar um Messenger também no cliente. Em seguida, quando o cliente receber o callback 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 e bindService() é retornado imediatamente sem retornar IBinder ao cliente. Para receber IBinder, o cliente precisa criar uma instância de ServiceConnection e passá-la para bindService(). O ServiceConnection inclui um método de callback 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 broadcast receiver.

Para vincular um serviço do seu cliente, siga estas etapas:

  1. Implemente ServiceConnection.

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

    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 falha ou é fechado de forma repentina. Isso não é chamado quando o cliente desfaz o vínculo.
  2. Chame bindService(), passando 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 deverá 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 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.

O exemplo 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:

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 passando-o para bindService(), como mostrado no exemplo a seguir:

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.

    Atenção: se você usar um intent para vincular um Service, use um intent explícito para verificar se o aplicativo é seguro. O uso de um intent implícito para iniciar um serviço representa um risco de segurança, porque não é possível determinar qual serviço responderá ao intent e o usuário não poderá ver que serviço é iniciado. A partir do Android 5.0 (API de nível 21), o sistema lança uma exceção ao chamar bindService() com um intent implícito.

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

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, é preciso 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 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: em geral, não se realiza o vínculo e seu rompimento 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 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 ver 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 callback 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 callback onServiceConnected(). A figura a seguir ilustra a lógica desse tipo de ciclo de vida.

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

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