Um Service
é um
componente do aplicativo que pode executar
operações de longa duração em segundo plano. Ele não fornece uma interface do usuário. Depois
de iniciado, um serviço pode continuar em execução por algum tempo, mesmo depois que o usuário muda para outro
aplicativo. Além disso, um componente pode se vincular a um serviço para interagir com ele e até mesmo realizar
comunicação entre processos (IPC). Por exemplo, um serviço pode processar transações de rede, tocar
música, realizar E/S de arquivos ou interagir com um provedor de conteúdo, tudo em segundo plano.
Atenção:um serviço é executado na linha de execução principal do processo de hospedagem. O serviço não cria a própria linha de execução e não é executado em um processo separado, a menos que você especifique o contrário. Execute todas as operações de bloqueio em uma linha de execução separada no serviço para evitar erros de "O app não está respondendo" (ANR, na sigla em inglês).
Tipos de serviços
Veja os três tipos diferentes de serviços:
- Primeiro plano
-
Um serviço em primeiro plano executa alguma operação que é perceptível para o usuário. Por exemplo, um app de áudio usaria um serviço em primeiro plano para reproduzir uma faixa de áudio. Os serviços em primeiro plano precisam mostrar uma notificação. Os serviços em primeiro plano continuam em execução mesmo quando o usuário não está interagindo com o app.
Ao usar um serviço em primeiro plano, você precisa mostrar uma notificação para que os usuários saibam que o serviço está em execução. Essa notificação não pode ser dispensada, a menos que o serviço seja interrompido ou removido do primeiro plano.
Saiba mais sobre como configurar serviços em primeiro plano no app.
Observação:a API WorkManager oferece uma maneira flexível de programar tarefas e pode executar esses jobs como serviços em primeiro plano, se necessário. Em muitos casos, é preferível usar o WorkManager em vez de usar os serviços em primeiro plano diretamente.
- Contexto
- Um serviço em segundo plano executa uma operação que não é notada diretamente
pelo usuário. Por exemplo, se um app usasse um serviço para compactar o armazenamento,
ele seria um serviço em segundo plano.
Observação:se o app for destinado ao nível 26 da API ou mais recente, o sistema vai impor restrições à execução de serviços em segundo plano quando o app não estiver em primeiro plano. Na maioria das situações, por exemplo, não é possível acessar informações de local em segundo plano. Em vez disso, programe tarefas usando o WorkManager.
- Vinculado
- Um serviço é vinculado quando um componente de aplicativo é vinculado a ele chamando
bindService()
. Um serviço vinculado oferece uma interface cliente-servidor que permite que os componentes interajam com o serviço, enviem solicitações, recebam resultados e até mesmo façam isso em processos com comunicação entre processos (IPC). Um serviço vinculado é executado apenas quando outro componente do aplicativo está vinculado a ele. Vários componentes podem se vincular ao serviço de uma só vez, mas quando todos eles se desvinculam, o serviço é destruído.
Embora esta documentação discuta serviços iniciados e vinculados separadamente,
seu serviço pode funcionar de duas maneiras: ele pode ser iniciado (para ser executado indefinidamente) e também permitir
vinculação. Basta implementar alguns métodos de callback: onStartCommand()
para permitir que os componentes sejam iniciados e onBind()
para permitir a vinculação.
Independentemente de o serviço ser iniciado, vinculado ou ambos, qualquer componente do aplicativo
pode usar o serviço (mesmo em um aplicativo separado) da mesma maneira que qualquer componente pode usar
uma atividade, iniciando-a com um Intent
. No entanto, é possível declarar
o serviço como privado no arquivo de manifesto e bloquear o acesso de outros aplicativos.
Isso é discutido mais na seção sobre Como declarar o serviço no
manifesto.
Como escolher entre um serviço e um thread
Um serviço é simplesmente um componente que pode ser executado em segundo plano, mesmo quando o usuário não interage com o aplicativo. Portanto, crie um serviço apenas se for necessário.
Se você precisar realizar um trabalho fora da linha de execução principal, mas apenas enquanto o usuário estiver interagindo
com o aplicativo, crie uma nova linha de execução no contexto de outro componente
do aplicativo. Por exemplo, se você quiser tocar uma música, mas apenas enquanto a atividade estiver em execução,
crie uma linha de execução em onCreate()
,
inicie a execução em onStart()
e pare em onStop()
.
Também considere usar pools de linhas de execução e executores do pacote java.util.concurrent
ou Corrotinas do Kotlin em vez da classe
Thread
tradicional. Consulte o documento
Linhas de execução no Android para mais informações sobre
como mover a execução para linhas de execução em segundo plano.
Lembre-se de que, se você usar um serviço, ele ainda será executado na linha de execução principal do aplicativo por padrão. Portanto, ainda é necessário criar uma nova linha de execução no serviço se ele executar operações intensivas ou de bloqueio.
Noções básicas
Para criar um serviço, você precisa criar uma subclasse de Service
ou usar uma
das subclasses dele. Na implementação, é necessário substituir alguns métodos de callback que
processam aspectos importantes do ciclo de vida do serviço e fornecem um mecanismo que permite que os componentes
se associem ao serviço, se apropriado. Estes são os métodos de callback mais importantes que você precisa
substituir:
onStartCommand()
- O sistema invoca esse método chamando
startService()
quando outro componente (como uma atividade) solicita que o serviço seja iniciado. Quando esse método é executado, o serviço é iniciado e pode ser executado em segundo plano indefinidamente. Se você implementar isso, será sua responsabilidade interromper o serviço quando o trabalho for concluído, chamandostopSelf()
oustopService()
. Se você quiser apenas fornecer a vinculação, não será necessário implementar esse método. onBind()
- O sistema invoca esse método chamando
bindService()
quando outro componente quer se vincular ao serviço (por exemplo, para executar RPC). Na implementação desse método, é necessário fornecer uma interface que os clientes usem para se comunicar com o serviço, retornando umIBinder
. Você sempre precisa implementar esse método. No entanto, se você não quiser permitir a vinculação, retorne null. onCreate()
- O sistema invoca esse método para executar procedimentos de configuração únicos quando o serviço é
criado inicialmente (antes de chamar
onStartCommand()
ouonBind()
). Se o serviço já estiver em execução, esse método não será chamado. onDestroy()
- O sistema invoca esse método quando o serviço não é mais usado e está sendo destruído. Seu serviço precisa implementar isso para limpar todos os recursos, como linhas de execução, listeners registrados ou receptores. Essa é a última chamada que o serviço recebe.
Se um componente iniciar o serviço chamando startService()
(o que resulta em uma chamada para onStartCommand()
), o serviço
continuará em execução até ser interrompido com stopSelf()
ou outro
componente o interromper chamando stopService()
.
Se um componente chamar
bindService()
para criar o serviço e onStartCommand()
não for chamado, o serviço será executado
apenas enquanto o componente estiver vinculado a ele. Depois que o serviço é desvinculado de todos os clientes,
ele é destruído pelo sistema.
O sistema Android interrompe um serviço apenas quando a memória está baixa e precisa recuperar os recursos
do sistema para a atividade que tem o foco do usuário. Se o serviço estiver vinculado a uma atividade que tenha o foco
do usuário, será menos provável que ele seja encerrado. Se o serviço for declarado para ser executado em primeiro plano, ele raramente será encerrado.
Se o serviço for iniciado e tiver longa duração, o sistema vai diminuir a posição
na lista de tarefas em segundo plano ao longo do tempo, e o serviço se tornará altamente suscetível a
encerramento. Se o serviço for iniciado, ele precisará ser projetado para processar reinicializações
pelo sistema. Se o sistema encerrar o serviço, ele será reiniciado assim que os recursos estiverem
disponíveis, mas isso também depende do valor retornado de onStartCommand()
. Para mais informações
sobre quando o sistema pode destruir um serviço, consulte o documento
Processos e linhas de execução.
Nas seções a seguir, você vai aprender a criar os métodos de serviço
startService()
e
bindService()
, além de como usá-los
em outros componentes do aplicativo.
Declaração de serviço no manifesto
Declare todos os serviços no arquivo de manifesto do seu app, assim como você faz com atividades e outros componentes.
Para declarar seu serviço, adicione um elemento <service>
como filho do elemento
<application>
. Confira um exemplo:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Consulte a referência do elemento
<service>
para mais informações sobre como declarar seu serviço no manifesto.
Há outros atributos que podem ser incluídos no elemento <service>
para
definir propriedades, como as permissões necessárias para iniciar o serviço e o processo em
que ele será executado. O atributo android:name
é o único atributo obrigatório. Ele especifica o nome da classe do serviço. Depois
de publicar o aplicativo, deixe esse nome inalterado para evitar o risco de interromper
o código devido à dependência de intents explícitas para iniciar ou vincular o serviço (leia a postagem do blog, Itens
que não podem ser mudados).
Cuidado: para garantir que o app esteja protegido, use sempre uma
intent explícita ao iniciar um Service
e não declare filtros de intent para
os serviços. 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 vai responder à intent, e o usuário não pode conferir qual serviço
será iniciado. No Android 5.0 (nível 21 da API) e versões mais recentes, o sistema gera uma exceção se você chamar
bindService()
com uma intent implícita.
Para garantir que o serviço esteja disponível apenas para seu app,
inclua o atributo android:exported
e defina-o como false
. Isso impede que outros apps iniciem seu
serviço, mesmo quando usando uma intent explícita.
Observação:
os usuários podem conferir quais serviços estão em execução no dispositivo. Se eles encontrarem
um serviço que não reconhecem ou em que não confiam, podem interromper o serviço. Para
evitar que o serviço seja interrompido acidentalmente pelos usuários, adicione o
atributo
android:description
ao elemento
<service>
no manifesto do app. Na descrição,
forneça uma frase curta explicando o que o serviço faz e quais benefícios
ele oferece.
Criação de um serviço iniciado
Um serviço iniciado é aquele que outro componente inicia chamando startService()
, o que resulta em uma chamada para o método
onStartCommand()
do serviço.
Quando um serviço é iniciado, ele tem um ciclo de vida 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. Portanto, o serviço precisa ser interrompido quando o job
for concluído chamando stopSelf()
, ou outro componente pode
interrompê-lo chamando stopService()
.
Um componente de aplicativo, como uma atividade, pode iniciar o serviço chamando startService()
e transmitindo um Intent
que especifica o serviço e inclui todos os dados que ele precisa usar. O serviço recebe
essa Intent
no método onStartCommand()
.
Por exemplo, imagine que uma atividade precise salvar alguns dados em um banco de dados on-line. A atividade
pode iniciar um serviço complementar e transmitir os dados a serem salvos transmitindo uma intent para startService()
. O serviço recebe a intent em onStartCommand()
, se conecta à Internet e realiza a
transação do banco de dados. Quando a transação é concluída, o serviço é interrompido e
destruído.
Atenção:um serviço é executado no mesmo processo do aplicativo em que é declarado e na linha de execução principal desse aplicativo por padrão. Se o serviço realizar operações intensas ou de bloqueio enquanto o usuário interage com uma atividade do mesmo aplicativo, o serviço vai diminuir a performance da atividade. Para evitar impactos no desempenho do aplicativo, inicie uma nova linha de execução no serviço.
A classe Service
é a classe base
de todos os serviços. Ao estender essa classe, é importante criar uma nova linha de execução em que
o serviço possa concluir todo o trabalho. Por padrão, o serviço usa a linha de execução principal do
aplicativo, o que pode diminuir a performance de qualquer atividade que ele esteja executando.
O framework do Android também fornece a subclasse IntentService
de Service
, que usa uma
linha de execução de worker para processar todas as solicitações de início, uma por vez. O uso dessa classe não
é recomendado para novos apps, porque ela não funciona bem a partir do Android 8 Oreo devido à
introdução dos limites de execução em segundo plano.
Além disso, o uso foi descontinuado a partir do Android 11.
É possível usar o JobIntentService como um
substituto para IntentService
que seja compatível com versões mais recentes do Android.
As seções a seguir descrevem como implementar seu próprio serviço personalizado. No entanto, é recomendável usar o WorkManager para a maioria dos casos de uso. Consulte o guia de processamento em segundo plano no Android para saber se há uma solução que atenda às suas necessidades.
Extensão da classe Service
É possível estender a classe Service
para processar cada intent recebida. Confira como uma implementação básica pode ficar:
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 processa todas as chamadas recebidas em onStartCommand()
e publica o trabalho em uma Handler
em execução em uma linha de execução em segundo plano. Ele funciona como um IntentService
e processa todas as solicitações em série, uma após a outra.
Você pode mudar o código para executar o trabalho em um pool de linhas de execução, por exemplo, se quiser executar várias solicitações simultaneamente.
O método onStartCommand()
precisa retornar um
número inteiro. O número inteiro é um valor que descreve como o sistema precisa continuar o serviço caso ele seja encerrado. O valor de retorno
de onStartCommand()
precisa ser uma das seguintes
constantes:
START_NOT_STICKY
- Se o sistema encerrar o serviço após o retorno de
onStartCommand()
, não recrie o serviço, a menos que haja intents pendentes para entrega. Essa é a opção mais segura para evitar a execução do serviço quando não for necessário e quando o aplicativo puder simplesmente reiniciar os trabalhos inacabados. START_STICKY
- Se o sistema encerrar o serviço após o retorno de
onStartCommand()
, recrie o serviço e chameonStartCommand()
, mas não envie novamente a última intent. Em vez disso, o sistema chamaonStartCommand()
com uma intent nula, a menos que haja intents pendentes para iniciar o serviço. Nesse caso, essas intents são enviadas. Isso é adequado para players de mídia (ou serviços semelhantes) que não estão executando comandos, mas estão em execução indefinidamente e aguardando um job. START_REDELIVER_INTENT
- Se o sistema encerrar o serviço após o retorno de
onStartCommand()
, recrie o serviço e chameonStartCommand()
com a última intent que foi enviada ao serviço. Quaisquer intents pendentes são entregues um de cada vez. Isso é adequado para serviços que estão executando ativamente um job que precisa ser retomado imediatamente, como o download de um arquivo.
Para mais detalhes sobre esses valores de retorno, consulte a documentação de referência vinculada para cada constante.
Iniciar um serviço
É possível iniciar um serviço de uma atividade ou de outro componente do app
transmitindo um Intent
para startService()
ou startForegroundService()
. O
sistema Android chama o método onStartCommand()
do serviço e o transmite o Intent
,
que especifica qual serviço iniciar.
Observação: se o app for destinado ao nível 26 da API ou mais recente, o sistema
vai impor restrições ao uso ou à criação de serviços em segundo plano, a menos que o app
esteja em primeiro plano. Se um app precisar criar um serviço em primeiro plano,
ele precisará chamar startForegroundService()
. Esse método cria um serviço em segundo plano, mas o
método sinaliza para o sistema que o serviço será promovido para
o primeiro plano. Depois que o serviço é criado, ele precisa chamar o
método startForeground()
em
até cinco segundos.
Por exemplo, uma atividade pode iniciar o serviço de exemplo na seção anterior (HelloService
) usando uma intent explícita com startService()
, conforme mostrado aqui:
Kotlin
startService(Intent(this, HelloService::class.java))
Java
startService(new Intent(this, HelloService.class));
O método startService()
é retornado 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 vai chamar onCreate()
primeiro e depois
onStartCommand()
.
Se o serviço não fornecer vinculação, a intent enviada com startService()
será o único modo de comunicação entre o
componente do aplicativo e o serviço. No entanto, 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 enviá-lo ao serviço
no Intent
que inicia o serviço. O serviço pode usar a
transmissão para gerar um resultado.
Várias solicitações para iniciar o serviço resultam em várias chamadas correspondentes ao
onStartCommand()
do serviço. No entanto, apenas uma solicitação para interromper
o serviço (com stopSelf()
ou stopService()
) é necessária.
Interromper um serviço
Um serviço iniciado precisa gerenciar o próprio ciclo de vida. Ou seja, o sistema não interrompe nem
destrói o serviço, a menos que precise recuperar a memória do sistema e o serviço
continue sendo executado após o retorno de onStartCommand()
. O
serviço precisa ser interrompido chamando stopSelf()
, ou outro
componente pode fazer isso chamando stopService()
.
Depois que o sistema é solicitado a parar com stopSelf()
ou stopService()
, ele destrói o serviço o mais rápido
possível.
Se o serviço processar várias solicitações para onStartCommand()
simultaneamente, não pare o
serviço quando terminar de processar uma solicitação de início, porque você pode ter recebido uma nova
solicitação de início. Parar no final da primeira solicitação encerraria a segunda. Para evitar
esse problema, use stopSelf(int)
para garantir que a solicitação de
parada do serviço seja sempre baseada na solicitação de início mais recente. Ou seja, quando você chama stopSelf(int)
, transmite o ID da solicitação de início (o startId
enviado para onStartCommand()
) ao qual a solicitação de parada
corresponde. Se o serviço receber uma nova solicitação de início antes que você possa chamar stopSelf(int)
, o ID não vai corresponder e o serviço não vai ser interrompido.
Cuidado:para evitar o desperdício de recursos do sistema e o consumo
de bateria, verifique se o app interrompe os serviços quando ele para de funcionar.
Se necessário, outros componentes podem interromper o serviço chamando stopService()
. Mesmo que você ative a vinculação para o serviço,
é necessário sempre interromper o serviço se ele receber uma chamada para onStartCommand()
.
Para mais informações sobre o ciclo de vida de um serviço, consulte a seção abaixo sobre Como gerenciar o ciclo de vida de um serviço.
Como criar um serviço vinculado
Um serviço vinculado permite que os componentes do aplicativo sejam vinculados a ele chamando bindService()
para criar uma conexão de longa duração.
Geralmente, ele não permite que os componentes o iniciem chamando startService()
.
Crie um serviço vinculado quando quiser interagir com o serviço de atividades e outros componentes no seu aplicativo ou para expor algumas das funcionalidades do seu aplicativo a outros aplicativos por meio da comunicação interprocesso (IPC).
Para criar um serviço vinculado, implemente o método de callback onBind()
para retornar um IBinder
que
define a interface para comunicação com o serviço. Outros componentes do aplicativo podem chamar
bindService()
para recuperar a interface e
começar a chamar métodos no serviço. O serviço existe apenas para atender ao componente do aplicativo
vinculado a ele. Portanto, quando não há componentes vinculados ao serviço, o sistema o destrói.
Não é necessário 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. Essa interface entre o serviço
e um cliente precisa ser uma implementação de IBinder
e é o que o serviço precisa
retornar do método de callback onBind()
. Depois que o cliente recebe o IBinder
, ele pode começar
a interagir com o serviço por essa interface.
Vários clientes podem se vincular ao serviço por vez. Quando um cliente termina de interagir com
o serviço, ele chama unbindService()
para desvincular.
Quando não houver clientes vinculados ao serviço, o sistema o eliminará.
Há várias maneiras de implementar um serviço vinculado, e a implementação é mais complicada do que um serviço iniciado. Por esses motivos, a discussão sobre serviços vinculados aparece em um documento separado sobre Serviços vinculados.
Envio de notificações ao usuário
Quando um serviço está em execução, ele pode notificar o usuário sobre eventos usando notificações de barra de informações ou notificações de barra de status.
Uma notificação de snackbar é uma mensagem que aparece na superfície da janela atual por apenas um momento antes de desaparecer. Uma notificação na barra de status fornece um ícone na barra de status com uma mensagem que o usuário pode selecionar para realizar uma ação, como iniciar uma atividade.
Normalmente, uma notificação na barra de status é a melhor técnica a ser usada quando um trabalho em segundo plano, como um download de arquivo, é concluído e o usuário pode agir em relação a ele. Quando o usuário seleciona a notificação na visualização expandida, ela pode iniciar uma atividade, como mostrar o arquivo transferido por download.
Gerenciamento do ciclo de vida de um serviço
O ciclo de vida de um serviço é muito mais simples do que o de uma atividade. No entanto, é ainda mais importante prestar atenção em como o serviço é criado e destruído, porque ele pode ser executado em segundo plano sem que o usuário perceba.
O ciclo de vida do serviço, desde a criação até a destruição, pode seguir uma destas duas opções:
- Um serviço iniciado
O serviço é criado quando outro componente chama
startService()
. O serviço é executado indefinidamente e precisa ser interrompido chamandostopSelf()
. Outro componente também pode interromper o serviço chamandostopService()
. Quando o serviço é interrompido, o sistema o elimina. - Um serviço vinculado
O serviço é criado quando outro componente (um cliente) chama
bindService()
. Em seguida, o cliente se comunica com o serviço por uma interfaceIBinder
. O cliente pode fechar a conexão chamandounbindService()
. Vários clientes podem se vincular ao mesmo serviço, e quando todos eles se desvinculam, o sistema destrói o serviço. O serviço não precisa ser interrompido.
Esses dois caminhos não são totalmente separados. É possível vincular a um serviço que já
foi iniciado com startService()
. Por exemplo, é possível
iniciar um serviço de música em segundo plano chamando startService()
com um Intent
que identifica a música a ser tocada. Mais tarde,
possivelmente quando o usuário quiser exercer algum controle sobre o player ou receber informações sobre a
música atual, uma atividade poderá ser vinculada ao serviço chamando bindService()
. Em casos como esse, stopService()
ou stopSelf()
não interrompem o serviço até que todos os clientes sejam desvinculados.
Implementação dos callbacks do ciclo de vida
Assim como uma atividade, um serviço tem métodos de callback do ciclo de vida que podem ser implementados para monitorar mudanças no estado do serviço e realizar trabalhos nos momentos adequados. O serviço de esqueleto a seguir demonstra cada um dos métodos de 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 funonCreate
() { // The service is being created } override funonStartCommand
(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind
(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind
(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind
(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy
() { // 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 voidonCreate
() { // The service is being created } @Override public intonStartCommand
(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()
return startMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return binder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return allowRebind; } @Override public voidonRebind
(Intent intent) { // A client is binding to the service withbindService()
, // after onUnbind() has already been called } @Override public voidonDestroy
() { // The service is no longer used and is being destroyed } }
Observação:ao contrário dos métodos de callback do ciclo de vida da atividade, não é necessário chamar a implementação da superclasse desses métodos de callback.
A figura 2 ilustra os métodos de callback tradicionais para um serviço. Embora a figura separe
os serviços criados por startService()
dos
criados por bindService()
, lembre-se
de que qualquer serviço, não importa como ele é iniciado, pode permitir que os clientes se conectem a ele.
Um serviço que foi inicialmente iniciado com onStartCommand()
(por um cliente que chama startService()
)
ainda pode receber uma chamada para onBind()
(quando um cliente chama
bindService()
).
Ao implementar esses métodos, você pode monitorar estes dois loops aninhados do ciclo de vida do serviço:
- O ciclo de vida completo de um serviço ocorre entre o momento em que
onCreate()
é chamado e o momento em queonDestroy()
retorna. Assim como uma atividade, um serviço faz a configuração inicial emonCreate()
e libera todos os recursos restantes emonDestroy()
. Por exemplo, um serviço de reprodução de música pode criar a linha de execução em que a música é tocada emonCreate()
e, em seguida, pode interromper a linha de execução emonDestroy()
.Observação: os métodos
onCreate()
eonDestroy()
são chamados para todos os serviços, sejam eles criados porstartService()
oubindService()
. - O tempo de atividade de um serviço começa com uma chamada para
onStartCommand()
ouonBind()
. Cada método recebe oIntent
que foi transmitido parastartService()
oubindService()
.Se o serviço for iniciado, o ciclo de vida ativo será encerrado ao mesmo tempo que todo o ciclo de vida será encerrado (o serviço ainda estará ativo mesmo depois que
onStartCommand()
retornar). Se o serviço estiver vinculado, o tempo de atividade vai terminar quandoonUnbind()
retornar.
Observação:embora um serviço iniciado seja interrompido por uma chamada para
stopSelf()
ou stopService()
, não há um callback correspondente para o
serviço (não há um callback onStop()
). A menos que o serviço esteja vinculado a um cliente,
o sistema o destrói quando ele é interrompido. onDestroy()
é o único callback recebido.
Para mais informações sobre como criar um serviço que fornece vinculação, consulte o documento Serviços vinculados,
que inclui mais informações sobre o método de callback onRebind()
na seção sobre Como gerenciar o ciclo de vida de
um serviço vinculado.