Um Serviço é um componente da aplicação que pode executar operações em segundo plano e não fornece uma interface com o usuário. Um outro componente da aplicação pode iniciar um serviço e ele continuará a ser executado em segundo plano mesmo se o usuário passar a usar outra aplicação. Adicionalmente, um componente pode se conectar a um serviço para interagir com ele e até mesmo executar comunicação inter processos (IPC). Por exemplo, um serviço pode manipular transações de rede, tocas música, executar entrada e saída de arquivos, ou interagir com um fornecedor de conteúdo, tudo em segundo plano,
Um serviço pode essencialmente tomar duas formas:
- Started
- Um serviço está na forma “Started” quando um componente da aplicação (como uma Atividade) inicia-o pela chamada a
startService()
. Uma vez iniciado, um serviço pode rodar em segundo plano indefinitivamente, mesmo se o componente que o iniciou for destruído. Normalmente, um serviço iniciado executa uma única operação e não retorna um resultado para o componente que o chamou. Por exemplo, ele pode baixar ou enviar um arquivo através da rede. Quando a operações for completada, o serviço deve se auto interromper. - Bound
- Um serviço está na forma “bound” quando um componente da aplicação se liga a ele pela chamada a
bindService()
. Um serviço nessa forma oferece uma interface cliente-servidor que permite que os componentes interajam com ele, enviem requisições, obtenham resultados, e mesmo executando alguma comunicação inter processos (IPC). Um serviço conectado é executado apenas durante o tempo que o outro componente da aplicação estiver conectado a ele. Múltiplos componentes podem se conectar ao serviço de uma vez, mas quando todos se desconectarem, o serviço é destruído.
Apesar desse artigo geralmente discutir esses dois tipos de serviço separadamente, seu serviço pode trabalhar das duas formas – pode ser iniciado (para rodar indefinitivamente0 e também permitir conexões. É simplesmente uma questão de implementar um dos métodos de chamada: onStartCommand()
para permitir que os componentes o iniciem e onBind()
para permitir conexões.
Não importa se a forma tomada é iniciada, conectada ou ambas, qualquer componente da aplicação pode usar o serviço (mesmo de uma aplicação separada), da mesma forma que qualquer componente pode usar uma Atividade – iniciando ele com um Intent
. Porém, você pode declarar um serviço como private, no arquivo de manifesto, e bloquear o acesso de outras aplicações.
Cuidado: Um serviço roda na thread principal do processo que o hospeda – o serviço não cria a sua própria thread e não roda em um processo separado (a menos que você especifique de outra forma). Isso significa que, se o seu serviço for fazer uso intensivo da CPU ou bloqueio de operações (como em execução de um MP3 ou operações de rede), você deve criar uma nova thread que inclua o serviço para fazer o trabalho. Pelo uso de uma thread separada, você reduz o risco de erros de “Application Not Responding (ANR)” e a thread principal da aplicação pode permanecer dedicada as interações com o usuário.
O Básico
Para criar um serviço, você deve criar um sub-classe de Service
(ou uma de suas sub-classes existentes). Em sua implementação, você precisa sobrecarregar alguns métodos de chamada que manipulam aspectos chave do ciclo de vida do serviço e fornecem mecanismos para que os componentes se conectem ao serviço, se for apropriado. Os métodos mais importantes a serem sobrecarregados são:
onStartCommand()
- O sistema chama esse método quando outro componente, como uma atividade, requisita que esse serviço seja iniciado, através da chamada ao método
startService()
. Uma vez que esse método seja executado, o serviço é iniciado e pode rodar em segundo plano indefinitivamente. Se você implementar esse método, é sua responsabilidade para o serviço quando o trabalho estiver feito, pela chamada aos métodosstopSelf()
oustopService()
. (se você quiser fornecer apenas conexões com outros componentes, não precisa implementar esse método). onBind()
- O sistema chama esse método quando outro componente quer se conectar com o serviço (como para executar RPC), através da chamada ao método
bindService()
. Em sua implementação dessa método, você deve fornecer uma interface que os clientes usarão para se comunicar com o serviço, através do retorno de umIBinder
. Você deve sempre implementar esse método, mas se não quiser que o serviço se conecte com outros componentes, então deve retornar null. onCreate()
- O sistema chama esse método quando o serviço é criado pela primeira vez, para executar procedimento de configuração (antes de chamar
onStartCommand()
oronBind()
). Se o serviço estiver sendo executado, esse método não é chamado. onDestroy()
- O sistema chama esse método quando o serviço não for mais ser usado e estiver sendo destruído. Seu serviço deve implementar esse método para liberar qualquer recurso como threads, listeners registrados, receiver, etc. Essa é a última chamada que o serviço recebe.
Se um componente inicia o serviço pela chamada a startService()
(o que resulta na chamada a onStartCommand()
), então o serviço permanece em execução até que interrompa ele mesmo com stopSelf()
ou outro componente o interrompa pela chamada a stopService()
.
Se um componente chama bindService()
para criar o serviço (e nesse caso onStartCommand()
não é chamado), então o serviço é executado apenas enquanto o componente estiver conectado. Uma vez que o serviço for desconectado de todos os clientes, o sistema o destrói.
O sistema Android forçará o interrompimento do serviço apenas quando a memória estiver baixa e precisar recuperar recursos do sistema para a atividade que o usuário estiver executando no momento. Se o serviço estiver conectado a uma atividade que o usuário estiver executando, então ela tem menos chances de ser interrompida, e se o serviço for declarado para rodar em primeiro plano, ele quase nunca será interrompido. Em outros casos, se o serviço foi iniciado e está em execução a muito tempo, então o sistema diminuirá a sua posição na lista de tarefas do segundo plano no decorrer do tempo e o serviço estará mais suscetível a ser encerrado – se o seu serviço for iniciado, então você precisa desenhado de modo pode manipular reinícios pelo sistema. Se o sistema encerrar o seu serviço, ele será reiniciado assim que recursos estiverem disponíveis novamente (embora isso também dependa do valor que você retorna de onStartCommand()
).
Declarando um serviço no manifesto
Como as atividades (e outros componentes), você deve declarar todos os serviços no arquivo de manifesto. Para declarar o seu serviço, adicione um elemento <service> como filho do elementos <application>. Por exemplo:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Existem outros atributos que você pode incluir no elemento <service> para definir propriedades com permissões necessárias para iniciar o serviço e o processo onde o serviço deve rodar. O atributo android:name é o único atributo obrigatório – ele especifica o nome da classe do serviço. Uma vez que tiver publicado a sua aplicação, você não deve alterar esse nome, porque se fizer isso, pode quebrar alguma funcionalidade onde intents explícitos são usados para fazer referência a seu serviço.
Como no caso das atividades, um serviço pode definir filtros que permitam que outros componentes invoquem o serviço usando intents implícitos. Ao declarar esses filtros, os componentes que qualquer plicação instalada no dispositivo do usuário poderá iniciar o seu serviço e ele declarar um filtro que coincida com o intent que a outra aplicação passe ao método startService()
.
Se o seu plano for usar seu serviço apenas localmente (outras aplicações não o usarão), então você não precisa (e não deve) fornecer nenhum filtro. Sem nenhuma filtro declarado, você deverá iniciar o serviço usando um intent que explicitamente nomeie a classe do serviço.
Adicionalmente, você pode garantir que o seu serviço seja privativo a sua aplicação apenas incluindo o atributo android:exportes e ajustando seu valor para “false”. Isso é efetivo mesmo se o seu serviço fornecer algum filtro.
Criando um serviço do tipo Started
Um serviço do tipo “started” é um que outro componente inicia pela chamada ao método startService()
, resultando em um chamada ao método onStartCommand()
do serviço.
Quando um serviço é iniciado, possui um ciclo de vida independente do componente que o iniciou, e o serviço pode ser executado em segundo plano indefinitivamente, mesmo que o componente que o iniciou seja destruído. Dessa forma, o serviço deve interromper ele mesmo quando suas tarefas forem concluidas pela chamada ao método stopSelf()
, ou outro componente pode interrompe-lo pela chamada ao método stopService()
.
Um componente da aplicação como uma atividade pode iniciar o serviço através do método startService()
passando um Intent
que especifica o serviço e inclui qualquer dados necessários ao serviço. O serviço recebe esse Intent
no método onStartCommand()
.
Por exemplo, suponhamos que uma atividade precise salvar algum dado em um banco de dados on-line. A atividade pode iniciar um serviço e passar os dados a serem salvos passando um intent para startService()
. O serviço recebe o intent em onStartCommand()
, conecta-se a Internet e executa a transação no banco de dados. Quando a transação for concluída, o serviço se auto interrompe e é destruído.
Cuidado: Um serviço roda no mesmo processo da aplicação que o declara e na mesma thread dela, por padrão. Dessa forma, se o seu serviço executa muitas operações de bloqueio enquanto o usuário interage com uma atividade da mesma aplicação, o serviço irá diminuir a performance da aplicação. Para evitar impacto na performance da aplicação, você deve iniciar uma nova thread para o serviço.
Tradicionalmente, existem duas classes que você pode estender para criar um serviço do tipo “started”:
Service
- Essa é a classe base para todos os serviços. Quando você estende essa classes, é importante que você crie uma nova thread para executar todas as tarefas dos serviço, por que se o serviço usar a thread principal de sua aplicação, isso pode afetar a performance das outras atividades que sua aplicação estiver executando.
IntentService
- Essa é uma sub-classe de
Service
que usa uma thread de trabalho para manipular todas as requisições iniciadas. Essa é melhor opção se você não precisar que seu serviço manipule múltiplas requisições ao mesmo tempo. Tudo o que você precisa fazer é implementaronHandleIntent()
, que receberá o Intent de cada requisição de forma que você possa fazer o trabalho do segundo plano.
As seções a seguir descrevem como você pode implementar seu serviço usando uma dessas duas classes.
Estendendo a classe IntentService
Por muitos serviços não precisarem manipular múltiplas requisições ao mesmo tempo (o que pode normalmente ser um cenário perigoso de multi-threading), é provavelmente melhor se você implementar o seu serviço usando a classe IntentService
.
A classe IntentService
faz o seguinte:
- Cria uma thread de trabalho padrão que processo todos os Intents entregues pelo método
onStartCommand()
de forma separada da thread principal de sua aplicação. - Crua uma fila de trabalho que passe um Intent por vez para sua implementação de
onHandleIntent()
, de forma que você nunca tenha que se preocupar com multi-threading, - Interrompe o serviço após todas as requisições terem sido manipuladas, de forma que você nunca tenha que usar
stopSelf()
. - Fornece uma implementação padrão de
onBind()
que retorna null. - Fornece uma implementação padrão de
onStartCommand()
que envia o Intent para a fila de trabalho e em seguida para a implementação deonHandleIntent(
)
.
Tudo isso é feito para que você precise implementar somente o método onHandleIntent()
para fazer o trabalho fornecido pelo cliente (Além disso, você também precisa implementar um pequeno construtor para o serviço).
Abaixo segue um exemplo de implementação para IntentService
:
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread. */ public HelloIntentService() { super("HelloIntentService"); } /** * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } } }
Isso é tudo o que você precisa: um construtor e uma implementação de onHandleIntent()
.
Se você decidir usar também outros métodos, como onCreate()
, onStartCommand()
, ou onDestroy()
, certifique-se de chamar a implementação super, de forma que IntentService
possa manipular de forma apropriada o ciclo de vida da thread.
Por exemplo, onStartCommand()
precisa retornar a implementação padrão (que é como o Intent é entregue a onHandleIntent()
):
@Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent,flags,startId); }
Além de onHandleIntent()
, o único método para o qual você não precisa chamar a super classe é onBind()
(mas você precisa apenas implementa-la se o seu serviço permitir ligações).
Na próxima seção, você verá como o mesmo tipo de serviço é implementado quando se estende a classe Service
, o que significa mais código, mas isso pode ser adequado se você precisa manipular requisições simultâneas.
Estendendo a classe Service
Como você viu na seção anterior, usar IntentService
torna sua implementação do serviço muito simples. Se, porém, você precisar que seu serviço execute multi-threading (ao invés de processar as requisições através de uma fila), então você pode estender a classe Service
para manipular cada Intent.
Para efeito de comparação, o código abaixo é uma implementação da classe Service
que faz a mesma coisa que o exemplo acima faz. Isso e, para cada requisição, usa uma thread para executar a tarefa e processa apenas uma requisição por vez.
public class HelloService extends Service { private Looper mServiceLooper; private ServiceHandler mServiceHandler; // 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. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } // 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 will not 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 mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @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 = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.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(); } }
Como você pode ver, é necessário um pouco mais de trabalho que o uso de IntentService
.
Porém, por você poder manipular cada chamada onStartCommand(), pode executar múltiplas requisições ao mesmo tempo. Isso não é o que o exemplo faz, mas é o que você quer, então você pode criar uma nova thread para cada requisição e executa-las diretamente (ao invés de esperar pela execução da requisição anterior).
Observe que o método onStartCommand()
precisa retornar um inteiro. O inteiro é um valor que descreve como o sistema deve continuar o serviço cado ele mate o serviço (como discutido acima, a implementação padrão de IntentService
cuida disso para você, apesar de ser possivel modificar isso). O valor de retorno para onStartCommand()
precisa ser uma das seguintes constantes:
START_NOT_STICKY
- Se o sistema mata o serviço depois que o método
onStartCommand()
retorna um valor, não recriar o serviço, a menos que existam Intents pendentes a serem entregues. Essa é a opção mais segura para evitar executar o serviço sem necessidade e quando sua aplicação pode simplesmente reiniciar qualquer tarefa não concluída. START_STICKY
- Se o sistema mata o serviço depois que o método
onStartCommand()
retorna um valor, recriar o serviço e chamar o métodoonStartCommand()
, mas não re-entregar o último Intent. Ao invés disso, o sistema chama o métodoonStartCommand()
com um Intent nulo, a menos que existam Intent pendentes para iniciar o serviço, nesse caso, esses Intents serão entrregues. Essa forma é adequada para tocadores de mídia que não estão executando comando, mas sendo executados indefinitivamente e aguardando por uma tarefa. START_REDELIVER_INTENT
- Se o sistema mata o serviço depois que o método
onStartCommand()
retorna um valor, recria o serviço e chama o métodoonStartCommand()
passando como parâmetro o último Intent que foi entregue ao serviço. Qualquer Intent pendente será entregue em seguida. Essa forma é adequada para serviços que estejam executando uma tarefa que deveria ser continuada imediatamente, como o download de um arquivo.
Iniciando um serviço
Você pode iniciar um serviço a partir de uma atividade ou de outro componente da aplicação apenas passando um Intent (especificando o serviço a ser iniciado) para o método startService()
. O sistema Android chamada o método onStartCommand()
do serviço e passa com parâmetro o Intent
. (Você nunca deve chamar onStartCommand()
diretamente).
Por exemplo, uma atividade pode iniciar o serviço do exemplo da seção anterior usando explicitamente o Intent com o método startService()
:
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 não estiver sendo executado, o sistema chama primeiro onCreate()
, e em seguida onStartCommand()
.
Se o serviço não permitir ligações, o Intent entregue com startService()
é a única forma de comunicação entre os componentes da aplicação e o serviço. Porém, se você quiser que o serviço retorne um resultado, então o cliente que inicia o serviço pode criar um PendingIntent
para transmitir (com getBroadcast()
) e entrega-lo ao serviço. O serviço poderá então usar essa transmissão para entregar um resultado.
Requisições múltiplas para iniciar o serviço resultam em múltiplas chamadas ao método onStartCommand()
. Porém, apenas uma requisição para interromper o serviço (com stopSelf()
ou stopService()
) é necessária para para-los.
Interrompendo um serviço
Um serviço do tipo “started” precisa gerenciar seu ciclo de vida. Isso é, o sistema não irá interromper ou destruir o serviço a menos que precise de espaço de memória e o serviço continua a ser executado depois que o método onStartCommand()
retorna um valor. Dessa forma, o serviço precisa se auto interromper através do método stopSelf()
ou outro componente pode interrompe-lo pela chamada a stopService()
Uma vez que seja requisitado a interrupção do serviço com stopSelf()
ou stopService()
, o sistema destrói o serviço assim que for possível.
Porém, se o seu serviço manipula múltiplas requisições simultâneas a onStartCommand()
, então você não deve interromper o serviço quando estiver processando uma requisição, por que pode ter recebido uma nova requisição para iniciar o serviço (interromper ao final da primeira requisição interromperá a segunda). Para evitar esse problema, você pode usar stopSelf(int)
para garantir que sua requisição para interromper o serviço seja sempre baseada na requisição mais recente. Isso é, quando você chama stopSelf(int)
, passa o ID da requisição (o atributo startId entregue a onStartCommand()
) que quer interromper. Assim se o serviço receber uma nova requisição antes de você ser pode chamar stopSelf(int)
, então o ID não corresponderá e serviço não será interrompido.
Cuidado: É importante que sua aplicação interrompa seus serviços quando finalizar suas tarefas, para evitar desperdiçar recursos do sistema e consumir a bateria. Se necessário, outros componentes podem interromper o serviço através do método stopService()
. Mesmo se você tiver permitido ligações no serviço, sempre pode interromper o serviço você mesmo mesmo se ele tiver recebido um chamada para onStartCommand()
.
Criando um serviço no modo Bound
Um serviço do tipo “bound” é um que permite que os componentes da aplicação se liguem a ele através do método bindService()
de forma a criar um conexão (e geralmente não permite que os componentes o iniciem pelo método startService()
).
Você deve criar um serviço desse tipo quando quiser interagir com o serviço através da atividades e outros componentes de sua aplicação ou para expor algumas das funcionalidades da sua aplicação para outras, através de comunicação inter-processos (IPC).
Para criar esse tipo de serviço, você precisa implementar o método onBind()
para retornar um IBinder
que defina a interface para comunicação com o serviço. Outros componentes da aplicação podem então chamar bindService()
para obter acesso a interface e iniciar as chamadas aos métodos do serviço. O serviço existe apenas para servir ao componente ao qual ele está ligado, de forma que quando não houver componentes ligados ao serviço, o sistema destrói ele (você não precisa interromper o serviço da forma que precisa fazer quando o serviço é iniciado pelo método onStartCommand()
).
Para criar um serviço do tipo “bound”, a primeira coisa que você precisa fazer é definir a interface que especifica como um cliente pode se comunicar com o serviço. Essa interface entre o serviço e o cliente deve ser uma implementação de IBinder
e é o que o seu serviço deve retornar a prtir do método onBind()
. Uma vez que o cliente receba IBinder
, pode começar a interagir com o serviço através da interface.
Múltiplos clientes podem interagir com o serviço ao mesmo tempo. Quando um cliente não precisar mais interagir com o serviço, ele chama unbindService()
para desfazer a conexão. Quando não houverem mais clientes conectados ao serviço, o sistema o destruirá.
Existem várias maneiras de implementar esse tipo de serviço e essas implementações são mais complicadas do que as implementações do tipo “started”, de forma que as discussões sobre esse tipo podem ser vistas no documento Bound Services.
Enviando notificações o usuário
Quando o serviço estiver em execução, pode enviar notificações de eventos ao usuário usando Toast Notifications ou Status Bar Notifications.
Uma notificação “toast” é uma mensagem que aparece na superfície da janela atual por um momento e desaparece em seguida, enquanto uma notificação da barra de status fornece um ícone na barra de status com uma mensagem, que o usuário pode selecionar de modo a executar alguma ação (como iniciar uma atividade).
Normalmente, uma notificação na barra de status é a melhor técnica quando uma tarefa executada em segundo plano é completada (como o download de arquivo) e o usuário pode trabalhar nele. Quando o usuário seleciona a notificação na visão expandida da barra de status, a notificação pode iniciar uma atividade (como a visualização do arquivo baixado).
Rodando um serviço em primeiro plano
Um serviço executado em primeiro plano é um serviço que é considerado como algo de que o usuário está ciente dele e que não é um candidato a ser morto pelo sistema em caso de necessidade de liberação de memória. Um serviço em primeiro plano precisa fornecer uma notificação na barra de status, que é colocada sob o cabeçalho “Ongoing”, o que significa que a notificação não irá ser descartada a menos que ou o serviço seja interrompido ou removido do primeiro plano.
Por exemplo, um tocado de música que toque uma música a partir de um serviço poderia ser configurado para rodar em primeiro plano, porque o usuário está ciente da sua execução. A notificação na barra de status pode indicar a música atual e permitir que o usuário carregue a atividade para interagir com o tocador.
Para fazer com que seu serviço seja executado em primeiro plano, chame o método startForeground()
. Esse método pede dois parâmetros: um inteiro que identifique de forma única a notificação e a Notification
para a barra de status. Por exemplo:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), System.currentTimeMillis()); Intent notificationIntent = new Intent(this, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), pendingIntent); startForeground(ONGOING_NOTIFICATION, notification);
Para remover o serviço do primeiro plano, chame o método stopForeground()
. Esse método pede um parâmetro booleano, indicando se a notificação será removida da barra de status também. Esse método não interrompe o serviço. Porém, se você interromper o serviço enquanto estiver sendo executado em primeiro plano, a notificação será removida também.
Gerenciando o ciclo de vida de um serviço
O ciclo de vida de um serviço é muito mais simples que o de uma atividade. Porém, é importante que você preste atenção a forma como o seu serviço é criado e destruído, porque um serviço pode ser executado em segundo plano sem a ciência do usuário.
O ciclo de vida do serviço – desde sua criação até sua destruição – pode seguir dois caminhos diferentes:
- Um serviço do tipo “started”: é criado quando outro componente chama o método
startService()
. O serviço então fica em execução indefinitivamente e precisa se auto interromper através da chamada ao métodostopSelf()
. Outro componente também pode interromper o serviço através do métodostopService()
. Quando o serviço é interrompido, o sistema o destrói. - Um serviço do tipo “bound”: é criado quando outro componente (um cliente) chama o método
bindService()
. O cliente se comunica com o serviço através de uma interfaceIBinder
. O cliente pode encerrar a conexão através do métodounbindService()
. Múltiplos clientes pode se conectar ao mesmo serviço e quando todos eles se desconectarem, o sistema destrói o serviço (o serviço não precisa se auto interrromper).
Esses dois caminhos não são inteiramente separados. Isso é, você pode se conectar a um serviço que tenha sido iniciado com startService()
. Por exemplo, um serviço de música em segundo plano poderia ser iniciado pelo método startService()
com um Intent
que identifica a música que está sendo tocada. Mais tarde, possivelmente quando o usuário quiser ter algum controle sobre o tocador ou obter informações sobre a música atual, uma atividade pode se conectar ao serviço através de uma chamada a bindService()
. Em casos como esse, stopService()
ou stopSelf()
não interrompem o serviço até que todos os clientes tenham se desconectado.
Implementando as chamadas relacionadas ao ciclo de vida
Como uma atividade, um serviço métodos para o seu ciclo de vida que você pode implementar para monitorar as mudanças no estado do serviço e executar alguma tarefa nos momentos apropriados. O esqueleto abaixo demonstra cada método relacionado ao ciclo de vida do serviço:
public class ExampleService extends Service { int mStartMode; // indicates how to behave if the service is killed IBinder mBinder; // interface for clients that bind boolean mAllowRebind; // 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 mStartMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return mBinder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return mAllowRebind; } @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 } }

Pela implementação desses métodos, você pode monitorar dois loops embutidos no ciclo de vida do serviço:
- O ciclo de vida global do serviço é o que acontece entre a chamada a
onCreate()
e a chamada aonDestroy()
. Como no caso das atividades, um serviço tem uma configuração inicial criada no métodoonCreate()
e libera todos os recursos usados através do métodoonDestroy()
. - O ciclo de vida ativo de um serviço começa quando se chama
onStartCommand()
ouonBind()
. Cada método manipula oIntent
que foi passado ou parastartService()
ou parabindService()
, respectivamente. Se o serviço é do tipo “started”, o ciclo ativo termina ao mesmo tempo que o ciclo global termina (o serviço ainda estará ativo após o retorno do métodoonStartCommand()
). Se o serviço for do tipo “bound”, se ciclo ativo termina quando for chamado o métodoonUnbind()
.
Para mais informações sobre a criação de um serviço que permita conexões, veja o documento Bound Services, que inclui mais informações sobre o método onRebind()
na seção Managing the Lifecycle of a Bound Service.
Traduzido de http://developer.android.com/guide/topics/fundamentals/services.html