Desenvolvimento para Android
Aula 7 - Services
Prof. Markus Endler
Services
 Um service é um tipo de componente de uma aplicação Android que é utilizado
para executar operações de longa duração em background
 Services não possuem interface gráfica para o usuário
 São utilizados para operações de rede, processamento intenso, tocar músicas,
etc.
•
•
Por exemplo, em uma aplicação que toca músicas, uma música deve continuar a ser
tocada para o usuário independente do que o mesmo esteja fazendo no dispositivo
A comunicação pela rede pode demorar, e por isso é importante que ocorra de forma
assíncrona (sem bloquear a app)
 Podem executar de forma independente do componente que os criou
•
Se uma activity inicia um service e esta é fechada, o service continuará executando em
background
 Podem ser conectados a quaisquer outros componentes de aplicação (de acordo
com as permissões)
2
 Por exemplo, é possível permitir que qualquer aplicação possa conectar-se ao service e
manipulá-lo
Services – Formas
 Um service pode assumir duas formas:
• Não-conectado (unbounded)
• Um service é criado quando outro componente chama(*) o método startService(),
pasando um Intent
• O service executa indefinidamente (mesmo que o componente criador termine) e pode
se parar chamando o método stopSelf().
• Um outro componente pode parar o service diretamente através do chamado
stopService().
• Quando o service é parado, o sistema destrói o mesmo.
• Conectado (bounded)
• Um service é criado quando outro componente chama o método bindService().
• O componente (cliente) comunica-se com o service pela interface IBinder – podendo
fazer comunicação entre diferentes processos.
• O cliente pode fechar a conexão com o mesmo através da chamada unbindService().
• Múltiplos clientes podem se conectar ao mesmo service e quando todos estes fecham a
conexão, o sistema Android destrói o service.
(*) Em Android, “chamar” significa criar um Intent corresponente.
3
Services – Formas e Ciclo-de-vida
4
Services – Ciclo-de-vida
public class CallbackLifeCycleExampleService extends Service {
int mStartMode;
// indica como se comportar caso o service seja destruído
IBinder mBinder;
// interface para clientes que fazem a conexão com o service
boolean mAllowRebind; // indica se onRebind deve ser utilizado
5
@Override
public void onCreate() {
// O service está sendo criado
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// O service é iniciando devido a uma chamada a startService()
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// Um cliente se conectou ao service usando bindService()
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// Todos os clientes se desconectaram do service usando unbindService()
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
// Um cliente está se re-conectando ao service com bindService(),
// depois de onUnbind() ter sido chamado
}
@Override
public void onDestroy() {
// O service não está sendo mais usado e está sendo destruído
}
}
Services – Informações
 Um mesmo service pode funcionar de ambas as formas, bastando que implemente:
• O método onStartCommand() para permitir que componentes o iniciem
• O método onBind() para permitir que componentes se conectem ao mesmo
 Qualquer componente pode utilizar o service, mesmo aqueles que estejam em
aplicações separadas
• Da mesma forma como acontece com uma activity, utiliza-se um intent para
ativar um service
• Se a declaracão do Service no Manifest contiver um Intent filter, isso significa que
qualquer componente (de outra app) pode ativa-lo com um implicit intent. Senão,
somente pode ser invocado pelo seu nome da classe, através de um intent
explicito. Isso é o default do atributo android:exported =[“true”
|”false”]
 IMPORTANTE: um service executa normalmente na thread principal do processo que
o abriga.
• Se é necessário executa-lo em um processo separado, deve-se explicitar isto em
isolatedProcess e dar o nome em process na declaracão no manifesto
6
• Dependendo da utilização do service, deve-se criar uma thread separada para
Criação de um service
 Para desenvolver um service deve-se estender a classe android.app.Service
• É preciso implementar métodos para atender o ciclo-de-vida e fornecer
mecanismos para que seja possível se conectar ao service
• Obs: em situacões de escassez de memória, o Android também pode destruir um
service. Para que estado do service possa ser recriado posteriormente, os
métodos do ciclo de vida precisam ser implementados.
 Os mais importantes métodos são:
• onStartCommand(): método chamado quando um outro componente solicita que
o service seja iniciado utilizado startService()
• onBind(): método chamado quando um outro componente solicita se conectar ao
service através do método bindService()
• É necessário fornecer uma interface, Ibinder, para os clientes se comunicarem com o
service
• onCreate(): método para procedimentos de configuração inicial do service,
chamado quando o service é criado (antes de chamar onStartCommand() ou
onBind()
• onDestroy(): método chamado quando o service não está mais em uso e deve ser
destruído – aqui devemos liberar recursos alocados (p. ex. threads)
7
public class HelloService extends Service {
Extensão da android.app.Service
private static final String TAG = HelloService.class.getName();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Service iniciou");
return super.onStartCommand(intent, flags, startId);
}
Exemplo de service
@Override
public void onCreate() {
Log.d(TAG, "Service parou");
super.onCreate();
}
8
@Override
public void onDestroy() {
Log.d(TAG, "Service destruído");
super.onDestroy();
}
Método onStartCommand() é chamado
quando algum componente executa o
método startService()
Método onBind() deve retornar
interface para chamadas remotas ao
service – neste exemplo, não é possível
se conectar a este service
@Override
public IBinder onBind(Intent arg0) {
// Retorna nulo quer dizer que clientes não podem se conectar ao service
return null;
}
}
Declaração de um service
 Como os outros componentes Android – activities, content providers e broadcast
receivers – um service deve ser declarado no arquivo de manifesto da aplicação para
que este seja usado pela aplicação
-O único atributo obrigatório é o nome da
classe que estende android.app.Service
<application>
...
<service
android:name="HelloService"
android:process=":the_process"
android:exported="true”
android:permission=“abc”>
</service>
...
</application>
9
-O atributo android:process determina o
processo que executará este service,
podendo ser o mesmo da aplicação, privado
à aplicação (definido no atributo process
de application), ou em um processo
independente, sendo acessível e
compartilhado para outras aplicações
(quando começa com ‘:’)
-O atributo android:exported determina se
este service é visível para outras aplicações
através de intent filters
- Atributo android:permission define a
permissão necesearia para ativar o service
IntentService
 IntentService é uma subclasse de android.app.Service que facilita o desenvolvimento
de services e que utiliza uma única thread para tratar todas as requisições para iniciar
o service, uma por vez
• Esta é a melhor opção se o service não precisa tratar requisições
concorrentes/simultâneas
• Basta implementar onHandleIntent() que recebe o intent de cada solicitação de
ativação do service
 A maioria dos services desenvolvidos não tem o requisito de tratar requisições
concorrentes
• Nestes casos, é muito mais fácil utilizar o IntentService como subclasse para
implementação do service
10
Iniciando um service
 Deve-se sempre iniciar um service utilizando intents com o método startService()
 O Android chamará o método startCommand() passando como parâmetro o intent
utilizado
Intent intent = new Intent(this, HelloService.class);
startService(intent);
• Múltiplas requisições para iniciar o service vão chamar múltiplas vezes o método
onStartCommand()
• Quando um service não permite a conexão, a única forma de passar dados para o
service é através do intent utilizado
11
Parando um service
 Para parar um service, o próprio deve chamar o método stopSelf() ou algum
componente deve chamar o método stopService()
Intent intent = new Intent(this, HelloService.class);
stopService(intent);
• Quando estes métodos – stopSelf() e stopService() – são chamados, o Android
imediatamente destrói o service
• Contudo, se o service deve receber múltiplas requisições concorrentes para executar
tarefas independentes , deve-se utilizar o identificador de cada requisição para
controlar quando o service será destruído
• Atenção: É importante sempre parar o service quando seu trabalho foi finalizado
para liberar recursos e não consumir bateria
12
Habilidade p/ criar threads
public class MyService extends Service implements Runnable{
Exemplo de service com
thread
private static final String TAG = HelloService.class.getName();
private boolean ativo;
13
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Service iniciou");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
Log.d(TAG, "Service foi criado");
super.onCreate();
ativo = true;
new Thead(this).start();
Criando uma nova thread
}
@Override
public void onDestroy() {
Log.d(TAG, "Service destruído");
super.onDestroy();
ativo = false;
}
public void run() {
while (ativo && count < MAX) {
fazAlgumaCoisa();
Log.d(TAG, ”processando...");
count++;
}
Log.d(TAG, ”terminei");
stopSelf();
}
Veja: java.lang.Runnable#run()
A therad executa um loop chamando
fazAlgumaCoisa();
Executando em foreground
 Um service pode executar em foreground quando é considerado importante para o
usuário, e não deva ser termiando quando a memória estiver baixa
 Para isto, é necessário chamar no próprio service o método startForeground(), que
provê para o usuário uma notificação na barra de status
• Esta notificação sumirá somente quando o service for parado ou tirado do
foreground
Notification notification = new Notification(R.drawable.icon, "Notif.",
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, ”MonitorService", "Notif.", pendingIntent);
startForeground(0, notification);
 Para tirar o service do foreground deve-se executar o método stopForeground()
14
Handler e Messenger
 O service pode se comunicar de volta com a activity através de um objeto Messenger
• Este objeto é enviado para o service através do intent
• Caso este Messenger esteja conectado com um Handler na activity, o service
pode enviar objetos Message para a mesma
public class MainActivity extends Activity {
private Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
... //tratamento ao objeto Message enviado
};
};
}
15
public void onClick(View view) {
Intent intent = new Intent(this, DownloadService.class);
Messenger messenger = new Messenger(handler);
intent.putExtra("MESSENGER", messenger);
startService(intent);
Um novo objeto Messenger é passado
}
como extra do intent
Handler e Messenger
Para receber e processar a Messsage IntentService deve implementar o
método onHandleIntent()
public class DownloadService extends IntentService {
...
@Override protected void onHandleIntent(Intent intent) {
...
//Execução do service
...
Bundle extras = intent.getExtras();
if (extras != null) {
Messenger messenger = (Messenger) extras.get("MESSENGER");
Message msg = Message.obtain();
Método estático Message.obtain()
msg.arg1 = 0;
retorna um novo objeto Message
msg.arg2 = 1;
msg.obj = new Object();
msg.setData(extras);
O objeto Message contém atributos e
try {
métodos para definir dados resultantes
messenger.send(msg);
do service
}
catch (android.os.RemoteException e1) { ...
}
}
}
16
}
Executando um service após boot
 Existem várias maneiras de agendar um service para execução
• Pode ser interessante agendar a execução de um service após a inicialização do
Android (o boot)
• Para isto, basta criar um Broadcast Receiver que receba a notificação de que a
inicialização completou, e que irá então iniciar o service
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<service android:name="HelloService"
android:exported="true"
android:process=":the_process">
</service>
<receiver android:name="MyScheduleReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
17
Executando um service após boot
 O BroadcastReceiver é notificado de que o Android finalizou seu boot e solicita o início
da execução do service
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, HelloService.class);
context.startService(service);
}
}
18
Exemplo de Activity que Interage com Service
usando Message
 Quando o serviço é executado, ele incrementa o número na frequência 10Hz.
 Quando a Activity faz um bind com o Service, irá exibir o valor atual. É possive
também enviar mensagens para o Service para alterar o inclremento.
 Os dados (integer e string) são transferidos usando Message e Handlers.
Estudar o código em https://bitbucket.org/alexfu/androidserviceexample/src
19
Handler na Activity
final Messenger mMessenger = new Messenger(new IncomingHandler());
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyService.MSG_SET_INT_VALUE:
textIntValue.setText("Int Message: " + msg.arg1);
break;
case MyService.MSG_SET_STRING_VALUE:
String str1 = msg.getData().getString("str1");
textStrValue.setText("Str Message: " + str1);
break;
default:
super.handleMessage(msg);
}
}
}
20
Obs: o Service é a classe Myservice
 O service estende a classe Handler, que
implementa o médodo handleMessage,
 Message é recebida no Intent do
onBind()
Download

Services - PUC-Rio