A Service
é um componente aplicacional que pode executar operações em segundo plano. Ele não fornece uma interface de usuário. Oncestarted, um serviço pode continuar rodando por algum tempo, mesmo depois que o usuário mudar para outra aplicação. Além disso, um componente pode ligar-se a um serviço para interagir com ele e até mesmo executar comunicação interprocessada (IPC). Por exemplo, um serviço pode lidar com transações de rede, playmusic, executar I/O de arquivo, ou interagir com um provedor de conteúdo, tudo a partir do fundo.
Cautela: Um serviço corre na linha principal do seu processo de alojamento; o serviço não cria a sua própria linha e não executa um processo em separado, a menos que especifique o contrário. Você deve executar qualquer operação de bloqueio em uma thread separada dentro do serviço para evitar erros de ApplicationNot Responding (ANR).
- Tipos de Serviços
- Selecionar entre um serviço e uma thread
- >O básico
- Declarando um serviço no manifesto
- Criar um serviço iniciado
- Extendendo a classe de serviço
- Kotlin
- Java
- Iniciar um serviço
- Kotlin
- Java
- Parar um serviço
- Criando um serviço ligado
- Enviar notificações ao usuário
- Gerenciar o ciclo de vida de um serviço
- Implementando as chamadas de retorno do ciclo de vida
- Kotlin
- Java
Tipos de Serviços
Estes são os três tipos diferentes de serviços:
Foreground
Um serviço em primeiro plano executa alguma operação que é perceptível para o usuário. Por exemplo, um aplicativo de áudio usaria um serviço foreground para reproduzir uma faixa de áudio. Os serviços em primeiro plano devem exibir uma Notificação. Os serviços em primeiro plano continuam sendo executados mesmo quando o usuário não está interagindo com o app.
Quando você usa um serviço em primeiro plano, você deve exibir uma notificação para que os usuários estejam ativamente cientes de que o serviço está sendo executado. Esta notificação não pode ser descartada a menos que o serviço seja parado ou removido do foreground.
Aprenda mais sobre como configurar serviços foreground no seu app.
Nota: A API do WorkManager oferece uma forma flexível de agendar tarefas, e é capaz de executar estes trabalhos como serviços foreground, se necessário. Em muitos casos, o uso do WorkManager é preferível ao uso direto dos serviços foreground.
Background Um serviço em background executa uma operação que não é diretamente notada pelo usuário. Por exemplo, se um aplicativo usasse um serviço para compactar seu armazenamento, isso normalmente seria um serviço em segundo plano.
Nota: Se a sua aplicação tem como alvo o nível 26 ou superior da API, o sistema impõe restrições na execução de serviços em segundo plano quando a própria aplicação não está em primeiro plano. Na maioria das situações, por exemplo, você não deve acessar informações de localização a partir do plano de fundo. Em vez disso, agende tarefas usando o WorkManager.
Bound A service is bound when an application component binds to it by call
bindService()
. Um serviço vinculado oferece uma interface cliente-servidor que permite aos componentes interagir com o serviço, enviar solicitações, receber resultados e até mesmo fazer isso através de processos com comunicação inter-processo (IPC). Um serviço vinculado é executado apenas enquanto outro componente de aplicação estiver vinculado a ele. Vários componentes podem se ligar ao serviço de uma só vez, mas quando todos eles se desacoplam, o serviço é destruído.
Embora esta documentação geralmente discuta os serviços iniciados e vinculados separadamente, o serviço pode funcionar nos dois sentidos – pode ser iniciado (para rodar indefinidamente) e também permitir a vinculação. É simplesmente uma questão de se você implementar alguns métodos de retorno de chamada: onStartCommand()
para permitir que componentes o iniciem e onBind()
para permitir a ligação.
Independentemente de o seu serviço ser iniciado, ligado, ou ambos, qualquer componente de aplicação pode usar o serviço (mesmo de uma aplicação separada) da mesma forma que qualquer componente pode usar uma atividade – iniciando-o com um Intent
. No entanto, você pode declarar o serviço como privado no arquivo de manifesto e bloquear o acesso de outras aplicações. Isto é discutido mais na seção sobre Declarar o serviço no themanifest.
Selecionar entre um serviço e uma thread
Um serviço é simplesmente um componente que pode ser executado em segundo plano, mesmo quando o usuário não está interagindo com sua aplicação, então você deve criar um serviço somente se isso for o que você precisa.
Se você precisar executar trabalho fora da thread principal, mas somente enquanto o usuário estiver interagindo com seu aplicativo, você deve criar uma nova thread no contexto de outro componente do aplicativo. Por exemplo, se você quiser tocar alguma música, mas somente enquanto sua atividade estiver rodando,você pode criar uma thread em onCreate()
,começar a rodá-la em onStart()
,e pará-la em onStop()
.Considere também o uso de threads e executores do pacote java.util.concurrent
ou coroutinas Kotlin ao invés da tradicional classeThread
. Veja o documentoThreading no Android para mais informações sobre a execução de threads em background.
.Lembre-se que se você usar um serviço, ele ainda será executado no bydefault da thread principal da sua aplicação, então você ainda deve criar uma nova thread dentro do serviço se ele executar operações intensivas ou de bloqueio.
>O básico
.Para criar um serviço, você deve criar uma subclasse de Service
ou usar uma de suas subclasses existentes. Na sua implementação, você deve substituir alguns métodos de callback que tratam de aspectos chave do ciclo de vida do serviço e fornecer um mecanismo que permita que os componentes sejam ligados ao serviço, se apropriado. Estes são os métodos de callback mais importantes que devem ser executados:
onStartCommand()
O sistema invoca este método chamandostartService()
quando outro componente (como uma atividade) solicita que o serviço seja iniciado. Se isso for implementado, é responsabilidade do usuário interromper o serviço quando seu trabalho estiver concluído, chamandostopSelf()
oustopService()
. Se você quiser apenas fornecer binding, você não precisa implementar este método.onBind()
O sistema invoca este método chamandobindService()
quando outro componente quer fazer binding com o serviço (como para executar RPC). Na implementação deste método, você deve fornecer uma interface que os clientes usam para se comunicar com o serviço, retornando umIBinder
. Você deve sempre implementar este método; entretanto, se você não quiser permitir a vinculação, você deve retornar o método.onCreate()
O sistema invoca este método para executar procedimentos de configuração únicos quando o serviço é inicialmente criado (antes de chamar ouonStartCommand()
ouonBind()
). Se o serviço já estiver em execução, este método não é chamado.onDestroy()
O sistema invoca este método quando o serviço não é mais usado e está sendo destruído. Seu serviço deve implementar isto para limpar quaisquer recursos como threads, ouvintes registrados ou receptores. Esta é a última chamada que o serviço recebe.
Se um componente inicia o serviço chamando startService()
(o que resulta em uma chamada para onStartCommand()
), o serviço continua a ser executado até que ele se pare com stopSelf()
ou outro componente o pára chamando stopService()
.
Se um componente chama bindService()
para criar o serviço e onStartCommand()
não é chamado, o serviço é executado apenas enquanto o componente estiver vinculado a ele. Após o serviço não estar vinculado a todos os seus clientes, o sistema o destrói.
O sistema Android pára um serviço apenas quando a memória está baixa e deve recuperar os recursos do sistema para a atividade que tem foco no usuário. Se o serviço estiver vinculado a uma atividade que tem foco no usuário, é menos provável que seja morto; se o serviço for declarado como executado em primeiro plano, raramente é morto. Se o serviço for iniciado e estiver funcionando há muito tempo, o sistema baixa sua posição na lista de tarefas de fundo ao longo do tempo, e o serviço torna-se altamente suscetível ao tokilling- se o seu serviço for iniciado, você deve desenhá-lo para lidar graciosamente com o reinício pelo sistema. Se o sistema mata o seu serviço, ele o reinicia assim que os recursos ficam disponíveis, mas isso também depende do valor que você retorna de onStartCommand()
. Para mais informações sobre quando o sistema pode destruir um serviço, veja o documento Processos e Threadingdocument.
Nas seções seguintes, você verá como você pode criar os métodos de serviçostartService()
ebindService()
, bem como como usá-los a partir de outros componentes de aplicação.
Declarando um serviço no manifesto
Você deve declarar todos os serviços no arquivomanifest da sua aplicação, assim como faz para atividades e outros componentes.
Para declarar seu serviço, adicione um elemento <service>
como um filho do elemento <application>
. Aqui está um exemplo:
>
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application></manifest>
Veja o elemento <service>
para mais informações sobre como declarar seu serviço no manifesto.
Existem outros atributos que você pode incluir no elemento <service>
para definir propriedades tais como as permissões necessárias para iniciar o serviço e o processo em que o serviço deve ser executado. O atributo android:name
attribute é o único atributo necessário – ele especifica o nome da classe do serviço. Após publicar sua aplicação, deixe esse nome inalterado para evitar o risco de quebra de código devido à dependência de intenções explícitas de iniciar ou ligar o serviço (leia o post do blog, Things That Cannot Change).
Cautela: Para garantir que seu aplicativo esteja seguro, sempre use a intenção anexada ao iniciar um Service
e não declare a intenção filtrada para seus serviços. Usar uma intenção implícita para iniciar um serviço é um risco de segurança porque você não pode ter certeza do serviço que responde à intenção, e o usuário não pode ver qual serviço inicia. Começando com o Android 5.0 (nível 21 da API), o sistema lança uma exceção se você chamar bindService()
com uma intenção implícita.
Você pode garantir que seu serviço está disponível apenas para sua aplicação, incluindo o atributo android:exported
e definindo-o para false
. Isto efetivamente impede que outros aplicativos iniciem o seu serviço, mesmo quando usando uma intenção explícita.
Note: Usuários podem ver quais serviços estão rodando no seu dispositivo. Se eles virem um serviço que eles não reconhecem ou não confiam, eles podem parar o serviço. A fim de evitar que o seu serviço seja interrompido acidentalmente pelos usuários, você precisa adicionar o atributo android:description
ao elemento <service>
no manifesto do seu aplicativo. Na descrição, forneça uma pequena frase explicando o que o serviço faz e quais benefícios ele oferece.
Criar um serviço iniciado
Um serviço iniciado é aquele que outro componente começa chamando startService()
, o que resulta em uma chamada para o métodoonStartCommand()
do serviço.
Quando um serviço é iniciado, ele tem um ciclo de vida que é independente do componente que o iniciou. O serviço pode ser executado em segundo plano indefinidamente, mesmo que o componente que o iniciou seja destruído. Como tal, o serviço deve parar a si mesmo quando seu trabalho estiver concluído, chamando stopSelf()
, ou outro componente pode pará-lo chamando stopService()
.
Um componente de aplicação como uma atividade pode iniciar o serviço chamando startService()
e passando um Intent
que especifica o serviço e inclui quaisquer dados para o serviço usar. O serviço recebe este Intent
no método onStartCommand()
.
Por exemplo, suponha que uma tarefa precise gravar alguns dados em um banco de dados on-line. A activitycan inicia um serviço companheiro e entrega-lhe os dados para gravar, passando uma intenção para startService()
. O serviço recebe a intenção em onStartCommand()
, conecta-se à Internet, e realiza a transação da base de dados. Quando a transação é concluída, o serviço pára por si mesmo e é destruído.
Cautela: Um serviço roda no mesmo processo que a aplicação na qual é declarado e na linha principal dessa aplicação por padrão. Se o seu serviceper executa operações intensivas ou de bloqueio enquanto o usuário interage com uma atividade da mesma aplicação, o serviço retarda o desempenho da atividade. Para evitar impacto no desempenho da aplicação, inicie uma nova thread dentro do serviço.
A classe Service
é a baseclass para todos os serviços. Quando você estender esta classe, é importante criar uma nova thread em que o serviço possa completar todo o seu trabalho; o serviço usa o bydefault da thread principal do seu aplicativo, o que pode diminuir o desempenho de qualquer atividade que seu aplicativo esteja rodando.
O framework Android também fornece a IntentService
subclasse de Service
que usa uma threadworker para lidar com todas as solicitações de inicialização, uma de cada vez. O uso desta classe não é recomendado para novos aplicativos, pois não funcionará bem a partir do Android 8 Oreo, devido à introdução de limites de execução em segundo plano. Além disso, é obsoleto a partir do Android 11. Você pode usar o JobIntentService como substituto para IntentService
que é compatível com versões mais recentes do Android.
As seções seguintes descrevem como você pode implementar seu próprio serviço personalizado, no entanto, você deve considerar fortemente o uso do WorkManager em vez de usar para a maioria dos casos de uso. Consulte o guia de processamento em segundo plano no Android para ver se existe uma solução que atenda às suas necessidades.
Extendendo a classe de serviço
Pode estender a classe Service
para lidar com cada intenção de entrada. Veja como uma implementação básica pode parecer:
Kotlin
class HelloService : Service() { private var serviceLooper: Looper? = null private var serviceHandler: ServiceHandler? = null // Handler that receives messages from the thread private inner class ServiceHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000) } catch (e: InterruptedException) { // Restore interrupt status. Thread.currentThread().interrupt() } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1) } } override fun onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply { start() // Get the HandlerThread's Looper and use it for our Handler serviceLooper = looper serviceHandler = ServiceHandler(looper) } } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show() // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job serviceHandler?.obtainMessage()?.also { msg -> msg.arg1 = startId serviceHandler?.sendMessage(msg) } // If we get killed, after returning from here, restart return START_STICKY } override fun onBind(intent: Intent): IBinder? { // We don't provide binding, so return null return null } override fun onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show() }}
Java
public class HelloService extends Service { private Looper serviceLooper; private ServiceHandler serviceHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread().interrupt(); } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work doesn't disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler serviceLooper = thread.getLooper(); serviceHandler = new ServiceHandler(serviceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = serviceHandler.obtainMessage(); msg.arg1 = startId; serviceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don't provide binding, so return null return null; } @Override public void onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); }}
O código de exemplo lida com todas as chamadas de entrada em onStartCommand()
e coloca o trabalho em Handler
correndo em uma thread de fundo. Ele funciona como um IntentService
e processa todas as requisições em série, uma após a outra. Você poderia alterar o código para executar o trabalho em um pool de threads, por exemplo, se você gostaria de executar várias requisições simultaneamente.
Note que o método onStartCommand()
deve retornar o aninteger. O número inteiro é um valor que descreve como o sistema deve continuar o serviço no evento que o sistema o mata. O valor de retorno de onStartCommand()
deve ser um dos seguintesconstantes:
START_NOT_STICKY
Se o sistema mata o serviço apósonStartCommand()
retornar, não recriar o serviço a menos que haja pendências de entrega. Esta é a opção mais segura para evitar executar o seu serviço quando não for necessário e quando a sua aplicação pode simplesmente reiniciar quaisquer trabalhos inacabados.START_STICKY
Se o sistema matar o serviço apósonStartCommand()
retornar, recrie o serviço e ligue paraonStartCommand()
, mas não volte a entregar a última intenção. Ao invés disso, o sistema liga paraonStartCommand()
com intenção nula a menos que haja intenção pendente de iniciar o serviço. Nesse caso, essas intenções são entregues. Isto é adequado para media players (ou serviços similares) que são comandos de notexecuting mas que estão rodando indefinidamente e esperando por um trabalho.START_REDELIVER_INTENT
Se o sistema mata o serviço apósonStartCommand()
retornar, recriar o serviço e chamaronStartCommand()
com a última intenção que foi entregue a este serviço. Qualquer intenção pendente é entregue à vez. Isto é adequado para serviços que estão executando um trabalho que deve ser retomado imediatamente, como o download de um arquivo.
Para mais detalhes sobre estes valores de retorno, veja a referenciação ligada para cada constante.
Iniciar um serviço
Você pode iniciar um serviço a partir de uma atividade ou outro componente de aplicação passando um Intent
para startService()
ou startForegroundService()
. O sistema Android chama o método onStartCommand()
do serviço e passa o método Intent
, que especifica qual serviço iniciar.
Nota: Se o aplicativo tiver como alvo o nível 26 ou superior da API, o sistema impõe restrições ao uso ou criação de serviços em segundo plano, a menos que o próprio aplicativo esteja em primeiro plano. Se uma aplicação precisar criar um serviço em primeiro plano, a aplicação deve chamar startForegroundService()
. Esse método cria um serviço de fundo, mas o método sinaliza para o sistema que o serviço se promoverá a si mesmo em primeiro plano. Uma vez que o serviço tenha sido criado, o serviço deve chamar seu método startForeground()
em cinco segundos.
Por exemplo, uma atividade pode iniciar o serviço de exemplo na seção anterior (HelloService
) usando uma intenção explícita com startService()
, como mostrado aqui:
Kotlin
Intent(this, HelloService::class.java).also { intent -> startService(intent)}
Java
Intent intent = new Intent(this, HelloService.class);startService(intent);
O método startService()
retorna imediatamente, e o sistema Android chama o método onStartCommand()
do serviço. Se o serviço ainda não estiver em execução, o sistema primeiro chama onCreate()
, e depois chama onStartCommand()
.
Se o serviço também não fornecer ligação, a intenção que é entregue com startService()
é o único modo de comunicação entre o componente da aplicação e o serviço. Entretanto, se você quiser que o serviço envie um resultado de volta,o cliente que inicia o serviço pode criar um PendingIntent
para uma transmissão(com getBroadcast()
) e entregá-lo ao serviço no Intent
que inicia o serviço. O serviço pode então usar a transmissão para entregar um resultado.
Múltiplos pedidos para iniciar o serviço resultam em múltiplas chamadas correspondentes ao serviçoonStartCommand()
. No entanto, apenas um pedido para parar o serviço (com stopSelf()
ou stopService()
) é necessário para pará-lo.
Parar um serviço
Um serviço iniciado deve gerenciar seu próprio ciclo de vida. Ou seja, o sistema não pára o serviço a menos que tenha de recuperar a memória do sistema e o serviço continua a funcionar depois de onStartCommand()
regressos. O serviço deve parar ele mesmo chamando stopSelf()
, ou outro componente pode pará-lo chamando stopService()
.
Após ser solicitado a parar com stopSelf()
ou stopService()
, o sistema destrói o serviço assim que possível.
Se o seu serviço lida com várias solicitações para onStartCommand()
simultaneamente, você não deve parar o serviço quando terminar de processar uma solicitação de início, pois você pode ter recebido uma nova solicitação de início (parar no final da primeira solicitação terminaria a segunda). Para evitar este problema, você pode usar stopSelf(int)
para garantir que a sua solicitação seja sempre baseada na mais recente solicitação de início. Ou seja, quando você chama stopSelf(int)
, você passa o ID da solicitação de início (o startId
delivered para onStartCommand()
) ao qual a sua solicitação de parada corresponde. Então, se o serviço recebe uma nova solicitação de início antes de você poder ligar para stopSelf(int)
, o ID não corresponde e o serviço não pára.
Cautela: Para evitar desperdiçar os recursos do sistema e consumir energia da bateria, certifique-se de que a sua aplicação pára os seus serviços quando termina de funcionar. Se necessário, outros componentes podem parar o serviço chamando stopService()
. Mesmo que você habilite a ligação para o serviço, você mesmo deve sempre interromper o serviço se ele alguma vez receber uma chamada para onStartCommand()
.
Para mais informações sobre o ciclo de vida de um serviço, veja a seção abaixo sobre Gerenciamento do ciclo de vida de um serviço.
Criando um serviço ligado
Um serviço ligado é aquele que permite que os componentes da aplicação se liguem a ele chamando bindService()
para criar uma conexão de longa duração.Ele geralmente não permite que componentes o iniciem chamando startService()
.
Criar um serviço vinculado quando você quiser interagir com o serviço a partir de atividades e outros componentes da sua aplicação ou expor algumas das funcionalidades da sua aplicação a outras aplicações através da comunicação inter-processo (IPC).
Para criar um serviço vinculado, implemente o método onBind()
callback para retornar um IBinder
que defina a interface de comunicação com o serviço. Outros componentes de aplicação podem então chamar o métodobindService()
para recuperar a interface e iniciar os métodos de chamada no serviço. O serviço vive apenas para servir o componente de aplicação que está vinculado a ele, portanto, quando não há componentes vinculados ao serviço, o sistema o destrói. Você não precisa interromper um serviço vinculado da mesma forma que você precisa quando o serviço é iniciado por onStartCommand()
.
Para criar um serviço vinculado, você precisa definir a interface que especifica como um cliente pode se comunicar com o serviço. Esta interface entre o serviço e um cliente deve ser uma implementação de IBinder
e é o que seu serviço deve retornar a partir do método onBind()
callback. Após o cliente receber o IBinder
, ele pode começar a interagir com o serviço através dessa interface.
Múltiplos clientes podem se ligar ao serviço simultaneamente. Quando um cliente termina de interagir com o serviço, ele chama unbindService()
para unbind.Quando não há clientes vinculados ao serviço, o sistema destrói o serviço.
Existem várias formas de implementar um serviço vinculado, e a implementação é mais complicada do que um serviço iniciado. Por estes motivos, a discussão sobre o serviço vinculado aparece em um documento separado sobre Bound Services.
Enviar notificações ao usuário
Quando um serviço está sendo executado, ele pode notificar o usuário sobre eventos usando Toast Notifications ou Status Bar Notifications.
Uma notificação de torrada é uma mensagem que aparece na superfície da janela atual por apenas amomento antes de desaparecer. Uma notificação da barra de status fornece um ícone na barra de status com mensagem de erro, que o usuário pode selecionar para tomar uma ação (como iniciar uma atividade).
Usualmente, uma notificação da barra de status é a melhor técnica a ser usada quando o trabalho em background de tal arquivo asa tiver sido concluído, e o usuário pode agora agir sobre ele. Quando o usuário seleciona a notificação a partir da visão expandida, a notificação pode iniciar uma atividade (como para exibir o arquivo baixado).
Ver as Notificações da Barra de Status ou Notificações do Desenvolvedor da Barra de Status para mais informações.
Gerenciar o ciclo de vida de um serviço
O ciclo de vida de um serviço é muito mais simples do que o de uma atividade. Entretanto, é ainda mais importante que você preste atenção em como seu serviço é criado e destruído porque o serviço pode ser executado em segundo plano sem que o usuário esteja ciente.
O ciclo de vida do serviço – de quando é criado até quando é destruído – pode seguir qualquer um desses dois caminhos:
- Um serviço iniciado
O serviço é criado quando outro componente chama
startService()
. O serviço é então executado indefinidamente e deve parar por si mesmo, chamandostopSelf()
. Outro componente também pode parar o serviço chamandostopService()
. Quando o serviço é interrompido, o sistema o destrói.>
- Um serviço vinculado
O serviço é criado quando outro componente (um cliente) chama
bindService()
. O cliente então se comunica com o serviço através de uma interfaceIBinder
. O cliente pode fechar a conexão chamandounbindService()
. Múltiplos clientes podem ligar para o mesmo serviço e quando todos eles se desacoplam, o sistema destrói o serviço. Os servicedoes não precisam se parar.
Estes dois caminhos não são totalmente separados. Você pode se ligar a um serviço que já está iniciado com startService()
. Por exemplo, você pode iniciar um serviço de música de fundo chamando startService()
com um Intent
que identifica a música a tocar. Mais tarde, possivelmente quando o usuário quiser exercer algum controle sobre o player ou obter informações sobre a música atual, uma atividade pode ser vinculada ao serviço chamando bindService()
. Em casos como este, stopService()
ou stopSelf()
não interrompe o serviço até que todos os clientes desvinculem.
Implementando as chamadas de retorno do ciclo de vida
Como uma atividade, um serviço tem métodos de retorno do ciclo de vida que você pode implementar para monitorar as mudanças no estado do serviço e executar o trabalho nos momentos apropriados. O seguinte serviço de esqueleto demonstra cada um dos métodos do ciclo de vida:
Kotlin
class ExampleService : Service() { private var startMode: Int = 0 // indicates how to behave if the service is killed private var binder: IBinder? = null // interface for clients that bind private var allowRebind: Boolean = false // indicates whether onRebind should be used override fun () { // The service is being created } override fun (intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override fun (intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override fun (intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override fun (intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override fun () { // The service is no longer used and is being destroyed }}
Java
public class ExampleService extends Service { int startMode; // indicates how to behave if the service is killed IBinder binder; // interface for clients that bind boolean allowRebind; // indicates whether onRebind should be used @Override public void () { // The service is being created } @Override public int (Intent intent, int flags, int startId) { // The service is starting, due to a call to return startMode; } @Override public IBinder (Intent intent) { // A client is binding to the service with return binder; } @Override public boolean (Intent intent) { // All clients have unbound with return allowRebind; } @Override public void (Intent intent) { // A client is binding to the service with , // after onUnbind() has already been called } @Override public void () { // The service is no longer used and is being destroyed }}
Nota: Ao contrário dos métodos de retorno de chamada do ciclo de vida da atividade, você não precisa chamar a implementação superclasse destes métodos de retorno.
Figure 2. O ciclo de vida de serviço. O diagrama à esquerda mostra o ciclo de vida quando o serviço é criado com startService()
e o diagrama à direita mostra o ciclo de vida quando o serviço é criado com bindService()
.
Figure 2 ilustra os métodos típicos de callback para um serviço. Apesar da figura separar os serviços criados por startService()
dos criados por bindService()
, tenha em mente que qualquer serviço, não importa como foi iniciado, pode potencialmente permitir que os clientes se liguem a ele. Um serviço que foi inicialmente iniciado com onStartCommand()
(por um cliente ligando para startService()
) ainda pode receber uma chamada para onBind()
(quando um cliente liga para bindService()
).
>
A implementação destes métodos permite monitorar estes dois loops aninhados do slifecycle do serviço:
- A vida inteira de um serviço ocorre entre o tempo que
onCreate()
é chamado e o tempo queonDestroy()
retorna. Como uma atividade, um serviço faz sua configuração inicial emonCreate()
e libera todos os recursos restantes emonDestroy()
. Por exemplo, o serviço de reprodução amusic pode criar a thread onde a música é tocada emonCreate()
, e depois pode parar a thread emonDestroy()
.Note: Os métodos
onCreate()
eonDestroy()
são chamados para todos os serviços, sejam eles criados porstartService()
oubindService()
.>
- A vida útil ativa de um serviço começa com uma chamada para
onStartCommand()
ouonBind()
.Cada método recebe oIntent
que foi passado parastartService()
oubindService()
.Se o serviço é iniciado, a vida útil ativa termina ao mesmo tempo em que toda a vida útil termina (o serviço ainda está ativo mesmo depois de
onStartCommand()
retornar). Se o serviço é ligado, a vida útil ativa termina quandoonUnbind()
retorna.
Note: Embora um serviço iniciado seja interrompido por uma chamada stopSelf()
ou stopService()
, não há uma chamada de retorno para o serviço (não há onStop()
chamada de retorno). A menos que o serviço esteja vinculado a um cliente,o sistema o destrói quando o serviço é interrompido-onDestroy()
é a única callback recebida.
Para mais informações sobre a criação de um serviço que forneça ligação, consulte o documento Serviços vinculados,que inclui mais informações sobre o método de boundback onRebind()
na seção sobre Gerenciamento do ciclo de vida de um serviço vinculado.