Curso de Android
Fevereiro de 2011
Cristiano Expedito Ribeiro
Fabrício Firmino de Faria
Agenda das próximas aulas [excluir]
Intent filter
BroadcastReceiver, Threads, Services e Notification
AlarmManager e Handler
Banco de Dados e ContentProvider
Mapas e GPS
Sockets e Web Services
Projeto
2
Agenda da Aula 2
Intent filter
Aplicações em segundo plano
BroadcastReceiver
Threads e Services
Notification
AlarmManager
Handler
Persistência
Arquivos e preferências
Banco de Dados SQLite
ContentProvider
Mapas e GPS
3
Intent Filter
Criação de filtros que determinam quais Intents devem
ser executadas para cada mensagem
<activity android:name=".HelloActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Action = MAIN
Diz que activity é um ponto de partida, semelhante ao
public static void main() da Java
Category = LAUNCHER
Indica que o ícone da activity deverá aparecer na tela
pode ser aberta pelo usuário
4
IntentFilter - Exercício 17
Volte ao projeto LayoutSamples
Abra o AndroidManifest.xml
• Remova o elemento <action> e salve
• Tente rodar a aplicação pelo eclipse
• Tente rodar a aplicação pelo menu do emulador
• Desfaça a remoção (Ctrl+Z)
• Remove o elemento <category> e salve
• Tente rodar a aplicação
• Desfaça a remoção (Ctrl+Z)
• Tente rodar a aplicação. Apenas com os dois elementos
que a aplicação rodará normalmente.
5
Ações de Intent úteis
Lembra das ações “nativas” do Android?
Action
URI - chamar Uri.parse(uri)
Descrição
ACTION_VIEW
http://www.gmail.com
Abre browser na página
ACTION_VIEW
ACTION_EDIT
content://com.android.contacts/contacts/1
Mostra ou edita o contato
solicitado
ACTION_VIEW
geo:0,0?q=Presidente+Vargas,Rio+de+Ja
neiro
Busca no Google Maps
ACTION_CALL
ACTION_DIAL
tel:12345678
Liga ou apenas disca para o
número
ACTION_INSERT
content://com.android.contacts/contacts
Abre activity padrão para
inserir contatos
ACTION_PICK
ContactsContract.Contacts.CONTENT_URI
Abre lista de contatos do
celular
ACTION_SET_WALLPAPER
-
Abre lista para escolha de
papéis de parede
6
Ações de Intent – Exercício 18
Crie um novo projeto chamado IntentFilterTest
Experimente chamar activities usando a tabela anterior
Exemplo:
Uri uri = Uri.parse("content://com.android.contacts/contacts");
Intent intent = new Intent(Intent.ACTION_INSERT, uri);
startActivity(intent);
intent = new Intent(Intent.ACTION_SET_WALLPAPER);
startActivity(intent);
Experimente também:
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, "Maria");
startActivity(intent);
Sim, você pode passar parâmetros via Intent,
dependendo de qual ação está sendo executada!
7
Ações de Intent – Exercício 18
ACTION_CALL não irá funcionar pois é necessário
pedir permissão através do AndroidManifest.xml
• Adicione esta permissão e tente novamente
<uses-permission android:name="android.permission.CALL_PHONE”/>
Outras permissões úteis
android.permission.READ_CONTACTS
android.permission.VIBRATE
android.permission.INTERNET
android.permission.BATTERY_STATS
android.permission.BLUETOOTH
android.permission.CAMERA
android.permission.REBOOT
android.permission.SEND_SMS
Além disso, para usar o Google Maps é necessário
rodar o emulador com Google Maps.
8
Categorias e parâmetros para Intent
Algumas vezes Ação e URI não são suficientes
É possível adicionar tantas categorias e parâmetros
extras quanto forem necessários, além de outros dados:
Método da Intent
Descrição
addCategory(String)
Adiciona mais uma categoria à Intent
putExtra(String, ...)
Adiciona um parâmetro à Intent
setData(Uri)
Define o Uri. Equivalente ao parâmetro URI do construtor
setType(String)
Define o tipo MIME: text/plain, image/jpeg, etc
setFlags(int)
addFlags(int)
Define os flags da Intent. Um flag útil é o FLAG_ACTIVITY_NEW_TASK,
que faz a activity iniciar numa nova tarefa
setAction(String)
Define a ação desta intent. Note que, diferentemente de categorias e
extras, apenas uma ação pode ser definida por intent.
Os métodos setData() e setType() são antagônicos, ou
seja, chamar um deles implica em limpar o outro.
9
Substituindo ações nativas
Tecla Home
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Tecla discar (call)
<action android:name="android.intent.action.CALL_BUTTON" />
<category android:name="android.intent.category.DEFAULT" />
Intent.ACTION_SEARCH
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
Intent.ACTION_WEB_SEARCH
<action android:name="android.intent.action.WEB_SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
10
Ações nativas - Exercícios 19 e 20
Exercício 19
Crie um projeto IntentFilterNativeSubst
Modifique o manifest e rode a aplicação para cada
exemplo do slide anterior
Exercício 20
Após o último exemplo (web search) edite o projeto
IntentFilterTest para chamar web search:
intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, "Maria");
startActivity(intent);
Execute IntentFilterTest
Veja que o emulador irá perguntar
qual aplicação executar
11
Ações e categorias próprias e filtragem
Para criar as próprias ações e categorias, faça:
Configurá-las no manifest usando <intent-filter>
Criar a Intent e executá-la
• Isto pode ser feito na mesma aplicação ou não
Filtragem
Ao executar uma Intent, uma activity só rodará caso seu
intent-filter satisfaça a ação e todas as categorais
definidas na Intent.
Exemplos:
• Considere intent-filter: ACAO1, CATEG1, CATEG2
1. Intent: ACAO1, CATEG1 Executa
2. Intent: ACAO1, CATEG1, CATEG2 Executa
3. Intent: ACAO1, CATEG3 Não executa!
12
Ações próprias e filtragem – Exercício 21
No manifest de IntentFilterNativeSubst
<action android:name="com.example.intentfilter.nativesubst.ACTION" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.intentfilter.nativesubst.CATEG1" />
<category android:name="com.example.intentfilter.nativesubst.CATEG2" />
Dê play na aplicação IntentFilterNativeSubst para
instalá-la, note que nada rodará na tela, pois não há
MAIN e LAUNCHER
Em IntentFilterTest
intent = new Intent("com.example.intentfilter.nativesubst.ACTION");
intent.addCategory("com.example.intentfilter.nativesubst.CATEG1");
intent.addCategory("com.example.intentfilter.nativesubst.CATEG2");
startActivity(intent);
Rode IntentFilterTest e IntentFilterNativeSubst rodará
Remova CATEG2 do manifest e repita a operação...
13
Intent filter e permissões
Caso um <intent-filter> não seja definido para uma
activity apenas a própria aplicação poderá iniciá-la
Mas é possível exportá-la
<activity ... android:exported=“true” > ...
Mesmo assim, é necessário que a aplicação que queira
iniciá-la use Intent.setComponentName() ou
setClassName() e conheça o nome da classe completo
• Exemplo: “com.example.application.ActivityName”
O uso de <intent-filter> no manifest exporta a activity
automaticamente
Usar setClassName() ou setComponentName() para
iniciar uma activity não exportada lançará uma
SecurityException
14
Intent filter e permissões
É possível criar sua própria permissão
<manifest ... >
<permission android:label="@string/..."
android:name="application_package.PERMISSION_NAME" />
<application ... >
<activity ...
android:exported="true"
android:permission="application_package.PERMISSION_NAME" >
</activity>
</application>
</manifest>
Se uma aplicação diferente quiser acessar esta activity
será necessário usar um elemento <uses-permission>
para a permissão definida pela aplicação
<uses-permission android:name="application_package.PERMISSION_NAME"/>
15
BroadcastReceiver
Chamado pelo Android para reagir a mensagens
broadcast
Usado para executar tarefas rápidas em segundo plano
Não interromper o usuário por meio de activities
Use notificações! (Serão explicadas em breve)
O que são mensagens broadcasts?
São mensagens enviadas pelo Android quando ocorre
algum evento do sistema ou de uma aplicação
Interceptada pelos BroadcastReceiver’s apropriados
• Definido pelos <intent-filter>
16
Tipos de broadcast
Ordered ou Síncrono
Os receivers são executados em sequência e a falha de
um interrompe o processamento dos demais
Não está no escopo deste curso
Normal ou Assíncrono
Todos os receivers executam simultaneamente em
paralelo e de forma independente
Método para disparar: Context.sendBroadcast(Intent)
BroadcastReceiver1
Evento
Mensagem
...
BroadcastReceiverN
17
Configurando um receiver
É necessário adicionar o elemento <receiver> dentro
de <aplication> no AndroidManifest.xml
<receiver android:name="NomeReceiver">
<intent-filter>
<action android:name="com.example.broadcastreceiver.ACTION"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
Implementar uma classe filha de BroadcastReceiver
com o callback onReceive(Context, Intent)
public class NomeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// ...
}
}
Atenção: onReceive deve retornar em menos de 10 s.
18
Disparando mensagens broadcast
Criar uma Intent com a mensagem
Enviar via Context.sendBroadcast(Intent)
Context é uma classe base de activity, logo o método
pode ser chamado diretamente
Intent intent =
new Intent("com.example.broadcastreceiver.ACTION");
sendBroadcast(intent);
19
Broadcast Receiver – Exercício 22
Crie um projeto chamado ReceiverTest
Crie um broadcast conforme slide anterior
Dentro do método onReceive escreva algo no log
Edite o projeto IntentFilterTest para enviar o broadcast
20
Mensagens broadcast do sistema
Mensagens broadcast enviadas apenas pelo sistema
Não podem ser enviadas pelo método sendBroadcast()
android.intent.action
Condição de envio (pelo sistema)
WALLPAPER_CHANGED
Papel de parece alterado
BOOT_COMPLETED*
Sistema concluiu o bootstrap
ACTION_SHUTDOWN
Sistema está desligando (antes de desligar o aparelho)
BATTERY_CHANGED**
Estado de carga da bateria mudou
BATTERY_LOW
Estado de carga da bateria baixo
BATTERY_OKAY
Estado de carga da bateria voltou a níveis normais
ACTION_POWER_CONNECTED
Carregador conectado
ACTION_POWER_DISCONNECTED Carregador desconectado
* Requer permissão android.permission.RECEIVE_BOOT_COMPLETED
** Não podem ser usados com <intent-filter> serão mostrados em breve 21
Mensagens broadcast do sistema
android.intent.action.*
Condição de envio (pelo sistema)
TIME_SET
Data e/ou hora do sistema foram alterados
TIMEZONE_CHANGED
Fuso horário foi modificado
TIME_TICK**
Hora do sistema mudou normalmente (enviado a cada minuto)
SCREEN_ON
Tela do dispositivo acendeu (estava inativa, mas usuário ativou)
SCREEN_OFF
Tela do dispositivo apagou (normal para economizar bateria)
PACKAGE_ADDED
Uma nova aplicação foi instalada no dispositivo
PACKAGE_REMOVED
Uma aplicação foi removida do dispositivo
PACKAGE_REPLACED
Uma aplicação foi substituída. Normalmente por upgrade de versão.
PACKAGE_RESTARTED
Uma aplicação foi reiniciada, tendo seus processados terminados.
PACKAGE_DATA_CLEARED
Dados de uma aplicação foram apagados. Enviado após
PACKAGE_RESTARTED
** Não podem ser usados com <intent-filter> serão mostrados em breve
22
Broadcast de sistema – Exercício 23
Adicione mais um receiver no projeto ReceiverTest
<receiver android:name="WallpaperReceiver">
<intent-filter>
<action android:name="android.intent.action.WALLPAPER_CHANGED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Adicione o seguinte no callback onReceive()
Log.i(this.getClass().getCanonicalName(), intent.getAction());
Instale a aplicaçao
Tenta mudar o papel de parede no emulador
Menu > Wallpaper > Wallpapers
Analise o LogCat.
23
Configuração de receivers via código
Indicado quando um receiver deve executar apenas
quando uma acitivity está executando
É possível registrar dinamicamente via código
registerReceiver(BroadcastReceiver, Intent)
unregisterReceiver(BroadcastReceiver)
Recomendável:
Registrar em Activity.onCreate() ou onResume()
Desregistrar no Activity.onDestroy() ou onPause()
Note que são necessários para actions TIME_TICK e
BATTERY_CHANGED da tabela
24
Threads
São linhas ou fluxos de execução de código que rodam
em “paralelo” numa mesma aplicação
Usadas para executar tarefas independentes entre si.
Sempre há uma thread inicial ou principal
Interface gráfica sempre executa nesta thread
Exemplo:
Uma aplicação pode usar 3 threads, assim distribuídas:
• Interface gráfica
• Reprodução de música
• Download de arquivo da Internet
25
Exemplo de aplicação multithread
26
Classe Thread e Interface Runnable
Métodos da classe Thread
Thread(Runnable)
Construtor de thread que recebe um objeto Runnable contendo o
código a ser executado
static void sleep(long milis)*
Faz thread que chamar este dormir milis milissegundos.
void start()
Inicia thread
void join(long milis, int nanos)*
Aguarda término da thread por tantos milissegundo. Ambos os
argumentos são opcionais.
bool isAlive()
Retorna true se thread ainda está em execução
void run()
Deve ser implementado com o código da thread. A interface
Runnable também possui este método. Não chamar diretamente.
* Cuidado ao chamar métodos bloqueantes em threads que recebem callbacks, pois
estes devem retornar rapidamente.
Objetos modificados por mais de uma thread:
synchronized (objeto) {
// modifica objeto
}
27
Usando threads
Em um método qualquer (criação e execução)
Runnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
Em outro método (aguardar término)
try {
thread.join(1000);
} catch (InterruptedException e) {}
Classe que contém o código
class MyRunnable implements Runnable {
public void run() {
// codigo da thread que pode ser um loop ou não
}
}
28
Threads e interfaces gráficas
Callbacks sempre rodam na thread principal da
aplicação
Todos os objetos de View e subclasses são atrelados à
thread que o criou também conhecida como UI Thread
Chamar um método de View que a modifique resultará
no lançamento de uma exceção
ViewRoot.CalledFromWrongThreadException: Apenas
a thread que criou a view pode modificá-la
Para isso deve-se usar um Handler que será mostrado
posteriormente
29
Serviços
Usado para executar tarefas em segundo plano
Estas tarefas não possuem um tempo definido de
execução (podendo ser demoradas)
Não deve iniciar activities: use notificações (em breve)
Configuração no AndroidManifest.xml
<application ... >
<service android:name="ServiceName">
<intent-filter>
<action android:name="com.example.serviceapp.ACTION" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
</application>
Caso se queira iniciar o serviço de outra aplicação sem
um <intent-filter> deve-se usar android:exported="true"
30
Formas de iniciar um serviço
Pode ser iniciado de dentro de activity, broadcast receiver ou
outro serviço
Duas formas:
Desacoplado: serviço é iniciado e fica independente do
contexto (activity, receiver ou serviço) chamador
Com conexão: serviço é iniciado, retorna uma interface de
acesso e fica associado ao contexto chamador. Usado quando
precisa-se “conversar” com o serviço.
Métodos para inicialização (classe Context)
Método
Descrição
startService(Intent)
Inicia um serviço desacoplado
bindService(Intent, ServiceConnection, flags)
Inicia um serviço conectado. O segundo
parâmetro é um objeto com métodos
callbacks para notificar conexão e desconexão
31
Ciclo de vida de um serviço
32
Classe Service
Classe base para qualquer serviço
public class MyService extends Service {
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
// Inicializar varíaves e criar uma thread (opcional)
}
@Override
public void onDestroy() {
super.onDestroy();
// Terminar a thread aqui, caso esteja rodando
}
}
33
Compatibilidade com versões anteriores
// Método onStart antigo que é chamado nas
// plataformas anteriores a 2.0
@Override
public void onStart(Intent intent, int startId) {
processaStart(intent);
}
// Método chamado a partir da plataforma 2.0
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
processaStart(intent);
// Retorne isto para que o serviço rode até ser
// explicitamente terminado
return START_STICKY;
}
// Método para onde onStart e onStartCommand converge
protected void processaStart(Intent intent) {
// Processa independente de versão de plataforma
}
34
Inicialização de serviços desacoplados
Método startService(Intent)
Inicia o serviço determinado pela intent.
O serviço roda independente do chamador e por tempo
indeterminado
Se o contexto chamador terminar o serviço continua
rodando normalmente
Pode ser chamado inúmeras vezes
• Apenas na primeira o callback onCreate() é chamado
• O método onStart/onStartCommand sempre é chamado
Método stopService(Intent)
Termina o serviço chamando onDestroy()
Não importa quantas vezes startService() foi chamado,
uma única chamada a este encerra o serviço
35
Como e quando terminar serviços
Método stopSelf()
Chamar quando serviço terminar o processamento
Boa prática para evitar consumo de bateria
Caso queira que o serviço volte a executar de forma
automática no futuro usar AlarmManager (em breve)
36
Serviços - Exercício 24
Crie um projeto chamado ServiceTest sem activitty
Adicione uma classe ServiceTest que extenda Service
Implemente onCreate() e onDestroy() escrevendo no
LogCat uma mensagem dizendo em qual deles está
No manifest, coloque um <intent-filter> dentro de
<service> com o seguinte par action-category:
"com.example.servicetest.SERVICE“
"android.intent.category.DEFAULT"
No projeto ReceiverTest, adicione as seguintes linhas
no final do método WallpaperReceiver.onReceive()
intent = new Intent("com.example.servicetest.SERVICE");
context.startService(intent);
Instale, mude o papel de parede e olhe o LogCat
37
Serviços e threads – Exercício 25
Ainda na classe ServiceTest
Implemente a interface Runnable
Crie uma thread e a inicie no onCreate()
• Ela deve incrementar um contador a cada 250 ms até 40
• Ao terminar chamar stopSelf() dentro de run()
Instale o serviço
No emulador, mude o papel de parede
Olhe o LogCat e veja que, deta vez, o método
onDestroy() será chamado (em aproximadamente 10s)
38
Serviços e permissões – Exercício 26
No manifest de ServiceTest adicione <permission>
<permission android:label="@string/service_perm_label"
android:name="com.example.servicetest.permission.SERVICE" />
Note que android:label deve ser um recurso string
No elemento <service>
Remova <intent-filter>
Adicione android:exported=“true” android:permission
<service ...
android:exported="true"
android:permission="com.example.servicetest.permission.SERVICE" >
No manifest do projeto ReceiverTest adicione
<uses-permission
android:name="com.example.servicetest.permission.SERVICE”/>
(continua)
39
Serviços e permissões – Exercício 26
Em WallpaperReceiver.java altera a linha que cria
intent por
intent = new Intent();
intent.setClassName("com.example.servicetest",
"com.example.servicetest.ServiceTest");
Instale ambas as aplicações
No emulador mude o papel de parede
Veja pelo LogCat que o serviço foi normalmente
criado e finalizado
Remova o elemento <uses-permission> do manifest
Veja agora que ao mudar o papel de parede é lançado
um SecurityException
40
Uso de serviços com conexão
Método bindService(Intent, ServiceConnection, flags)
Associa o contexto ao serviço, ou seja, serviço é útil até
que o contexto termine ou chame unbindService()
Se o serviço não estiver rodando e flags for igual a
BIND_AUTO_CREATE o serviço será iniciado
Não pode ser chamado de um BroadcastReceiver
Chama onCreate() e onBind() mas não chama
onStartCommand() nem onStart()
Método unbindService(ServiceConnection)
Desconecta o contexto atual do serviço
Se não houver outras aplicações conectadas ao serviço
nem startService() tiver sido usado então o método
onDestroy() será chamado e o serviço terminado
41
Interface ServiceConnection
É uma interface com métodos callback para notificar a
aplicação sobre conexão e desconexão do serviço
Método callback
Descrição
onServiceConnected(ComponentName, IBinder) Evento: foi estabelecida uma nova conexão ao
serviço definido pelos argumentos do método.
Ação: fazer type cast para a classe Binder do
serviço e obter sua interface.
onServiceDisconnected(ComponentName name) Evento: a conexão com o serviço foi perdido
devido a uma chamada a unbindService() ou o
término do serviço. No segundo caso, a
associação ao serviço continua ativa e caso o
serviço volte a executar o método
onServiceConnected será chamado novamente.
Ação: remover todas as referências para a
interface obtida anteriormente.
42
Classe Binder e interface IBinder
IBinder é usada apenas como retorno de onBind() e
argumento de onServiceConnected()
Binder é uma classe que implementa os métodos de
IBinder para simplificar a criação de binders por parte
dos serviços
Binder deve ser usada como classe base para o binder
do serviço quando este não é remoto (em breve)
43
Serviços com conexão – Exercício 27
No projeto ServiceTest
Crie uma interface chamada Contador com os métodos
int get(), void set(int) e void reset()
Crie uma nova classe nomeada ServiceBindTest
• Faça-a estender ServiceTest e implementar Contador
• Crie um classe interna chamada ContadorBinder
• Faça-a estender Binder
• Crie um método Contador getInterface() que retorna a
intância do serviço
• Crie um campo para guardar a instância de
ContadorBinder e crie o método onBind() que a retorne
• Implemente os métodos get, set e reset que alteram a
variável de contagem da classe ServiceTest
44
Serviços com conexão – Exercício 27
Adicione um <service> para o novo serviço no
manifest
Legal o serviço está pronto, mas como conectar-se à
interface?
Uma activity!
Crie uma activity chamada ServiceBinderActivity
Pegue o arquivo de XML de layout do próximo slide
Adicione um <activity> no manifest
Crie um campo para guardar a interface do serviço
• Contador contador;
Pegue o código de onCreate() dos slide seguintes
Herde de ServiceConnection e adicione seus métodos
45
Exercício 27 – XML de layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent" >
<Button android:id="@+id/btnBind“ android:text="Conectar ao serviço"
android:layout_width="wrap_content“ android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<Button android:id="@+id/btnUnbind“ android:text="Desconectar do serviço"
android:layout_width="wrap_content“ android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<Button android:id="@+id/btnZerarContador“ android:text="Zerar contador"
android:layout_width="wrap_content“ android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<Button android:id="@+id/btnLerContador“ android:text="Ler contador“
android:layout_width="wrap_content“ android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView android:id="@+id/valorContador“ android:text="0"
android:layout_width="wrap_content“ android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
</LinearLayout>
46
Exercício 27 - Método onCreate()
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView text = (TextView) findViewById(R.id.valorContador);
Button btnBind = (Button) findViewById(R.id.btnBind);
btnBind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// bindService
}
});
Button btnUnbind = (Button) findViewById(R.id.btnUnbind);
btnUnbind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// unbindService
}
});
47
Exercício 27 - Método onCreate()
Button btnGet = (Button) findViewById(R.id.btnLerContador);
btnGet.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// ler contador aqui
int count = 0;
text.setText("" + count);
}
});
}
Button btnReset = (Button) findViewById(R.id.btnZerarContador);
btnReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// zerar contador aqui
}
});
// Fim onCreate()
48
Exercício 27 – Conclusão
Adicione códigos necessários nos callbacks onClick()
bindService(intent,ServiceBinderActivity.this,BIND_AUTO_CREATE);
unbindService(ServiceBinderActivity.this);
int count = contador.get();
contador.reset();
Implemente os métodos de ServiceConnection
onServiceConnected(ComponentName, IBinder service)
ContadorBinder binder = (ContadorBinder) service;
contador = binder.getInterface();
onServiceDisconnected(ComponentName)
contador = null;
Instale a aplicação e execute sua activity
49
Serviços remotos e AIDL
Serviços remotos são aqueles executados em uma
aplicação diferente da que chama bindService()
Necessário dizer ao Android qual é a interface do
serviço
Android Interface Definition Language (AIDL)
Criar uma interface com extensão *.aidl
Ao criar a interface AIDL no projeto, o eclipse cria
automaticamente uma classe de mesmo nome
• Esta classe não pode ser alterada
• O serviço deve herdar da classe interna Stub e
implementar os métodos definidos pela interface AIDL
A aplicação que se conectar ao serviço deve conhecer
apenas a interface AIDL
50
Serviços remotos - Exercício 28
No projeto ServiceTest, crie ContadorRemoto.aidl
O package pode ser com.example.servicetest.aidl
Os métodos devem ser os mesmo da interface Contador
Não é possível usar extends com AIDL
Na classe ServiceBindTest
Crie um classe interna que herde ContadorRemoto.Stub
• Chame-a de ContadorRemotoBinder
• Crie construtor que guarde uma instância de Contador
• Implemente os métodos de ContadorRemoto usando a
instância de Contador obtida
Crie campo para uma instância de ContadorRemotoBinder
No método onBind(), retorne esta instância
51
Serviços remotos – Exercício 28
Crie um projeto chamado ActivityForRemoteService
Copie o layout de ServiceTest para main.xml do novo
projeto
Substitua o conteúdo da nova activity pelo existente na
ServiceBinderActivity
Corrija os erros de nome de activity (ficam destacados)
Faça-a implementar ServiceConnection
Substitua o tipo do contador para ContadorRemoto
Copie o pacote com.example.servicetest.aidl de
ServiceTest para a pasta src do novo projeto
Adicione try...catch nas chamadas do ContadorRemoto
52
Serviços remotos – Exercício 28
Substitua o código de onServiceConnected
void onServiceConnected(ComponentName name, IBinder service) {
contador = ContadorRemoto.Stub.asInterface(service);
}
No manifest do projeto ServiceTest remova <intentfilter> da activity
Instale ServiceTest novamente
Execute ActivityForRemoteService
Pelo LogCat pode-se ver que o resultado é igual, mas a
activity roda em uma aplicação e o serviço em outra.
Note que este método também pode ser usado com
activity e serviço na mesma aplicação, permitindo
criação de interfaces de serviço genéricas
53
Notificações
Mensagem que aparece na barra de status
Permite avisar o usuário sobre
algo sem pertubá-lo
Pode disparar uma intent
ao ser selecionada
Motivo para usar
Não pertubar o usuário com a
apresentação de uma Activity
O usuário só irá abrir a activity
quando e se quiser
54
Classe NotificationManager
Classe responsável por gerenciar notificações
Cada notificação é identificada por um par (tag, id)
Id é um identificador inteiro
Tag é uma string que pode ser null
Usar getSystemService(NOTIFICATION_SERVICE)
Método
Descrição
notify(int id, Notification)
Adiciona uma notificação à barra de status associando-a ao id
notify(tag, id, Notification)
Semelhante ao anterior, porém associa a notificação a um par
(tag, id)
cancel(id)
Cancela uma notificação, ou seja, remove da barra da status
cancel(tag, id)
Semalhante ao anterior, porém a notifacação precisa ter sido
criado com notify(tag, id, Notification)
cancelAll()
Cancela todas as notificações
55
Classe PendingIntent
Permite definir que uma intent seja executada por
alguma aplicação no futuro
Métodos
Descrição
static PendingIntent
Retorna uma PendingIntent que iniciará uma
getActivity(Context, int requestCode, Intent, flags) activity quando for disparada.
Semelhante a startActivity(Intent)
static PendingIntent
getBroadcast(Context, requestCode, Intent, flags)
Retorna uma PendingIntent que ativará um
broadcast quando for disparada.
Semelhante a sendBroadcast(Intent)
static PendingIntent
getService(Context, int requestCode, Intent, flags)
Retorna uma PendingIntent que iniciará um
serviço quando for disparada.
Semelhante a startService(Intent)
void send()
Dispara esta PendingIntent.
FLAG_CANCEL_CURRENT
FLAG_UPDATE_CURRENT
FLAG_NO_CREATE
FLAG_ONE_SHOT
56
Classe Notification
Representa a notificação propriamente dita
Construtor Notification(int icon,
textoBarraStatus,
long when)
Construtor que define o ícone e o texto que aparece na
barra de status durante alguns segundos. Além do instante
em que a notificação deve aparecer baseado em
System.currentTimeMillis().
Método
setLatestEventInfo
Define o conteúdo da mensagem: título, mensagem e a
(Context, titulo,
PendingIntent que será disparada caso o usuário selecione
mensagem, PendingIntent) a notificação
Campo
public int flags
Flags: FLAG_INSISTENT ou FLAG_AUTO_CANCEL
Campo
public int defaults
Define o que fazer quando a notificação aparece na barra
de status: DEFAULT_SOUND, DEFAULT_LIGHTS,
DEFAULT_VIBRATE, DEFAULT_ALL
Campo
public long [] vibrate
Define padrão de vibração: sequência de números inteiros
de definem tempo de vibração e parada
Notification.FLAG_INSISTENT
Vibração e/ou áudio contínuos
Notification.FLAG_AUTO_CANCEL
Cancela notificação quando usuário seleciona
57
Etapas para mostrar uma notificação
Criar um Intent para activity, service ou broadcast
Obter uma PendingIntent associada à intent
Criar uma instância de Notification
Configurar a notificação com setLatestEventInfo(),
flags e defaults
Obter a intância NotificationManager (nm)
Chamar nm.notify(...)
Quando o usuário selecionar a notificação a intent
definida será disparada (activity, service ou broadcast)
O alvo da intent pode cancelar a notificação se esta não
for mais necessária ou colocar FLAG_AUTO_CANCEL
no flags da notificação antes de chamar nm.notify()
58
Notificação – Exercício 29
Criar uma aplicação que cria uma notificação
A notificação deverá abrir uma segunda activity quando
selecionada
Expanda o exercício para enviar parâmetros para a
segunda activity usando Intent.putExtra() ou putExtras
Você pode usar flags e defaults (embora algumas
funcionalidades não possam ser vistas no emulador)
59
AlarmManager
Permite agendar intents paras serem executadas
Em um momento futuro, ou
Em intervalos regulares
Agendamentos são preservados enquanto dispositivo
estiver ligado (em uso ou stand-by) mas são
cancelados quando é desligado e ligado novamente ou
é reiniciado (reboot)
Para obter a instância classe use
AlarmManger am = (AlarmManager)getSystemService(ALARM_SERVICE)
60
Classe AlarmManager
set(int tipo, long instante, PendingIntent) Agenda um alarme para ser disparado no instante
especificado e a intent que será disparada.
setRepeating(int tipo, long instante, long
intervalo, PendingIntent)
Agenda um alarme para ser disparado no instante
especificado e o intervalo para disparos subsequentes.
cancel(PendingIntent)
Cancela um alarme previamente configurado
Tipo
Instante de tempo do alarme
Acorda o dispositivo?
ELAPSED_REALTIME
Relativo
Sim
ELAPSED_REALTIME_WAKEUP
Relativo
Não
RTC
Absoluto
Sim
RTC_WAKEUP
Absoluto
Não
Absoluto
Baseado em SystemClock.elapsedRealtime(), i.e, milissegundos desde o boot.
Relativo
Baseado em System.currentTimeMillis(), i.e, milissegundos desde 01/01/1970
Acorda
Caso o dispositivo esteja dormindo será acordado para tratar o alarme.
Não acorda
Caso o dispositivo esteja dormindo ele não será acordado e o alarme será disparado
apenas quando o dispositivo acordar normalmente.
61
AlarmManager – Exercício 30
Criar um alarme para iniciar ServiceTest e reativá-lo a
cada 30 segundos
Na activity WallpaperReceiver do projeto ReceiverTest
• Aproveite a intent que inicia o serviço
• Crie uma PendingIntent para serviço usando a intent
• Obtenha o AlarmManager via getSystemService()
• Chame setRepeating para agendar o alarme
Instale a aplicação ReceiverTest
No emulador, altere o papel de parede
Observe o LogCat por 1 min para ver as mensagens
• O serviço reiniciará e terminará infinitamente até que o
agendamento seja cancelado ou o emulador reiniciado
62
Handler
Threads têm filas de mensagens para comunicação
Um Handler se associa à fila de uma thread e permite
enfileirar mensagens nesta fila
Enfileira para execução imediata ou agendada
Estas mensagens serão executadas na thread associada
As mensagens podem ser enviadas de qualquer thread
Tipos de mensagens
java.lang.Runnable
• O método void run() será executado
android.os.Message
• Necessário estender Handler e implementar void
handleMessage(Message) para executar a mensagem
63
Hander com Message
Message guarda informações da mensagem
Campo
int what
O código da mensagem definido pelo usuário.
Campo
int arg1, arg2
Argumentos que podem ser definidos para não precisar definir
objetos complexos de dados.
Método
setData(Bundle)
Bundle getData()
Usado quando os parâmetros a serem passados não podem ser
representados como inteiros em arg1 e arg2.
Método
long getWhen()
Retorna o instante, em milisegundos, em que a mensagem será
entregue.
Forma de uso
Necessário estender Handler
Implementar handMessage(Message), e
Interpretar o atributo what da mensagem
64
Métodos de Handler
sendMessage(Message)
Envia mensagem para ser processada assim que possível.
sendMessageDelayed(Message,
long delay)
Envia mensagem para ser processada após o tempo indicado
ter decorrido.
sendMessageAtTime(Message,
long time)
Envia mensagem para ser processada apenas no instante de
tempo informado.
sendEmptyMessage(int what)
Cria uma mensagem apenas com o campo what preenchido e
adiciona na fila para ser processada assim que possível.
sendEmptyMessageDelayed(int what, Semelhante ao anterior mas processa mensagem apenas após
long delay)
o tempo indicado ter decorrido.
sendEmptyMessageAtTime(int what,
long time)
Semelhante ao anterior mas processa mensagem apenas no
instante informado.
post(Runnable)
Envia Runnable para ser executado assim que possível.
postDelayed(Runnable, long delay)
Envia Runnable para ser executado após o tempo indicado ter
decorrido.
postAtTime(Runnable, long time)
Envia Runnable para ser executado apenas no instante de
tempo informado.
65
Handler – Exercício 31
Na activity do projeto ActivityForRemoteService
Crie um campo para armazenar um handler para a
interface gráfica
Handler handler = new Handler();
Criar uma thread que atualiza a View que mostra o
contador a cada 1000 ms
• Crie uma classe interna chamada ContadorThread que
estenda Thread.
• No método run() faça um loop que poste um Runnable
Thread.sleep(1000)
handler.post(new Runnable() { ... } )
• O Runnable deve atualizar o TextView com o valor do
contador
Nos exemplos existe um brinde que não usa thread!
66
Persistência
Existem 3 formas de armazenar dados no dispositivo
Arquivos comuns (texto ou binário)
• Classes FileInputStream e FileOutputStream
• Armazenados em /data/data/<pacote>/files
Arquivos de preferências
• Classe SharedPreferences
Bancos de Dados usando SQLite
• Classes SQLiteDatabase, SQLiteOpenHelper
• Armazenados em /data/data/<pacote>/databases
67
Arquivos comuns
Métodos da classe Context
FileInputStream
openFileInput(String name)
Abre um arquivo privado associado a aplicação para leitura.
Argumento name não pode conter ‘/’.
FileOutputStream
openFileOutput(String name,
int mode)
Abre um arquivo privado associado a aplicação para escrita.
Argumento mode pode ser Context.MODE_PRIVATE ou
Context.MODE_APPEND
FileInputStream contém métodos para ler bytes
FileOutputStream contém métodos para escrever
bytes
InputStreamReader pode ser construído a partir de um
FileInputStream e contém métodos para ler caracteres
OutputStreamWriter pode ser construído a partir de
um FileOuputStream e contém métodos para escrever
caracteres
68
Arquivos comuns
Exemplo de escrita
try {
FileOutputStream fis = openFileOutput(filename, MODE_PRIVATE);
OutputStreamWriter isr = new OutputStreamWriter(fis);
isr.write("Nome: " + nome + "\n");
isr.write("email: " + email + "\n");
isr.close();
} catch (FileNotFoundException e) {
} catch (IOException e) { }
69
SharedPreferences
70