Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Coordenadores:
Ricardo Menotti
Daniel Lucrdio
Autor/Bolsista:
Matheus Fernando Finatti
Sumrio
Lista de Figuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
iv
Lista de Tabelas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Lista de Algoritmos
vii
Lista de Algoritmos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xi
xv
Introduo
Configurao do Ambiente
Linguagem do Android
3.1
Linguagem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2
11
Design
27
5.1
Activity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
5.2
28
5.3
Tipos de Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
5.4
Listas (ListView) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
5.5
Listas Compostas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
5.6
38
5.7
45
5.8
Fragmentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
5.9
Abas (Tabs) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
60
62
5.12 ActionBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
Comunicao
6.1 Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2 Telefone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.3 Short Message Service (SMS) . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
71
76
77
Armazenamento
7.1 Shared Preferences: . . .
7.2 Armazenamento interno .
7.3 Armazenamento Externo
7.4 Banco de dados . . . . .
79
79
81
85
86
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Cmera
91
8.1 Usando a API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
8.2 Gravando vdeos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
8.3 Usando um Intent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
udio
107
9.1 Gravando e tocando udio . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
10 Localizao e Mapas
111
10.1 Acessando a localizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
10.2 Google Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
11 Compartilhamento
119
12 Agenda e Contatos
125
12.1 Usando o Contacts Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
13 Acelermetro
135
14 Bluetooth
139
15 Internacionalizao
151
ii
Lista de Figuras
1.1
4.1
12
4.2
12
4.3
13
4.4
13
4.5
14
4.6
16
4.7
17
4.8
21
4.9
25
25
25
5.1
27
5.2
29
5.3
LinearLayout composto . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
5.4
Exemplo de RelativeLayout . . . . . . . . . . . . . . . . . . . . . . . . .
30
5.5
31
5.6
Exemplo de TableLayout . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
5.7
32
5.8
32
5.9
Lista simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
38
44
45
47
50
54
iii
iv
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
59
65
69
114
114
115
116
Lista de Tabelas
1.1
Tabela com as distribuies das verses do Android, todas as verses com menos de 0.1% de participao foram desconsideradas . . . . . . . . . . . . . . .
Lista de Algoritmos
4.1
4.2
17
4.3
Cdigo do boto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
4.4
18
4.5
19
4.6
19
4.7
19
4.8
19
4.9
20
22
22
5.1
28
5.2
33
5.3
33
5.4
33
5.5
34
5.6
36
5.7
37
5.8
38
5.9
Layout list_item_parent.xml . . . . . . . . . . . . . . . . . . . . . .
39
39
40
42
43
45
46
47
vii
48
49
49
51
52
52
53
54
55
55
56
56
57
57
58
59
60
61
62
63
63
64
64
65
66
66
67
67
68
6.1
71
6.2
Classe RequestTask . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
6.3
73
6.4
74
6.5
Classe JSONParser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
6.6
Criando JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
6.7
76
6.8
76
6.9
77
77
viii
78
7.1
80
7.2
81
7.3
82
7.4
83
7.5
83
7.6
84
7.7
85
7.8
87
7.9
88
89
90
8.1
91
8.2
91
8.3
92
8.4
Classe CameraAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
8.5
Classe CameraPreview . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
8.6
95
8.7
96
8.8
96
8.9
97
98
99
99
9.2
9.3
9.4
9.5
9.6
9.7
xi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
145
145
146
147
147
148
148
148
151
151
Lista de Abreviaturas
xiii
xiv
Resumo
Esse material didtico oferece uma viso geral de como programar para o sistema mvel
Android e utilizar suas APIs nativas na criao de aplicativos. O material tentar cobrir desde
o bsico, como a configurao do ambiente de desenvolvimento, criao de layouts bsicos e
complexos, estrutura geral de um aplicativo e, finalmente, apresentar a programao de aplicativos mais complexos que utilizam APIs nativas.
O objetivo fornecer noes sobre como utilizar as ferramentas do Android, introduzir
os conceitos sem entrar em detalhes aprofundados do sistema operacional e assim disponibilizar uma viso bsica sobre o assunto. Aps a leitura desse material e realizao da prtica
o leitor dever estar preparado para construir seus prprios aplicativos nativos, e poder at
monetiz-los se desejar.
xv
C APTULO
1
Introduo
Introduo
Codinome
Donut
Eclair
Froyo
Gingerbread
Gingerbread
Honeycomb
Ice Cream Sandwich
Jelly Bean
Jelly Bean
API
4
7
8
9
10
13
15
16
17
Distribuio
0.1%
1.5%
3.2%
0.1%
36.4%
0.1%
25.6%
29.0%
4.0%
Tabela 1.1: Tabela com as distribuies das verses do Android, todas as verses com menos
de 0.1% de participao foram desconsideradas
4
5
Honeycomb: http://developer.android.com/about/versions/android-3.0-highlights.html
Gingerbread: http://developer.android.com/about/versions/android-2.3-highlights.html
Introduo
Esse material ir cobrir alguns tpicos no desenvolvimento de aplicativos para android, tais
como:
Configuraco do ambiente de desenvolvimento: Como configurar o ambiente para comear a desenvolver aplicativos, os primeiros passos para criar seu primeiro aplicativo de
maneira simples;
Elementos da interface: Como projetar seu aplicativo para usar as principais interfaces.
Listas, Listas compostas, Grades, Abas, Menus so as interfaces mais usadas nos diversos
aplicativos no mercado; e
Elementos de hardware: Como projetar seu aplicativo para usar as APIs de hardware:
Bluetooth, GPS, SMS, Chamadas.
Para esse material, algumas convenes sero seguidas:
Os cdigos estaro sempre com a sintaxe colorida para facilitar a leitura;
URLs das referncias estaro nas notas de rodap; e
Dicas estaro envoltas por uma caixa para facilitar a visualizao
Introduo
C APTULO
2
Configurao do Ambiente
http://developer.android.com/sdk/
Configurao do Ambiente
C APTULO
3
Linguagem do Android
3.1
Linguagem
A linguagem usada para programar na plataforma Android Java. Ento antes de engajar
no aprendizado Android altamente recomendvel estudar material Java e principalmente o
paradigma de orientao a objetos.
O Android tem algumas particularidades na organizao e configurao que feita atravs
de arquivos XML especficos do Android. Alguns arquivos XML servem para configurar o
aplicativo, layout de cada tela e outros do suporte a strings para facilitar o suporte a mltiplos
idiomas. Felizmente o conjunto Eclipse com ADT j cuida disso automaticamente e possui uma
srie de facilidades alcanadas por meio de interfaces grficas para os programadores. Por esse
motivo, para qualquer iniciante nessa rea recomendvel a utilizaco do ambiente Eclipse.
A criao de layouts dos aplicativos pode ser feita inteiramente atravs da interface grfica
disponvel no ambiente, no estilo drag and drop.
7
3.2
Linguagem do Android
Uma aplicao Android consiste de uma ou mais activities. Uma activity uma tela com views que interagem com o usurio. Como o Android segue o padro MVC (Model-View-Control)
as activities so os controllers e as views, views. As activities so classes do Java, o layout e
outros recursos so definidos em arquivos XML.
Dentre os diversos arquivos XML existentes na configurao de um aplicativo Android o
mais importante o AndroidManifest.xml 1 pois nele que se exprimem as configuraes
gerais do aplicativo. Nesse texto no iremos adentrar muito nos detalhes das configuraes,
mas apenas deixar claro que nesse arquivo que se colocam as verses do Android que seu
aplicativo ser compatvel com, as permisses para usar os recursos do aparelho como Internet,
GPS, Bluetooth, etc.
A pasta src/ contm o pacote com as classes do seu aplicativo isto , o cdigo fonte do
seu aplicativo. Tanto activites como classes de suporte devem estar dentro do pacote.
Dentro da pasta res/ de recursos, encontram-se outros arquivos, referentes disposio
do layout, valores de strings e imagens que sua aplicao ir utilizar. A pasta layout/ junto
com as pastas drawable-*/ servem para dispor o layout. Cada drawable comporta imagens
para um tamanho diferente de tela, enquanto que a pasta de layout contm a disposio geral
do layout. So nesses arquivos que se colocam os itens (views) que iro nas telas, como botes,
caixas de texto, caixas de seleo, etc.
Na pasta values/ o mais importante o arquivo strings.xml que contm os valores
das strings do aplicativo. Sempre que voc quiser referenciar alguma string, a mesma dever estar expressa nesse arquivo. Fica fcil dessa forma fazer o aplicativo suportar mltiplos idiomas,
pois basta traduzir esse nico arquivo para alterar todos os textos do aplicativo.
A pasta menu/ contm os layouts do menus do aplicativo, esses so aqueles que podem ser
acessados atravs da Action Bar2 ou atravs dos botes fsicos do aparelho.
1
2
Linguagem do Android
Resumindo:
AndroidManifest.xml: Configuraes gerais do aplicativo;
src/: Classes do aplicativo; e
res/: Recursos do aplicativo tais que:
strings/: Todos os textos da sua aplicao, suporte a mltiplos idiomas;
layout/: Todos os layouts de suas telas (activites);
drawable/: Todas as imagens, separados por tamanho de tela; e
menu/: layout dos menus do aplicativo.
10
Linguagem do Android
C APTULO
4
Criando seu primeiro aplicativo
Para exemplificar a criao de um aplicativo, seguiremos o exemplo dado pelo prprio manual do Google sobre o Android (Ver original1 ). Trata-se de aplicativo simples do tipo Hello
World.
Iniciaremos criando um novo projeto no Eclipse acessando o menu: File -> New -> Android
Application Project.
Na janela que apareceu voc deve colocar o nome do aplicativo, do projeto e do pacote. O
nome do pacote deve seguir a conveno do Java2 .
Minimum Required SDK: a verso mnima do sistema operacional Android que sua
aplicao ir suportar, o mais comum a verso 8 do SDK que se refere ao Android 2.2.
Alguns tipos de layouts mais complexos no so suportados em verses mais antigas;
Target SDK: a verso principal do Android para qual seu aplicativo est sendo desenvolvido;
Compile With: Verso do Android com qual seu aplicativo ser compilado; e
Theme: Cores do layout.
1
2
11
12
13
14
15
Observe na Figura 4.1 a janela de criao de uma nova aplicao Android. Em Application
Name voc deve colocar o nome do aplicativo, em Project Name, o nome do projeto e em
Package Name o nome do pacote. Para esse exemplo utilizaremos como Minimum Required
SDK a verso API 8, j que nesse exemplo no usaremos nenhum layout que no suportado
em verses mais antigas. Em Target SDK e Compile With optaremos pela verso mais nova, a
API 17. Por final o Theme eu optei pelo Holo Light with Dark Action Bar que um tema com
fundo branco e barra superior preta, um dos padres do Android.
Dica: Para obter o mximo de compatibilidade sempre procure utilizar layouts compatveis com verses antigas, observe na figura 1.1 que verses antigas ainda tem uma fatia
considervel do mercado.
A figura 4.2 mostra a segunda janela da configurao inicial do seu aplicativo. Voc pode
escolher um cone personalizado se marcar a caixa Create custom launcher icon o que te levar
para a janela da figura 4.3. Se marcar Create Activity o assistente de criao te levar para a
janela da figura 4.4 onde poder escolher qual activity vai ser criada para seu aplicativo. Em
todos os exemplos escolheremos a opo Blank Activity. Como nosso projeto no uma biblioteca no marcaremos Mark this project as a library. Se marcar Create Project in Workspace o
assistente ir salvar o projeto na pasta que foi configurada para o Workspace, caso contrrio ele
ir pedir para escolher outro caminho. Como no trabalharemos com Working Sets do Eclipse,
a opo Add project to working sets permanece desmarcada.
Finalmente a figura 4.5 mostra a janela para nomear a activity inicial, nesse exemplo mantive
MainActivity. O nome do layout dessa activity mantive como activity_main que o padro. Na
caixa Navigation Type existem algumas opes de layout pr-definidas pelo Android. So elas:
None: O layout vem apenas com uma Action Bar3
Fixed Tabs + Swipe: O layout vem com algumas abas e com gesto de arrastar entre as
abas (activities) pr-programados.
Scrollable Tabs + Swipe: O layout vem com algumas abas e com gesto de arrastar entre
as abas pr-programados, porm nesse o estilo das abas diferente, em vez de abas fixas,
3
4
16
1
2
3
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
A tag uses-sdk serve apenas para o compilador saber quais verses do Android voc
pretende que seu aplicativo suporte. Dessa forma quando seu aplicativo for lanado na loja
Google Play o aplicativo s ser visvel para aqueles usurios que possuem a verso mnima do
Android indicada no atributo.
Primeiro vamos criar um layout para o aplicativo usando o construtor de interfaces presente
no ambiente, primeiro abra o arquivo res/layout/activity_main.xml , segundo o
manifest, essa activity que ser aberta quando o aplicativo for iniciado, isso configurado
atravs do intent-filter5 .
Selecione o Hello world e o remova da sua activity.
A tela dever ficar parecida com a da figura 4.4. Agora arraste um Text Field -> Plain Text
e um Form Widgets -> Button para sua activity.
5
17
<EditText
android:id="@+id/nameField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="28dp"
android:layout_marginTop="35dp"
android:ems="10"
android:hint="@string/name">
<requestFocus />
</EditText>
18
<Button
android:id="@+id/sendButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@id/nameField"
android:layout_below="@id/nameField"
android:layout_marginTop="48dp"
android:text="@string/send_button"
android:onClick="sendMessage" />
<resources>
<string name="app_name">MeuApp</string>
<string name="action_settings">Settings</string>
<string name="send_button">Enviar</string>
<string name="name">Nome</string>
</resources>
19
por obter o contedo da caixa de texto e enviar para uma nova activity que ir mostrar esse
contedo.
1
2
3
Dica: Isso vai requer voc importe a classe View, voc pode apertar Ctrl+Shit+O no
Eclipse para importar classes que estejam faltando
import android.view.View;
Algoritmo 4.8: Obtendo o contedo da caixa de texto e enviando para outra activity
7
20
O cdigo na linha 3 est obtendo a referncia da caixa de texto usando o mtodo findViewById() passando o id da caixa de texto como parmetro, esse id obtido acessando uma
varivel esttica da classe R (observe que esse e o mesmo id que voce colocou no arquivo xml
do layout da activity). Em seguida usando o mtodo getText() da caixa de texto, obtem-se
a string que foi escrita pelo usurio.
Por fim, essa string colocada no Intent com o mtodo putExtra(), uma Intent
pode carregar consigo uma coleo de vrios tipos de dados como pares chave-valor chamados
extras, esse mtodo toma a chave como primeiro parmetro e o valor no segundo parmetro.
Para que a prxima activity consiga coletar esse valor, voc deve definir uma chave para seu
extra usando uma constante pblica. Para isso adicione a definio de EXTRA_MESSAGE no
topo da sua classe MainActivity.
1
2
3
4
5
Agora voc deve criar uma nova activity, para isso v em File -> New -> Other -> Android
Activity e selecione Blank Activity. Preencha a prxima janela como na figura 4.8, depois clique
Finish.
21
http://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)
22
Agora, precisamos extrair os dados enviados a essa activity atravs do intent, voc pode
obter a referncia do intent que comeou a activity chamando o mtodo getIntent()9 .
1
2
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
5
6
7
8
9
10
11
//Cria o TextView
TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText("Hello " + mensagem);
12
13
14
15
16
17
18
19
http://developer.android.com/reference/android/app/Activity.html#getIntent()
http://developer.android.com/reference/android/widget/TextView.html
23
emulador. Lembrando que para ambos os casos necessria a instalao do SDK primeiro,
acesse Android SDK Manager e faa o download do SDK desejado.
Para rodar diretamente no smartphone:
1. Conecte seu smartphone no computador atravs do cabo USB. Se estiver desenvolvendo
no Windows ser preciso instalar os drivers USB do seu dispositivo. Se precisar de ajuda
para instalar os drivers acesse: OEM USB11
2. Ative o modo USB Debugging no dispositivo
Para Android 3.2 ou mais antigos, a opo deve estar em Configuraes -> Aplicativos -> Desenvolvimento
Para Android 4.0 e 4.1, a opo est em Configuraes -> Opes do desenvolvedor
Para Android 4.2 e mais novos, a opo est escondida por padro, para mostrar a
opo voc deve entrar em Sobre o telefone e clicar em Nmero da verso 7 vezes,
ao retornar para tela anterior dever aparecer Opes do desenvolvedor
Dica: Caso ocorra o erro Launch error: adb rejected command: device not found.
Verifique se o aparelho est conectado e se os drivers esto instalados corretamente. Na rea
de notificaes do aparelho deve ter uma notificao escrita: Android debugging enabled.
11
http://developer.android.com/tools/extras/oem-usb.html
24
http://developer.android.com/tools/devices/index.html
25
26
C APTULO
5
Design
5.1
Activity
Enquanto um usurio navega pelas variadas telas de um aplicativo, sai dele e volta depois,
as instncias de uma activity transitam dentre diferentes estados em seu ciclo de vida. Quando
um aplicativo iniciado, uma activity inicial criada o sistema invoca mtodos especficos
que correspondem a criao dessa activity. Durante todo o ciclo de vida vrios mtodos so
chamados, e todos eles correspondem a diferentes estgios desse ciclo de vida.
Observe na imagem abaixo os mtodos correspondentes a cada estado da vida de uma activity, quando ela criada o mtodo onCreate() o responsvel pela configuraco inicial. O
sistema ao criar uma nova instncia de uma activity, cada mtodo muda o estado da activity um
degrau pra cima na pirmide.
28
Design
casos a activity ir apenas ir at certo ponto e esperar (por exemplo quando o usurio troca para
outro aplicativo) tal que ela possa voltar de onde parou caso o usurio volte.
No so todos mtodos que precisam ser implementados pois isso ir depender da complexidade do seu aplicativo. importante salientar porm que, implementar esses mtodos ir
garantir que seu aplicativo se comporte de maneira correta, por exemplo voc deve garantir que:
Seu aplicativo no falhe quando o usurio receber uma chamada telefnica ou quando o
usurio troca de aplicativo;
Seu aplicativo no consuma recursos do sistema enquanto no estiver sendo usado;
Seu aplicativo no perca o progresso do usurio; e
Seu aplicativo no falhe ou perca o progresso do usurio quando a tela rotaciona entre
retrato e paisagem.
Apenas trs dentre os estados so estticos, isto , a activity pode ficar nesse estado por um
longo perodo de tempo:
Retomado (Resumed)
Nesse estado a activity est em primeiro plano e o usurio pode interagir com ela.
Pausado (Paused)
Nesse estado a activity est parcialmente obscurecida por outra activity - a outra activity
que est em primeiro plano semi-transparente ou no ocupa todo espao da tela. A activity
quando pausada no consegur interagir com o usurio e no executa nenhum cdigo.
Parado (Stopped)
Nesse estado a activity est completamente oculto e no est visvel para o usurio, est
em plano de fundo. Quando est parada, uma instncia de uma activity e toda informao de
seu estado tais como variveis so mantidos, porm a activity no executa nenhum cdigo.
5.2
Quando um usurio abre um aplicativo, o sistema chama o mtodo onCreate() da activity que foi declarada como sendo a iniciadora do aplicativo. Voc pode definir qual activity
que vai iniciar seu aplicativo no arquivo AndroidManifest.xml que est no diretrio raz
do seu projeto.
A activity que inicia seu aplicativo deve ser declarada no manifesto com um <intent-filter>1
que inclui a <action> MAIN e a <category> LAUNCHER. Por exemplo:
1
2
3
4
5
6
Design
29
Dica: Quando voc cria um projeto Android no Eclipse, por padro includa uma
classe activity que est declarada no manifesto com esse filtro.
5.3
Tipos de Layout
Uma Activity contm Views e ViewGroups. Uma view um elemento que tm presena na
tela do dispositivo tais como botes, textos, imagens e etc. Um ViewGroup por sua vez um
elemento agrupador de views que prov um layout na qual voc pode ajustar a ordem e apario
das views.
5.3.1
LinearLayout
O LinearLayout arranja views em uma nica coluna ou uma nica linha, desse modo as
views podem ser arranjadas verticalmente ou horizontalmente. Como mostrado na figura 5.2:
30
5.3.2
Design
RelativeLayout
Novamente cabe comentar que possvel aninhar diferentes ViewGroups para formar um
layout com maior complexidade.
5.3.3
FrameLayout
O FrameLayout o mais simples e eficiente tipo de layout, pode ser usado apenas para
mostrar uma view ou views que se sobrepem. Geralmente usado como um recipiente para os
Fragments3 .
Uma view definida em um FrameLayout sempre ser colocado no canto superior esquerdo da tela do dispositivo ou do ViewGroup a que pertence o FrameLayout. Se mais de
uma view foi definida elas sero empilhadas uma em cima da outra. Isso significa que a primeira
view adicionada ao FrameLayout ser mostrada na base da pilha, e a ltima adicionada ser
mostrada no topo.
Voc pode fazer com que as views no sobreponham as outras usando o atributo layout_gravity4 , dessa forma uma view pode ficar posicionada na borda inferior e outra na borda
superior e no ficarem sobrepostas.
possvel posicionar as views dentro de um FrameLayout usando parmetros diferentes
no layout_gravity, no exemplo da figura 5.5 existe um FrameLayout com 3 elementos
e cada um com parmetros diferentes. possivel combinar os parmetros utilizando a barra
reta |.
2
http://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html
Mais informaes na seo 5.8
4
http://developer.android.com/reference/android/widget/FrameLayout.LayoutParams.html
3
Design
31
5.3.4
TableLayout
TableLayouts podem ser usadas para apresentar dados tabulados ou alinhar contedo
como tabelas HTML em uma pgina web. Um TableLayout composto de TableRows,
uma cada para linha da tabela. Os contedos das TableRows so as views que vo em cada
clula da tabela. Cada linha ter zero ou mais clulas e cada clula pode conter uma view.
O aspecto da TableLayout vai depender de alguns fatores. Primeiro, o nmero de colunas da tabela inteira vai depender do nmero de colunas da linha que contm mais colunas.
Segundo, a largura de cada coluna definida como a largura do contedo mais largo da coluna.
Voc pode combinar colunas para formar uma clula maior, mas no pode combinar linhas.
Leia mais na documentao5
Embora TableLayouts possam ser usados para projetar interfaces, geralmente no a
melhor opo j que so derivadas de LinearLayouts. Se voc tem dados que j esto em
formato de tabela, como planilhas, ento pode ser uma boa opo.
http://developer.android.com/reference/android/widget/TableLayout.html
32
5.4
Design
Listas (ListView)
Listas so uma das formas mais simples e poderosas de se mostrar informaes ao usurio
de forma objetiva. A ListView capaz de aprensentar uma lista rolvel de itens.
5.4.1
Adaptadores
Adaptadores so usados para providenciar dados a views. O adaptador tambm define como
item da view ser mostrada. Para ListViews o adaptador define como cada linha ser mostrada.
Um adaptador deve extender a classe base BaseAdapter. O Android j tem alguns adaptadores padro, os mais importantes so o ArrayAdapter e o CursorAdapter.
O ArrayAdapter usado para manipular dados em arrays ou listas (java.util.List).
J o SimpleCursorAdapter consegue manipular dados em banco de dados.
6
Documentao ListView:http://developer.android.com/reference/android/widget/ListView.html
Design
5.4.2
33
Construo
A construo desse tipo de design simples. No arquivo de layout da activity use o LinearLayout para conter a ListView.
1
2
3
4
5
6
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</LinearLayout>
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
<string-array name="listString">
<item>Menu 1</item>
<item>Menu 2</item>
<item>Menu 3</item>
<item>Menu 4</item>
</string-array>
34
1
2
Design
3
4
5
6
7
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
9
10
11
//Obtem a lista
ListView lv = (ListView) findViewById(R.id.listView1);
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
//Quando clicado, mostra um Toast
Toast.makeText(getApplicationContext(),
((TextView) view).getText(), Toast.LENGTH_SHORT).show();
}
});
24
25
26
27
28
29
30
31
32
33
}
...
http://developer.android.com/reference/android/widget/ArrayAdapter.html
Design
35
Toast, o Toast mostra uma mensagem em uma caixa de texto na parte inferior da tela por um
curto perodo de tempo, nesse caso ir mostrar o mesmo texto do item da lista que foi clicado.
Uma das aplicaes mais comuns fazer com que ao se clicar em um item da lista, uma nova
activity seja aberta com detalhes do item.
A figura 5.9 mostra como ficou o exemplo ao ser executado em um smartphone, o item
Menu 2 foi clicado e um Toast foi mostrado no momento do clique.
5.5
Listas Compostas
possvel compor um item da lista colocando mais elementos alm de um texto. Para
isso voc precisa criar um novo arquivo XML que ir definir a customizao de cada linha da
ListView, nesse exemplo iremos definir um arquivo chamado item.xml, mostrado abaixo.
36
1
2
3
4
5
Design
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
6
7
8
9
10
11
12
<ImageView
android:id="@+id/userIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp" >
</ImageView>
13
14
15
16
17
18
19
20
21
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical"
android:paddingLeft="0px"
android:paddingRight="5dp" >
22
23
24
25
26
27
28
29
30
<TextView
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:textColor="#FFF38585"
android:textSize="15sp" >
</TextView>
31
32
33
34
35
36
37
38
39
<TextView
android:id="@+id/usertext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="#FF444444"
android:textSize="13sp" >
</TextView>
40
41
42
</LinearLayout>
</LinearLayout>
Design
37
Agora voc precisa usar um adaptador para mostrar esse layout customizado em cada linha
da lista, usaremos a classe SimpleAdapter8 . Essa classe faz a adaptao de um ArrayList de Maps para um layout definido.
1
2
3
4
5
6
7
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Obtem a lista
ListView lv = (ListView) findViewById(R.id.listView1);
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
lv.setAdapter(adapter);
31
32
http://developer.android.com/reference/android/widget/SimpleAdapter.html
38
Design
R.layout.item. Passamos um array de strings que contm as chaves que sero usadas
para obter os dados e por ltimo um array de inteiros que contm os ids das views em que os
contedos dos Maps sero colocados.
5.6
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
6
7
8
9
10
11
12
13
<ExpandableListView
android:id="@+id/expandableList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:transcriptMode="alwaysScroll"
android:listSelector="@android:color/holo_green_light">
</ExpandableListView>
14
15
</LinearLayout>
5
1
2
3
4
5
6
Design
39
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_item"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
7
8
9
10
11
12
13
14
15
<TextView
android:id="@+id/list_item_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="20sp"
android:padding="10dp"
android:layout_weight="1"
android:layout_marginLeft="35dp" />
16
17
</LinearLayout>
Nesses dois layouts teremos apenas uma TextView para abrigar um texto.
1
2
3
4
5
6
7
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_item_child"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical">
8
9
10
11
12
13
14
15
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/list_item_text_child"
android:textSize="20sp"
android:padding="10dp"
android:layout_marginLeft="5dp"/>
16
17
</LinearLayout>
Em seguida precisamos criar uma classe que ir abrigar os dados dos elementos pai, elementos estes que sero expandidos quando clicados. Nesse exemplo criamos uma classe Parent,
como mostrado no algoritmo 5.11
40
1
2
3
Design
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
//Obtem o nome de cada item
public Object getChild(int groupPosition, int childPosition) {
return parent.get(groupPosition).getArrayChildren().
get(childPosition);
}
16
17
18
19
20
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
Design
21
22
23
24
25
@Override
//Nesse metodo voce seta os textos para ver os filhos na lista
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View view, ViewGroup viewGroup) {
26
if(view == null){
view = inflater.inflate(R.layout.list_item_child, viewGroup,
false);
}
27
28
29
30
31
32
33
34
textView.setText(parent.get(groupPosition).getArrayChildren().
get(childPosition));
35
36
37
return view;
38
39
40
41
42
43
44
45
@Override
public int getChildrenCount(int groupPosition) {
//retorna o tamanho do array de filhos
return parent.get(groupPosition).getArrayChildren().size();
}
46
47
48
49
50
51
@Override
//Obtem o titulo de cada pai
public Object getGroup(int groupPosition) {
return parent.get(groupPosition).getTitle();
}
52
53
54
55
56
@Override
public int getGroupCount() {
return parent.size();
}
57
58
59
60
61
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
62
63
64
65
66
@Override
//Nesse metodo voce seta o texto para ver os pais na lista
public View getGroupView(int groupPosition, boolean isExpanded,
View view, ViewGroup viewGroup) {
67
68
69
70
71
if(view == null) {
//Carrega o layout do parent na view
view = inflater.inflate(R.layout.list_item_parent, viewGroup,
false);
41
42
Design
72
73
//Obtem o textView
TextView textView = (TextView)
view.findViewById(R.id.list_item_text_view);
74
75
76
77
textView.setText(getGroup(groupPosition).toString());
78
79
return view;
80
81
82
@Override
public boolean hasStableIds() {
return true;
}
83
84
85
86
87
@Override
public boolean isChildSelectable(int groupPosition,
int childPosition) {
return true;
}
88
89
90
91
92
93
http://developer.android.com/reference/android/view/LayoutInflater.html
5
1
2
Design
43
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
4
5
6
7
8
mExpandableList = (ExpandableListView)
findViewById(R.id.listaExpandivel);
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
parent.setmArrayChildren(arrayChildren);
arrayParents.add(parent);
38
39
40
41
mExpandableList.setAdapter(
new CustomAdapter(MainActivity.this, arrayParents));
42
43
}
...
44
45
46
44
Design
Design
5.7
45
Grades so teis para mostrar imagens e fotos como uma galeria, ou permitir a seleo de
categorias semelhante a uma lista. A idia ter elementos lado a lado para mostrar ou para
selecionar e mostrar mais detalhes. Basicamente funciona como uma grade bi-dimensional que
pode ser arrastada para os lados ou de cima pra baixo.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
6
7
8
9
10
11
12
13
14
15
16
17
<GridView
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="auto_fit"
android:columnWidth="90dp"
android:horizontalSpacing="10dp"
android:verticalSpacing="10dp"
android:gravity="center"
android:stretchMode="columnWidth" >
</GridView>
18
19
</LinearLayout>
http://developer.android.com/reference/android/widget/GridView.html
46
1
2
Design
4
5
6
7
8
9
10
11
//Construtor
public ImageAdapter(Context c){
mContext = c;
}
12
13
14
15
16
@Override
//Retorna o tamanho do array
public int getCount() {
return thumbIds.length;
}
17
18
19
20
21
22
@Override
//Retorna um elemento do array
public Object getItem(int position) {
return thumbIds[position];
}
23
24
25
26
27
28
@Override
//Nao sera usado
public long getItemId(int position) {
return 0;
}
29
30
31
32
33
34
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
ImageView imageView = new ImageView(mContext);
imageView.setImageResource(thumbIds[position]);
imageView.setLayoutParams(new GridView.LayoutParams(200,200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
return imageView;
}
35
36
37
38
39
40
41
42
43
44
http://developer.android.com/reference/android/widget/BaseAdapter.html
Design
47
varivel pblica, um array das imagens que queremos colocar na grade. Como todo id de um
recurso da classe R um inteiro, criamos um array de inteiros. Note que estamos considerando
que todas as imagens j foram devidamente colocadas na pasta drawable.
O mtodo mais importante o mtodo getView(). Nele criamos uma nova ImageView12 para abrigar a imagem que queremos colocar na grade. Em seguida configuramos
alguns parmetros desse ImageView, o mtodo ImageView.setImageResource()
responsvel por estabelecer um drawable como contedo do ImageView. J o mtodo
View.setLayoutParams() configura os parmetros de layout associados com essa view,
note que para esse mtodo passamos parmetros de layout de uma GridView, que por sua vez
recebe (200,200) como largura e altura de um elemento da grade.
ImageView.setScaleType controla como a imagem deve ser redimensionada para
condizer com o tamanho do ImageView, ImageView.ScaleType13 so as formas disponveis para escalar a imagem.
Agora basta criar a grade em sua activity.
1
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
3
4
5
6
7
8
9
10
11
12
13
14
...
}
http://developer.android.com/reference/android/widget/ImageView.html
http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
48
Design
Para complementar, voc pode fazer com que a imagem abra em tela cheia quando clicada
na view, para isso necessrio que voc passe o id do recurso do GridView para uma nova
activity que ir mostrar a imagem em tela cheia. Para isso precisamos criar um novo layout
XML, a qual chamaremos de full_image.xml, nele teremos apenas uma ImageView e
um TextView que ser uma pequena legenda da imagem.
1
2
3
4
5
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/relativelayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
6
7
8
9
10
<ImageView
android:id="@+id/full_image_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
11
12
13
14
15
16
17
18
19
<TextView
android:id="@+id/myImageViewText"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:gravity="center"
android:background="#55555555"
android:textSize="16sp"
android:textColor="#FFFFFF" />
20
21
</RelativeLayout>
5
1
2
3
4
Design
49
6
7
8
//Seleciona o id da imagem
int id = intent.getExtras().getInt("id");
ImageAdapter imageAdapter = new ImageAdapter(this);
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gridView = (GridView) findViewById(R.id.gridview);
gridView.setAdapter(new ImageAdapter(this));
8
9
10
@Override
public void onItemClick(AdapterView<?> parent, View view,
int pos, long id) {
//Envia o id da imagem para o FullImageActivity
Intent intent = new Intent(getApplicationContext(),
FullImageActivity.class);
intent.putExtra("id", pos);
startActivity(intent);
}
});
11
12
13
14
15
16
17
18
19
20
21
50
Design
5.8
Fragmentos
Fragmentos so a soluo do Android para criar interfaces de usurio modulares, eles vivem
dentro das activity e uma activity pode conter vrios fragmentos. Assim como as activity os
fragmentos possuem um ciclo de vida.
Dentre as vantagens de um fragmento esto:
Modularidade e reuso de cdigo
Habilidade de construir interfaces com mltiplos painis
Facilidade de construir aplicativos para celulares e tablets
O primeiro conceito a ser coberto como construir um fragmento, comece definindo o
layout do fragmento.
Um layout bem simples, apenas com um boto para efeito de demonstrao. Agora crie
uma classe BasicFragment
5
1
Design
51
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState){
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public void onClick(View v) {
Activity activity = getActivity();
16
17
18
19
if(activity != null){
Toast.makeText(activity,
"A toast to a fragment", Toast.LENGTH_SHORT).show();
}
20
21
22
23
}
});
return view;
24
25
26
27
28
Caso voc esteja desenvolvendo para API menores que 11 (HoneyComb 3.0) voc vai precisar usar a API de retrocompatibilidade que o Google providenciou para essas APIs, voc precisa
importar a classe de suporte:
import android.support.v4.app.Fragment;
Agora para incluir o fragmento na activity existem duas opes. A primeira inlcuir o
fragmento no XML da activity como voc faria com qualquer view.
52
1
2
3
4
Design
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
5
6
7
8
9
10
11
12
<fragment
android:id="@+id/fragment_content"
android:name="com.example.fragmento.BasicFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</fragment>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/fragment_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
6
7
8
9
10
11
</LinearLayout>
http://developer.android.com/guide/topics/manifest/activity-element.html#nm
5
1
Design
53
2
3
4
5
6
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
8
9
10
11
12
13
14
if(fragment == null){
//Comeca uma transacao de fragmentos
FragmentTransaction ft = fm.beginTransaction();
//Adiciona o fragmento
ft.add(R.id.fragment_content, new BasicFragment());
//"Commita" a transacao
ft.commit();
}
15
16
17
18
19
20
21
22
23
24
}
...
E dessa forma obtemos o mesmo resultado, porm com a adio dinmica do fragmento,
voc pode experimentar e fazer com que o boto remova um fragmento e coloca outro diferente
no lugar.
5.9
Abas (Tabs)
Existem diversas maneiras de criar uma interface com abas no Android, uma delas usando
as interfaces TabHost e TabWidget, outra imitando o comportamento usando apenas
Fragments.
5.9.1
Abas usando essas interfaces so suportadas por todas as verses do Android.Vamos criar
uma interface com abas seguindo esse esquema:
54
Design
<TabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
7
8
9
10
11
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
12
13
14
15
16
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
17
18
19
20
21
22
23
</LinearLayout>
</TabHost>
http://developer.android.com/reference/android/widget/TabWidget.html
http://developer.android.com/reference/android/widget/TabHost.html
Design
55
Agora precisamos definir o layout dos fragmentos, isto , o layout de cada aba. Para simplificar o exemplo, as abas s tero um fundo colorido, de cores diferentes. Para isso usa-se o
atributo background.
1
2
3
4
5
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FF0000" />
1
2
3
if(container == null){
return null;
}
5
6
7
8
9
10
11
12
56
1
2
3
4
5
Design
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Estabelece o layout da activity
setContentView(R.layout.activity_tab_layout);
13
14
15
16
17
18
19
20
21
http://developer.android.com/reference/android/widget/TabHost.TabContentFactory.html
5
1
2
Design
57
4
5
6
7
@Override
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumHeight(0);
v.setMinimumWidth(0);
return v;
}
8
9
10
11
12
13
14
15
//Cria Tab1
tabSpec = mTabHost.newTabSpec("Tab1");
tabSpec.setIndicator("Tab 1");
tabSpec.setContent(new TabFactory(this));
tag = tabSpec.getTag();
tabInfo = new TabInfo("Tab1", Tab1Fragment.class, args);
tabInfo.fragment = getSupportFragmentManager().
findFragmentByTag(tag);
mTabHost.addTab(tabSpec);
mapTabInfo.put(tabInfo.tag, tabInfo);
/* Repete para Tab2 e Tab3 */
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
58
Design
@Override
public void onTabChanged(String tag) {
TabInfo newTab = mapTabInfo.get(tag);
if(mLastTab != newTab){
FragmentTransaction ft =
getSupportFragmentManager().beginTransaction();
5
6
7
8
if(mLastTab != null){
if(mLastTab.fragment != null){
ft.detach(mLastTab.fragment);
}
}
9
10
11
12
13
14
if(newTab != null){
if(newTab.fragment == null){
newTab.fragment = Fragment.instantiate(this,
newTab.klass.getName(), newTab.args);
ft.add(android.R.id.tabcontent, newTab.fragment, newTab.tag);
} else {
ft.attach(newTab.fragment);
}
}
mLastTab = newTab;
ft.commit();
getSupportFragmentManager().
executePendingTransactions();
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Design
59
1
2
3
4
60
5.10
Design
possvel trocar entre fragmentos usando o gesto de arrastar, isto , arrastando a tela de um
lado para o outro acionar a troca entre os fragmentos.
Primeiro iremos definir o layout do ViewPager18 . Depois iremos definir o PagerAdapter19 . Por ltimo precisamos definir a activity que ir conter o visualizador de pginas.
1
2
3
4
5
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
6
7
8
9
10
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
11
12
</LinearLayout>
Agora defina uma nova classe chamada PagerAdapter que ir extender a classe FragmentPagerAdapter. Primeiro crie uma lista que ir conter os fragmentos, isto , as pginas
que sero exibidas. Ao extender essa classe precisamos implementar dois mtodos: getItem() e getCount(). O mtodo getItem(), na linha 10 do algoritmo 5.34, deve retornar
o item que ser selecionado pelo parmetro position. O mtodo getCount(), na linha
15, deve retornar a quantidade de pginas. Depois crie o construtor como mostrado nas linhas
4-7.
18
19
http://developer.android.com/reference/android/support/v4/view/ViewPager.html
http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html
5
1
2
Design
61
4
5
6
7
8
@Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
9
10
11
12
13
@Override
public int getCount() {
return this.fragments.size();
}
14
15
16
17
18
Por ltimo devemos construir a activity que ir conter o PagerAdapter e ser reponsvel
por mostrar as pginas. Neste exemplo iremos reutilizar os fragmentos que fizemos na seo
anterior quando trabalhamos com abas.
Essa activity, como mostrada no algoritmo 5.35 abaixo, apenas precisa instanciar os fragmentos (linhas 10,11 e 12), criar e determinar o adaptador, linhas 14, 16 e 17.
62
1
2
Design
3
4
5
6
7
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpager_layout);
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
}
...
}
5.11
Ao juntar os dois conceitos, o de layout com abas e o gesto de arrastar, podemos fazer o
controle das abas arrastando a tela. Esse tipo de design comum em muitos aplicativos pela
facilidade e rapidez com o que o usurio pode visualizar vrios contedos. Nesse exemplo iremos reutilizar o cdigo dos exemplos anteriores com algumas modificaes. Sero reutilizadas
classes: TabInfo, TabFactory, PagerAdapter, Tab1Fragment, Tab2Fragment,
Tab3Fragment.
Primeiro modificaremos o layout das abas adicionando o ViewPager aps FrameLayout.
Note que esse o mesmo layout do algoritmo 5.24, por isso o algoritmo 5.36 no est completo.
5
1
2
3
4
5
Design
63
...
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
7
8
9
10
11
12
13
14
</FrameLayout>
...
10
11
12
13
14
15
64
1
2
3
4
5
Design
@Override
public void onTabChanged(String tag) {
int pos = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(pos);
}
1
2
3
4
@Override
public void onPageScrollStateChanged(int arg0) {
//Nada
}
5
6
7
8
9
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
//Nada
}
10
11
12
13
14
@Override
public void onPageSelected(int position) {
mTabHost.setCurrentTab(position);
}
Dica: Pela dificuldade em acompanhar passo a passo a construo desse design, recomendvel obter o cdigo do projeto no repositrio. Est sob o nome SwipeableTabs.
5.12 ActionBar
A ActionBar aquela barra presente em em todos os aplicativos que fizemos de exemplo
at agora. Ela pode mostrar o nome da activity, cones, aes que podem ser acionadas, outras
views ou botes interativos. Tambm pode ser usada para navegar entre as actvities do seu
aplicativo.
Dispositivos Android mais antigos possuem um boto fsico chamado Option que abre um
menu na parte inferior do aplicativo. A ActionBar melhor que esse menu pois est claramente visvel para o usurio, enquanto que o menu antigo era escondido e o usurio pode no
reconhecer que as opes esto disponveis.
Design
65
5.12.1
Implementando a ActionBar
<menu
xmlns:android="http://schemas.android.com/apk/res/android" >
3
4
5
6
7
8
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="always"
android:title="@string/action_settings"/>
9
10
</menu>
66
1
2
3
4
5
Design
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
Dica: Para criar uma nova activity, clique com o boto direito sob o projeto selecione
New -> Other (ou pressione Ctrl+N). Selecione Android Activity e selecione o tipo desejado.
Agora voc deve fazer com que o mtodo OnCreateOptionsMenu() abra essa nova
activity.
1
2
3
4
5
6
Para melhorar nossa ActionBar vamos adicionar um campo para pesquisa. Voc pode adicionar views em sua ActionBar. Para isso voc deve usar o mtodo setCustomView() da
classe ActionBar e passar uma view como parmetro. Voc tambm precisa ativar a exibio
de views com o mtodo setDisplayOptions() e passar a flag ActionBar.DISPLAY_SHOW_CUSTOM.
Primeiro vamos adicionar um cone de busca na nossa ActionBar, voltando ao arquivo do
layout da ActionBar, adicione um novo item acima do primeiro como mostrado no algoritmo
abaixo.
5
1
Design
67
<item
android:id="@+id/action_search"
android:orderInCategory="100"
android:showAsAction="always"
android:title="Search"
android:icon="@android:drawable/ic_menu_search" />
3
4
5
6
7
8
9
<item
android:id="@+id/action_settings"
android:showAsAction="never"
android:title="@string/action_settings"/>
10
11
12
13
14
15
</menu>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getActionBar().setDisplayOptions
(ActionBar.DISPLAY_SHOW_CUSTOM |
ActionBar.DISPLAY_SHOW_HOME);
6
7
8
9
68
Design
entrada ser texto, essa combinao faz com que o teclado mostre o cone da lupa no lugar da
tecla Enter. A linha 10 configura a cor do texto para branca. Adicionamos a view na ActionBar
com o mtodo ActionBar.setCustomView() e passamos como parmetro a view criada
e os parmetros de layout criados. O mtodo EditText.requestFocus() faz com que
o foco seja dado nova caixa de texto, para que possamos edit-la. Precisamos ainda fazer
com que o teclado abra para que possamos editar a caixa de texto, isso que as linhas 13-14 e
15 esto fazendo. O mtodo getSystemService() obtm a referncia de um servio do
Android, e nesse caso estamos pedindo pelo servio de mtodo de entrada, o teclado. O mtodo
InputMethodManager.showSoftInput() abre o Soft Input, ou seja, o teclado virtual
para edio da view.
Finalmente fazemos com que ao boto de busca no teclado ser clicado, um Toast mostre
para o usurio o contedo da caixa de texto. isso que a interface onEditorActionListener faz com o mtodo onEditorAction().
A inteno desse exemplo mostrar como voc pode adicionar novas views na ActionBar
de forma dinmica.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public boolean onEditorAction
(TextView v, int actionId, KeyEvent event) {
Toast.makeText
(MainActivity.this, v.getText(), Toast.LENGTH_SHORT).show();
return true;
}
});
18
19
20
21
22
23
24
25
}
return true;
26
27
28
Design
69
70
Design
C APTULO
6
Comunicao
6.1
Internet
Antes de iniciar sua aplicao que faz acesso Internet, devemos dar permisso ao aplicativo atravs do arquivo de Manifest. Logo antes da tag uses-sdk voc deve adicionar a tag
uses-permission, como mostrado abaixo:
<uses-permission android:name="android.permission.INTERNET"/>
Nesta seo, veremos como se faz requisies HTTP para obter pginas HTML, sadas de
um script server-side como PHP ou ASP.NET e parsing de respostas JSON ou XML.
6.1.1
HTTP GET
Para fazer uma requisio HTTP GET usaremos as classes da biblioteca Apache, tais como
HttpClient, HttpGet e HttpResponse. Primeiros crie uma classe que iremos chamar de RequestTask e ela deve extender a classe AsyncTask1 , ela vai permitir que faamos a requisio na thread da interface do usurio sem precisar criar e manipular uma thread diferente.
http://developer.android.com/reference/android/os/AsyncTask.html
71
72
1
Comunicao
@Override
protected String doInBackground(URI... uri) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = null;
3
4
5
6
7
8
try {
response = httpclient.execute(new HttpGet(uri[0]));
StatusLine statusLine = response.getStatusLine();
9
10
11
12
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
responseString = out.toString();
} else {
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return responseString;
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
http://developer.android.com/reference/java/net/URI.html
http://developer.android.com/reference/org/apache/http/StatusLine.html
Comunicao
73
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
6
7
8
9
try {
task = new RequestTask(this).execute(uri);
response = task.get();
} catch (Exception e) {
e.printStackTrace();
}
10
11
12
13
14
15
16
if(response != null){
WebView webview = new WebView(this);
setContentView(webview);
17
18
19
20
21
22
23
http://developer.android.com/reference/android/webkit/WebView.html
74
6.1.2
Comunicao
HTTP POST
try {
HttpPost post = new HttpPost(uri[0]);
List<NameValuePair> nvp = new ArrayList<NameValuePair>();
nvp.add(new BasicNameValuePair("testing", "Post"));
nvp.add(new BasicNameValuePair("user", "You"));
6
7
8
9
10
11
post.setEntity(new UrlEncodedFormEntity(nvp));
response = httpclient.execute(post);
...
...
}
6.1.3
Decodificando JSON
Vamos obter dados do objeto JSON retornado pelo exemplo anterior. Se voc observar a
string na tela, ir perceber os dados que foram enviado via POST dentro de um objeto JSON
chamado form. Queremos obter esses dados, para isso precisamos criar uma classe que ser
responsvel por obter especificamente esses dados do form.
http://developer.android.com/reference/org/apache/http/client/methods/HttpPost.html
http://developer.android.com/reference/org/apache/http/client/entity/UrlEncodedFormEntity.html
7
O que JSON: http://www.json.org/
6
6
1
Comunicao
75
3
4
5
try {
JSONObject jObj = new JSONObject(jsonstr);
JSONObject form = jObj.getJSONObject("form");
formData = form.getString("testing");
formData += "\n" + form.getString("user");
6
7
8
9
10
11
} catch (JSONException e) {
e.printStackTrace();
}
12
13
14
15
return formData;
16
17
18
6.1.4
Codificando JSON
1
2
3
4
5
6
7
8
9
10
76
6.2
Comunicao
Telefone
possvel fazer uma chamada telefnica, porm voc ter que usar o discador padro do
Android uma vez que ele no prov uma API pblica para fazer chamadas diretamente pelo
seu aplicativo. A nica forma atravs do interemediador ACTION_CALL. O Exemplo abaixo
mostra como fazer uma chamada usando esse intermediador.
1
2
3
4
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
6
7
8
@Override
public void onClick(View v) {
EditText tv = (EditText) findViewById(R.id.editNumber);
String phone = tv.getText().toString();
9
10
11
12
13
14
15
16
}
});
17
18
19
<uses-permission android:name="android.permission.CALL_PHONE"/>
http://developer.android.com/reference/android/telephony/TelephonyManager.html
Comunicao
6.3
77
O Android prov uma API pblica para mandar mensagens SMS, atravs da classe SMSManager9 . Assim como fazer ligaes, enviar SMS tambm precisa configurar a permisso
no Manifest.
<uses-permission android:name="android.permission.SEND_SMS"/>
Agora vamos criar um aplicativo simples que chama a classe SMSManager para enviar
uma mensagem para um nmero de telefone. Teremos duas EditText views para abrigar a
mensagem e o nmero, e um boto para enviar. Inicialmente crie um mtodo sendSMS().
1
2
3
4
5
6
7
8
9
10
http://developer.android.com/reference/android/telephony/SmsManager.html
78
1
2
3
4
Comunicao
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
6
7
8
@Override
public void onClick(View v) {
EditText editMsg = (EditText) findViewById(R.id.editMessage);
String message = editMsg.getText().toString();
EditText editPhone = (EditText) findViewById(R.id.editPhone);
String phone = editPhone.getText().toString();
9
10
11
12
13
14
15
sendSMS(message, phone);
16
17
18
19
20
21
22
23
}
});
24
25
26
C APTULO
7
Armazenamento
O Android prov algumas opes para que voc possa salvar dados persistentes de sua aplicao. A escolha da opo de armazenamento vai depender das necessidades da sua aplicao,
isto , se os dados vo ser visveis somente pela aplicao ou se o usurio ter acesso a eles,
quanto de espao ser necessario, que tipo de dados voc pretende salvar. As opes so:
Shared Preferences: Usada principalmente para salvar preferncias do usurio, esse mtodo guarda primitivas em duplas chave-valor;
Armazenamento Interno: Salva dados privados na memria do dispositivo;
Armazenamento Externo: Salva dados pblicos na memria externa compartilhada;
Banco de Dados SQLite: Salva dados estruturados em um banco de dados privado.
Conexo com a rede: Salva dados na web em seu prprio servidor na rede.
7.1
Shared Preferences:
http://developer.android.com/reference/android/content/SharedPreferences.html
79
80
Armazenamento
chamado para salvar os valores. Para ler os valores, voc deve chamar mtodos como getBoolean() ou getString().
O exemplo abaixo salva os dados de uma caixa de texto, uma barra de progresso e uma
chave em uma SharedPreferences e depois os l quando o aplicativo aberto novamente.
1
2
3
4
5
6
7
8
9
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
10
11
12
13
14
15
16
17
18
19
mEditText.setText(text);
mSeekBar.setProgress(progress);
mSwitch.setChecked(checked);
20
21
22
23
24
25
26
27
@Override
protected void onStop() {
super.onStop();
28
29
30
31
editor.putString("text", mEditText.getText().toString());
editor.putInt("seek", mSeekBar.getProgress());
editor.putBoolean("switch", mSwitch.isChecked());
editor.commit();
32
33
34
35
36
37
38
}
...
}
Armazenamento
81
7.2
Armazenamento interno
Voc pode salvar arquivos diretamente na memria interna do dispositivo. Por padro os
arquivos salvos no armazenamento interno so privados a seu aplicativo e no podem ser acessados por outros aplicativos.
Para criar um novo arquivo voc deve invocar o mtodo openFileOutput() passando o
nome do arquivo e o modo de operao. Esse mtodo ir retornar um FileOutputStream.
Voc poder escrever nesse arquivo chamando o mtodo FileOutputStream.write() e
FileOutputStream.close() para fechar o arquivo.
Para exemplificar, faremos um aplicativo do tipo bloco de notas. Ser composto de dois
botes, um para abrir um arquivo e outro para salvar um arquivo, e uma caixa de texto para
escrever. Tudo ser feito no mtodo onCreate(), primeiro usamos findViewById()
para obter as views. O boto de salvar ir abrir um alerta perguntando o nome do arquivo, e o
boto de abrir mostrar um alerta permitindo ao usurio escolher dentre os arquivos j salvos
anteriormente.
No cdigo abaixo criamos o listener do boto de salvar, dentro dele criamos um alerta e
precisamos de um listener para confirmar e um para cancelar.
1
saveBtn.setOnClickListener(new OnClickListener() {
2
3
4
@Override
public void onClick(View v) {
5
6
7
8
9
10
11
12
AlertDialog.Builder builder =
new AlertDialog.Builder(MainActivity.this);
LayoutInflater inflater = getLayoutInflater();
final View fnameEntry =
inflater.inflate(R.layout.save_dialog, null);
builder.setView(fnameEntry).setTitle("Save as...")
.setPositiveButton("Save", new DialogInterface.OnClickListener(){
13
14
...
82
Armazenamento
1
2
...
.setPositiveButton("Save", new DialogInterface.OnClickListener() {
3
4
5
6
7
8
9
10
@Override
public void onClick(DialogInterface dialog, int which) {
EditText fnameEt = (EditText)fnameEntry.findViewById(R.id.saveas);
String fname = fnameEt.getText().toString();
if(fname.isEmpty())
fname = "untitled";
String text = textEt.getText().toString();
11
12
13
14
15
16
17
18
19
20
try {
FileOutputStream fos = openFileOutput(fname, MODE_PRIVATE);
fos.write(text.getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
21
22
23
24
25
26
Toast.makeText(getApplicationContext(),
fname + " saved", Toast.LENGTH_SHORT).show();
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
...
7
1
2
Armazenamento
83
...
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
3
4
5
6
7
8
9
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
...
openBtn.setOnClickListener(new OnClickListener() {
2
3
4
@Override
public void onClick(View v) {
AlertDialog.Builder builder =
new AlertDialog.Builder(MainActivity.this);
6
7
8
builder.setTitle("Choose a File")
.setItems(fileList(), new DialogInterface.OnClickListener() {
9
10
11
...
12
});
13
14
builder.create().show();
15
16
17
}
});
Dessa vez usamos o mtodo builder.setItems() para construir uma lista no alerta.
O mtodo fileList() retorna um array de nomes de arquivo que foram armazenados
internalmente no aplicativo.
84
1
2
Armazenamento
...
.setItems(fileList(), new DialogInterface.OnClickListener() {
3
4
5
@Override
public void onClick(DialogInterface dialog, int which) {
try {
File f = getFilesDir().listFiles()[which];
BufferedReader in = new BufferedReader(new FileReader(f));
StringBuilder text = new StringBuilder();
7
8
9
10
11
try{
String line = null;
while ((line = in.readLine()) != null){
text.append(line);
text.append(System.getProperty("line.separator"));
}
} finally {
in.close();
}
12
13
14
15
16
17
18
19
20
21
textEt.setText(text);
in.close();
} catch(FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
22
23
24
25
26
27
28
29
30
31
}
});
...
Armazenamento
7.3
85
Armazenamento Externo
4
5
6
7
8
9
10
11
12
if (Environment.MEDIA_MOUNTED.equals(state)) {
mExternalStorageAvailable = mExternalStorageWriteable = true;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
mExternalStorageAvailable = mExternalStorageWriteable = false;
}
http://developer.android.com/guide/topics/data/data-storage.html#filesExternal
86
Armazenamento
mtodo recebe um parmetro que especifica o tipo de subdiretrio que voc quer usar, tais como
DIRECTORY_MUSIC e DIRECTORY_RINGTONES, ou passe null para obter a raz dos diretrios da sua aplicao. O mtodo ir criar o diretrio apropriado se necessrio. Ao especificar
o tipo, voc se assegura que o Android ir categorizar seus arquivos de forma apropriada. Se o
usurio desinstalar seu aplicativo, todos os dados sero deletados.
Se voc quer salvar arquivos que no so especficos da sua aplicao e que no devem ser
deletados quando desinstalado, salve-os em um dos diretrios pblicos que esto no raz da
mdia de armazenamento externo. So eles os diretrios Music/, Pictures/, etc. Use o
mtodo getExternalStoragePublicDirectory() passando o tipo de diretrio desejado, da mesma forma que anteriormente.
O sistema classifica os arquivos encontrados nessas pastas na forma:
7.4
Banco de dados
O Android fornece suporte ao bancos de dados SQLite. Qualquer banco que voc criar
ser acessvel apenas pela sua aplicao e no fora dela.
A maneira recomendada de criar um banco de dados criando uma subclasse da classe
SQLiteOpenHelper e sobrescrever o mtodo onCreate(). Para ler e escrever no banco,
chame os mtodos getReadableDatabase() e getWritableDatabase(). Ambas
retornam um objeto do tipo SQLiteDatabase que fornece mtodos para operar sobre o
banco.
Usando o mtodo SQLiteDatabase.query() podemos realizar uma consulta, o mtodo aceita vrios parmetros, tais como: tabela, seleo, colunas, agrupamento e etc. Para
consultas mais complexas voc pode usar a classe SQLiteQueryBuilder que contm vrios mtodos para construir consultas.
Toda consulta vai retornar um Cursor que aponta para as tuplas do resultado da consulta.
Voc dever us-lo para navegar atravs dos resultados.
Para exemplificar, vamos fazer um mecanismo simples de busca. O banco ser populado
com fabricantes de carros e alguns de seus modelos. Para o design desse exemplo, optei por
ter dois Spinners (equivalente ao Combo Box) e um boto. Os Spinners sero populados com
os dados do Banco de Dados de forma que o primeiro contenha todos os fabricantes de carros
e o segundo todos os anos de fabricao de seus modelos, esses dados sero obtidos atravs de
consultas ao banco.
Para comear, devemos criar o BD e isso feito com uma classe que iremos criar que ir ser
subclasse de SQLiteOpenHelper 3 . Chamaremos de CarOpenHelper. Essa classe tem
algumas funes bsicas, como criar e popular o BD, configurar a ao a ser tomada quando o
BD atualizado ou desatualizado.
3
http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html
Armazenamento
87
11
12
13
14
15
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_TABLE_CREATE);
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
88
Armazenamento
com a segunda consulta, que adiciona as tuplas ao banco, s uma maneira de inserir vrias
tuplas em uma nica consulta.
Agora na nossa activity precisamos realizar as consultas para popular os Spinners. No mtodo onCreate() faa:
1
2
3
@Override
protected void onCreate(Bundle savedInstanceBundle){
...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ArrayAdapter<String> manuAdapter =
new ArrayAdapter<String>
(this, android.R.layout.simple_spinner_item, list1);
manuAdapter.
setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
mSpManufacturer.setAdapter(manuAdapter);
28
29
30
31
32
33
34
35
ArrayAdapter<String> yearAdapter =
new ArrayAdapter<String>
(this, android.R.layout.simple_spinner_item, list2);
manuAdapter.
setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
mSpYear.setAdapter(yearAdapter);
Estou "pulando"a parte de obter as referncias dos spinners e botes e partindo para o que
interessa no cdigo 7.9. Na linha 5 instanciamos o CarOpenHelper na varivel mDatabase. Na linha 6 criamos um array que contm as colunas que iremos fazer consulta, isto
necessrio para o mtodo query() na linha 10.
Ao chamar mDatabase.getReadableDatabase() obtemos um objeto do tipo SQ-
Armazenamento
89
1
2
3
4
5
6
7
Esse mtodo responsvel por obter a lista de carros da seleo feita nos Spinners e mandar
essa lista para outra activity. O mtodo fetchCarList() que ir fazer a chamada ao BD,
da mesma forma que foi feito anteriormente, mas dessa vez estamos obtendo a coluna Model
do banco com WHERE sendo os parmetros obtidos.
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
90
1
2
3
4
5
6
7
Armazenamento
8
9
10
11
12
13
14
15
return list1;
}
C APTULO
8
Cmera
O Android fornece um framework para acesso s diferentes cmeras e funcionalidades dessas cmeras disponveis no dispositivo. possvel tirar fotos e gravar vdeos nos aplicativos.
H duas formas de acessar a cmera, a primeira sendo pela API e a segunda pelo Intent da
cmera. Nesse captulo iremos discutir brevemente sobre como usar a API e um exemplo de
chamar o aplicativo padro da cmera atravs de um Intent.
8.1
Usando a API
Para usar a API da cmera, primeiro devemos requisitar a permisso para usar a cmera no
Manifest.
1
2
3
<uses-permission android:name=
"android.permission.WRITE_EXTERNAL_STORAGE" />
http://developer.android.com/guide/topics/manifest/uses-feature-element.html#hw-features
91
92
Cmera
Se for gravar udio quando estiver gravando vdeo, precisa requisitar a permisso para gravar
udio:
Segundo a documentao2 existem alguns passos gerais que so seguidos para criar um
aplicao usando a API da cmera. So eles:
Detectar e acessar a cmera: Cdigo que verifica a existncia de uma cmera e requisita
o acesso.
Criar uma classe de pr-visualizao: Criar uma classe que extende SurfaceView e
implementa SurfaceHolder para mostrar na tela o que a cmera est vendo.
Construir o layout da pr-visualizao: Com a classe pronta, crie uma view que ir
incorporar a classe de pr-visualizao e mostrar os controles da interface.
Configurar os listeners para a captura: Criar listeners para os botes da interface para
gravar a imagem.
Liberar a cmera: Depois de usar a cmera, a aplicao deve liberar o uso para outras
aplicaes.
8.1.1
Acessando a cmera
Primeiro vamos criar uma classe CameraAccess que ir requisitar o acesso cmera.
A classe ficar responsvel apenas por verificar se o dispositivo tem cmera e por instanciar a
cmera para o uso.
http://developer.android.com/guide/topics/media/camera.html
8
1
2
3
Cmera
93
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
return cam;
29
30
31
32
33
34
35
8.1.2
Pr-visualizao
Em seguida iremos criar a classe da visualizao da cmera. Essa classe extende SurfaceView e implementa a interface SurfaceHolder.CallBack, iremos chamar essa classe
de CameraPreview. No cdigo 8.5 abaixo comeamos a implementar essa classe. Precisamos de duas variveis SurfaceHolder e Camera. O construtor recebe o contexto e
a cmera previamente instanciada como parmetro. Obtemos o SurfaceHolder usando o
mtodo getHolder(), adicionamos a classe como callback. Por ltimo, na linha 11 configuramos o tipo do SurfaceHolder como SURFACE_TYPE_PUSH_BUFFERS isso j
depredado mas necessrio para acessar a cmera em verses do Android mais antigas que 3.0.
94
1
2
3
Cmera
5
6
7
8
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
9
10
11
12
13
@Override
public void surfaceCreated(SurfaceHolder holder) {
try{
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("CAM", "Error setting camera preview: " + e.getMessage());
}
}
14
15
16
17
18
19
20
21
22
23
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
if(mHolder.getSurface() == null){
return;
}
24
25
26
27
28
29
30
try {
mCamera.stopPreview();
} catch (Exception e) {
// Irrelevante
}
31
32
33
34
35
36
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d("CAM", "Error setting camera preview: " + e.getMessage());
}
37
38
39
40
41
42
43
44
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Nada, tomar conta de liberar a camera na activity
}
45
46
47
48
49
Cmera
95
1
2
3
4
5
6
7
8
9
10
11
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1" />
12
13
14
15
16
17
18
19
<Button
android:id="@+id/button_capture"
android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
Voc deve tambm especificar a orientao da activity como landscape no Manifest. Como
mostrado na linha 5 do cdigo 8.7. Apesar disso no ser obrigatrio, normal que tiremos fotos
no modo paisagem e no retrato, mas isso no regra.
96
1
2
3
4
5
6
Cmera
...
<activity
android:name="com.example.camera1.MainActivity"
android:label="@string/app_name"
android:screenOrientation="landscape" >
...
8.1.4
Criando a activity
Para comear vamos apenas fazer com que a activity mostre a visualizao da cmera na
tela usando as classes que criamos anteriormente.
1
2
3
4
5
6
7
8
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
10
11
12
13
14
15
16
Cmera
8.1.5
97
Agora voc est pronto para capturar e salvar as fotos em sua aplicao. Para isso voc deve
definir listeners para o boto da sua interface que ir responder tirando uma foto.
Para capturar uma foto, voc deve usar o mtodo Camera.takePicture(). Para receber os dados no format JPEG voc deve implementar um Camera.PictureCallback que
recebe os dados da imagem e os escrevem em um arquivo. Observe a implementao da interface PictureCallback no cdigo abaixo, que pode ser escrito no mtodo onCreate()
da activity.
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File picFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if(picFile == null){
Log.d("ERROR",
"Error creating media file, check storage permissions");
return;
}
3
4
5
6
7
8
9
10
11
try {
FileOutputStream fos = new FileOutputStream(picFile);
fos.write(data);
fos.close();
} catch(FileNotFoundException e) {
Log.d("ERROR", "File not found: " + e.getMessage());
} catch (IOException e){
Log.d("ERROR", "Error accessing file: " + e.getMessage());
}
12
13
14
15
16
17
18
19
20
21
22
};
Para simplificar, todo cdigo que efetivamente cria a imagem em um arquivo ficou no mtodo getOutputMediaFile() que pode ser observado abaixo.
98
1
2
3
Cmera
4
5
6
7
File mediaStorageDir =
new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), folder);
8
9
10
11
12
13
14
15
16
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("ERROR", "failed to create directory: " + folder);
return null;
}
}
String timeStamp =
new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
17
18
19
20
21
22
23
24
25
26
27
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
28
return mediaFile;
29
30
Cmera
99
1
2
3
4
5
6
7
8
@Override
public void onClick(View v) {
mCam.takePicture(null, null, mJPEGCallback);
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
mCam.setParameters(params);
Voc consegue configurar os parmetros da cmera, neste caso usaremos para melhorar a
qualidade da foto. Para isso comece chamando getParameters() e guarde essa referncia
num objeto Parameters. Com setJpegQuality() conseguimos configurar a qualidade
da compresso JPEG entre 0 e 100, sendo 100 o melhor. Em seguida iteraremos sob uma lista
de resolues suportadas e escolhemos a maior resoluo. Dessa forma a foto ter a maior resoluo e com a melhor qualidade de compresso. Para finalizar, chame setParameters()
e os parmetros sero gravados.
3
http://developer.android.com/intl/es/reference/android/hardware/Camera.html
100
8.2
Cmera
Gravando vdeos
Agora voc j tem um aplicativo que tira fotos, mas tambm quer gravar vdeos. Para isso,
algumas modificaes sero necessrias, assim como algumas adies. Para capturar videos,
necessrio um controle cauteloso do objeto Camera em coordenao com a classe MediaRecorder4 . Diferente de tirar fotos, gravar vdeos requer chamadas mtodos em uma ordem
particular. Voc deve seguir essa ordem para preparar a aplicao e capturar o video.
Os trs primeiros passos so: 1) Abrir a cmera, 2) Criar uma visualizao e 3) Visualizar a
cmera, j foram feitos na seo anterior. Para comear a gravar o vdeo so necessrios mais
alguns passos:
8.2.1
Preparar a gravao
recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
6
7
8
CamcorderProfile profile =
CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
recorder.setProfile(profile);
9
10
11
12
recorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
recorder.setPreviewDisplay(mPreview.getHolder().getSurface());
13
14
15
try{
recorder.prepare();
} catch (IllegalStateException e){
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
16
17
18
19
20
21
22
23
24
25
return true;
26
27
http://developer.android.com/intl/es/reference/android/media/MediaRecorder.html
Cmera
101
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
9
@Override
protected void onPause() {
super.onPause();
releaseMediaRecorder();
if(mCam != null){
mCam.release();
mCam = null;
}
}
Por ltimo, configurar um listener para o boto de gravar vdeo, como mostrado no algoritmo 8.16 abaixo.
102
1
2
Cmera
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public void onClick(View v) {
if(isRecording){
recorder.stop();
releaseMediaRecorder();
((Button) v).setText("Record");
isRecording = false;
} else {
if(prepareForRecording()) {
recorder.start();
((Button) v).setText("Stop");
isRecording = true;
} else {
releaseMediaRecorder();
}
}
}
});
8.3
Usando um Intent
A maneira mais fcil de tirar uma simples foto na verdade chamando um Intent que se
encarregar de abrir a activity da cmera e retornar a foto tirada.
Cmera
103
1
2
3
4
private
private
private
private
5
6
7
8
@Override
public void onCreate(Bundle savedInstanceState) {
...
10
11
fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
12
13
14
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
15
16
Primeiro cria-se um novo Intent com parmetro MediaStore.ACTION_IMAGE_CAPTURE que configura uma activity com cmera. Depois usamos o mtodo getOutputMediaFileUri() que apenas faz uma chamada ao mtodo getOutputMediaFile()
(algoritmo 8.10) que usamos na seo anterior porm retornando uma Uri, que o caminho do
arquivo. Colocamos como extra no Intent o caminho retornado em fileUri, nesse caso
MediaStore.EXTRA_OUTPUT apenas uma conveno para ficar claro que o valor passado
no extra para ser usado na activity de cmera para salvar o arquivo. Por fim chamamos startActivityForResult(), que recebe o Intent e um cdigo que indica uma activity que
captura imagens.
1
2
3
8.3.2
Quando voc chama startActivityForResult() significa que voc espera uma resposta da activity que chamou. Essa resposta ser obtida no mtodo onActivityResult()
que voc precisa escrever para manipular esses dados da resposta. O algoritmo 8.19 exemplifica
esse mtodo, que trata a resposta da cmera, isto , se foi possvel capturar a foto ou gravar o
vdeo.
104
1
2
Cmera
3
4
5
6
@Override
protected void onActivityResult
(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Toast.makeText(this, "Image saved to:\n" +
fileUri.toString(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
// Opcional
} else {
Toast.makeText(this, "Error capturing image...",
Toast.LENGTH_LONG).show();
}
}
8
9
10
11
12
13
14
15
16
17
18
19
if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Toast.makeText(this, "Video saved to:\n" +
fileUri.toString(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
// Opcional
} else {
Toast.makeText(this, "Error recording video...",
Toast.LENGTH_LONG).show();
}
}
20
21
22
23
24
25
26
27
28
29
30
31
A lgica est apenas em verificar o retorno da activity e mostrar uma mensagem ao usurio,
o informando do caminho em que foi salvo a imagem ou vdeo.
Dica: Quando voc passa uma Uri para a activity de cmera, o retorno dela na varivel
data ser sempre null. Voc pode, entretando, no especificar uma Uri e usar o campo
data para criar um Bitmap.
8
1
2
3
Cmera
105
@Override
public void onCreate(Bundle savedInstanceState) {
...
5
6
fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
7
8
9
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
10
11
startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
12
13
106
Cmera
C APTULO
9
udio
9.1
Gravar udio uma tarefa muito semelhante a gravar vdeos no Android. Usaremos a mesma
classe: MediaRecorder, para configurar e gravar udio do microfone do aparelho. Para tocar
udio veremos uma nova classe chamada MediaPlayer.
Para este exemplo criaremos um aplicativo simples com 2 botes, um para gravar e um para
tocar a gravao. A fim de simplificar, toda gravao ser feita em apenas um arquivo, logo
sempre que gravar algo novo estar sobreescrevendo a gravao antiga. Entretanto, voc pode
modificar o mtodo getOutputMediaFile() (algoritmo 8.10) que criamos no captulo
anterior para gravar em diferentes arquivos.
Iniciaremos criando uma funo que chamaremos de prepareRecording(), similar
aquela que fizemos para no captulo de vdeo.
1
2
3
4
5
6
try{
recorder.prepare();
} catch (IOException e) {
Log.e("AudioRecorder", "prepareRecording() failed");
return false;
}
return true;
8
9
10
11
12
13
14
15
108
udio
Assim como fizemos no captulo anterior, a preparao precisa seguir passos determinados.
Primeiro precisamos configurar a fonte com setAudioSource(), nesse caso passamos o
MIC, o microfone do aparelho. O segundo passo configurar o formato da sada com setOutputFormat(), nesse exemplo optei pelo formato 3gp. O terceiro passo determinar
o arquivo de sada com setOutputFile() e para esse mtodo passamos uma string que
chamei de testFilename, o valor de testFilename neste exemplo o caminho do armazenamento externo mais o nome do arquivo. Depois, setAudioEncoder() para selecionar a codificao do udio. Por ltimo chame o mtodo prepare() para consolidar as
configuraes.
Tambm faa uma funo releaseRecorder() para liberar o gravador quando terminar
a gravao.
1
2
3
4
mRecordButton.setOnClickListener(new OnClickListener() {
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public void onClick(View v) {
if(isRecording){
recorder.stop();
releaseRecorder();
mRecordButton.setText("Record");
isRecording = false;
} else {
if(prepareRecording()){
recorder.start();
mRecordButton.setText("Stop");
isRecording = true;
} else {
releaseRecorder();
}
}
}
});
udio
109
boto ento chamamos stop() para parar a gravao, trocamos o texto do boto e atribumos
isRecording como falso, pois estamos parando de gravar. Caso contrrio, ou seja, queremos
gravar, ento chamamos start() para iniciar a gravao, ento mudamos o texto e atribumos
verdadeiro para isRecording. Se a preparao falhar chamamos releaseRecorder()
para liberar o microfone.
Para o tocador, iremos usar a classe MediaPlayer, iniciaremos criando um mtodo startPlaying() responsvel por instanciar um MediaPlayer e configur-lo.
1
2
player.setOnCompletionListener(new OnCompletionListener() {
4
5
@Override
public void onCompletion(MediaPlayer mp) {
mPlayButton.setText("Play");
stopPlaying();
isPlaying = false;
}
});
6
7
8
9
10
11
12
13
try{
player.setDataSource(testFilename);
player.prepare();
player.start();
} catch (IOException e){
Log.e("AudioRecorder", "file not found");
}
14
15
16
17
18
19
20
21
110
udio
Por fim, basta configurar o listener do boto de tocar udio, como mostrado no algoritmo
abaixo:
1
mPlayButton.setOnClickListener(new OnClickListener() {
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public void onClick(View v) {
if(isPlaying){
stopPlaying();
isPlaying = false;
mPlayButton.setText("Play");
} else {
startPlaying();
isPlaying = true;
mPlayButton.setText("Stop");
}
}
});
testFilename =
Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/audiorecordtest.3gp";
C APTULO
10
Localizao e Mapas
O Google j tem uma extensa documentao que nos ensina como acessar a API do Google
Maps no seu aplicativo. Porm, muitas vezes ela pode confusa e voc sente que faltam informaes um pouco mais claras. Nesse captulo iremos abordar tanto o acesso a localizao do
dispositivo usando LocationManager e colocar essas informaes no Google Maps.
J existe uma nova API que utiliza o Google Play Services, a documentao oficial pode ser
vista aqui1
10.1
Acessando a localizao
Antes de iniciar, voc precisa definir se quer obter a localizao usando GPS (Global Positioning System) ou usando a Internet. Caso opte por usar o GPS, deve-se atentar ao fato que o
GPS demora muito para inicializar e obter as coordenadas. Enquanto que usando a Internet isso
praticamente instantneo, porm a localizao no to precisa. Ou seja, se quer rapidez use
a Internet como seu Location Provider, se quer preciso use o GPS.
Sabendo disso ento voc deve colocar as permisses no Manifest, mostradas abaixo.
1
2
3
4
5
https://developer.android.com/google/play-services/location.html
111
112
1
2
3
10
Localizao e Mapas
@Override
public void onLocationChanged(Location location) {
c_lat = location.getLatitude();
c_long = location.getLongitude();
}
5
6
7
8
9
10
@Override
public void onProviderDisabled(String provider) {
Toast.makeText(getApplicationContext(),
provider + " provider disabled", Toast.LENGTH_SHORT).show();
}
11
12
13
14
15
16
@Override
public void onProviderEnabled(String provider) {
Toast.makeText(getApplicationContext(),
provider + " provider enabled", Toast.LENGTH_SHORT).show();
}
17
18
19
20
21
22
@Override
public void onStatusChanged
(String provider, int status, Bundle extras) {
}
23
24
25
26
27
...
28
29
10
1
2
3
4
5
Localizao e Mapas
113
LocationManager mlocManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
MyLocationListener mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates
(LocationManager.GPS_PROVIDER, 1000, 0, mlocListener);
A referncia ao LocationManager deve ser obtida com o mtodo getSystemService().Criamos uma nova instncia da classe MyLocationListener que criamos anteriormente. Depois deve-se registrar o listener para receber atualizaes usando requestLocationUpdates(). Os parmetros so: o provedor que ser usado, o intervalo mnimo
entre atualizaes (em milissegundos), a distncia mnima entre atualizaes (em metros) e
o listener. Nesse exemplo, estamos usando o GPS, caso queira usar a Internet, deve-se usar
LocationManager.NETWORK_PROVIDER.
10.2
Google Maps
Configurar o Google Maps para uso trabalhoso. Voc deve registrar sua aplicao para
obter uma chave que d permisso ao seu aplicativo para usar o Maps. Nessa seo faremos o
passo a passo de como obter a chave e colocar um mapa na sua activity.
Antes de iniciar, quero deixar claro que o Google Maps no funciona no emulador Android.
Isso devido a utilizao do Google Play Services que no est disponvel nos emuladores (at
essa data). Existe sim a possibilidade de instalar o Play Services nos emuladores, mas isso no
est previsto pelo Google e pode no funcionar corretamente.
10.2.1
Para poder testar o Maps nos aplicativos que est desenvolvendo voc deve obter uma chave
de certificao debug. Na verdade toda aplicao ao ser lanada na Play Store precisa estar
assinada digitalmente usando uma chave release que pode ser obtida da mesma maneira.2
Caso esteja usando o Eclipse, a chave de certificao debug pode ser obtida no menu Window
> Preferences > Android > Build, sob o campo SHA-1 fingerprint.
Voc tambm pode adquir-la pela linha de comando, usando o software keytool que vem
junto do JDK. Voc ir precisar apontar para o arquivo debug.keystore que est na pasta
.android do seu sistema. Basta executar o keytool com o seguinte comando.
keytool -list -v -keystore ".android/debug.keystore" -alias androiddebugkey -storepass android -keypass android
10.2.2
Com a chave de certificao debug em mos, voc deve acessar o Google API Console e
criar um novo projeto. Aps criar o projeto, acesse API no menu esquerda e marque Google
Maps Android API v2 com status ON. Como mostrado na figura abaixo:
2
http://developer.android.com/intl/es/tools/publishing/app-signing.html
114
10
Localizao e Mapas
10
Localizao e Mapas
115
Agora, com o cdigo em mos, voc deve abrir seu Manifest e adicionar a seguinte linha
dentro da tag <application>. Onde value a key adquirida.
1
2
3
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="AaaaBbB1cCcCCDDDd22eee-ffFFFgGg3HHhh4i5" />
10.2.3
Primeiro, voc deve fazer download do Google Play Services no SDK Manager. Aps
o trmino do download necessrio importar a biblioteca no Eclipse e referenci-la em seu
projeto.
A pasta com a biblioteca do Google Play Services se encontrar na pasta sdk/extras/google/google_play_services/libproject/ e se chama google-play-services_lib. necessrio importar essa pasta como projeto existente no Eclipse, no se esquea de
marcar a opo para copiar o projeto para o seu workspace.
Depois de importar, voc deve abrir as propriedades do seu projeto e selecionar Android
no menu esquerda. Na parte inferior onde est escrito Library clique em Add... e selecione
o google-play-services_lib. Se aparecer um smbolo verde de "correto", ento deu
certo.
116
10
Localizao e Mapas
10.2.4
O Google Maps no Android usa OpenGL ES verso 2 para renderizar o mapa, logo necessrio adicionar o uso do OpenGL no Manifest.
1
2
3
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.MapFragment"/>
10
1
2
3
4
5
Localizao e Mapas
117
6
7
8
9
10
private
private
private
private
11
12
13
14
15
16
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
17
LocationManager mlocManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
MyLocationListener mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates
(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
18
19
20
21
22
23
24
25
26
27
28
29
30
if (mMapFragment == null) {
mMapFragment = SupportMapFragment.newInstance();
31
32
33
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.add
(R.id.mapFrame, mMapFragment, MAP_FRAGMENT_TAG);
fragmentTransaction.commit();
34
35
36
37
38
39
40
setUpMapIfNeeded();
41
42
118
10
Localizao e Mapas
if (mMap != null)
marker = mMap.addMarker
(new MarkerOptions().position(new LatLng(0,0)));
5
6
7
8
9
@Override
public void onLocationChanged(Location location) {
c_lat = location.getLatitude();
c_long = location.getLongitude();
mLocation = new LatLng(c_lat, c_long);
7
8
9
marker.remove();
marker = mMap.addMarker
(new MarkerOptions().position(mLocation).title("You are here"));
mMap.moveCamera
(CameraUpdateFactory.newLatLngZoom(mLocation, 14.0f));
10
11
12
13
14
15
C APTULO
11
Compartilhamento
J aprendemos a enviar dados outras activities usando a classe Intent. Agora veremos como faz para enviar esses dados e dar ao usurio a opo de escolher qual aplicativo j
instalado no dispositivo ele quer usar para receber esses dados. Isso pode ser visto como compartilhamento. Imagine que voc tirou uma foto e quer mostrar ao seus amigos pelo Facebook.
Na verdade est enviando uma foto activity do Facebook que recebe esse tipo de dado e assim
ela tomar o controle.
Quando voc construir um Intent voc deve especificar a ao que voc espera que ele
acione. O Android j define vrios tipos de aes e entre eles est o ACTION_SEND que indica
que o intent est enviando dados de uma activity para outra.
Se voc quer enviar apenas um texto, por exemplo, basta seguir o pequeno exemplo abaixo:
1
2
3
4
5
Contanto que exista um aplicativo instalado no aparelho com um filtro que aceite ACTION_SEND e o tipo MIME "text/plain" o Android ir execut-lo, caso exista mais de um
ento um alerta aparecer perguntando qual aplicativo o usurio deseja escolher para receber o
Intent.
119
120
1
11
Compartilhamento
Voc pode usar alguns extras padres nos Intent, tais como: EXTRA_EMAIL para o
texto ser o corpo do e-mail, EXTRA_SUBJECT para o texto ser o assunto do e-mail. Porm
o aplicativo que estiver recebendo o Intent deve estar preparado para esse tipo de extra, se
no nada vai acontecer. Existe ainda a opo de criar extras personalizados, mas tambm s
ir funcionar caso o aplicativo esteja projetado para esse tipo de extra. Nesse caso comum
criar um extra personalizado caso voc tenha feito um conjunto de aplicativos que podem trocar
informaes atravs de Intents e que iro usar esse extra.
Alm de texto possvel enviar dados binrios ou at mesmo mais de um dado ao enviar
uma lista. Para enviar uma foto que voc tirou com a cmera, por exemplo, voc deve usar o
extra chamado EXTRA_STREAM e configurar o tipo do Intent para "image/jpeg".
Uma forma mais completa de enviar imagems ou outros tipos de dados usando um ContentProvider1 que ir criar uma interface para a prover os dados a outras aplicaes.
Outra parte importante do compartilhamento fazer com que sua aplicao consiga receber
dados de Intents. O primeiro passo para isso configurar os intent-filter no Manifest. Quando voc define um intent-filter voc est dizendo para o Android que uma
determinada activity capaz de receber um determinado de Intent. Uma activity pode ter
mltiplos filtros, cada um relacionado a um determinado tipo de dado.
Para exemplificar o conceito, iremos fazer um aplicativo que escreve um texto e tira uma
foto e um aplicativo que recebe um texto ou uma imagem e mostra o que foi recebido. O
aplicativo usa conceitos j conhecidos ento iremos nos limitar a explicar somente a parte do
compartilhamento. Entretanto, caso haja dvidas possivel obter ambos aplicativos do repositrio.
No primeiro aplicativo, interessante salientar apenas os botes que adicionei para compartilhar. Um tem a funo de compartilhar o texto e outro a imagem. Voc pode, por exemplo
compartilhar um e depois o outro no aplicativo do Gmail que ambos iro ser adicionados ao
corpo do e-mail.
Observe no cdigo abaixo, como ficaram os botes de compartilhamento.
http://developer.android.com/intl/es/reference/android/content/ContentProvider.html
11
1
2
Compartilhamento
121
3
4
shareText.setOnClickListener(new OnClickListener() {
5
6
7
8
9
10
11
12
13
@Override
public void onClick(View v) {
String text = textField.getText().toString();
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, text);
startActivity(Intent.createChooser(shareIntent, "Send to..."));
}
});
14
15
sharePic.setOnClickListener(new OnClickListener() {
16
17
18
19
20
21
22
23
@Override
public void onClick(View v) {
shareIntent.setType("image/png");
shareIntent.putExtra(Intent.EXTRA_STREAM, picUri);
startActivity(Intent.createChooser(shareIntent, "Send to..."));
}
});
A parte mais importante o mtodo setType, ele recebe um MIME Type2 , como o caso
de text/plain e image/png. Outros MIME Types poderiam ser usados como image/*
caso no soubssemos o formato da imagem ou at mesmo */* que representa qualquer tipo
de dado. O problema disso que todos aplicativos iro aparecer na lista e alguns podem no
receber o que voc est tentando enviar! Portanto, seja cauteloso.
J o segundo aplicativo ir receber tanto um texto como uma foto e mostrar ao usurio, apenas para exemplificar o recebimento de Intents. O primeiro passo criar os intent-filter
para receber os MIME Type corretos.
MIME: http://en.wikipedia.org/wiki/MIME
122
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
11
Compartilhamento
<activity
android:name="br.ufscar.dc.mobile.receivecontent.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
11
Compartilhamento
123
Intent e coloc-los nas suas views e portanto no o cdigo completo da activity. Basicamente o que fazemos comparar as strings recebidas no Intent para saber o que est sendo
recebido. Ao verificar o action, sabemos que o Intent veio atravs de compartilhamento e ao
analisar o type, sabemos o MIME type e podemos construir a activity de acordo.
Dica: Modifique a activity para salvar a imagem ou o texto no caso do usurio voltar
para compartilhar outra coisa. Voc pode salvar os dados no Bundle.
Esse captulo tentou apenas para dar uma introduo ao compartilhamento de dados entre
aplicativos. Outras coisas interessantes podem ser feitas, por exemplo adicionar o boto de
Easy Share como descrito nessa pgina3 da documentao. Alm disso, existe tambm a classe
ContentProvider que fornece uma interface para compartilhamento.
http://developer.android.com/intl/es/training/sharing/shareaction.html
124
11
Compartilhamento
C APTULO
12
Agenda e Contatos
12.1
O Android contm um repositrio central onde esto armazenadas as informaes dos contatos do usurio, incluindo os dados de redes sociais. Esse repositrio se chama Contacts Provider1 .
Seguindo as lies da documentao oficial, iremos criar uma pequena aplicao que obtm
todos seus contatos e popula uma lista com eles. Mais detalhes do contato podero ser obtidos
ao se clicar no contato. O primeiro passo, sempre obrigatrio para se acessar o repositrio de
contatos, adicionar permisso no Manifest. Demonstrado no trecho abaixo:
1
http://developer.android.com/guide/topics/providers/contacts-provider.html
http://developer.android.com/reference/android/provider/ContactsContract.html
125
126
1
2
12
Agenda e Contatos
Como pode ser observado no cdigo 12.2 estamos extendendo a classe FragmentActivity3 que nos permite usar o Loader em Android mais antigos. Alm disso estamos
implementando as interfaces LoaderManager.LoaderCallbacks4 que permite o carregamento de dados de forma assncrona. Estamos implementando tambm a interface OnItemClickListener5 para que possamos carregar mais informaes do contato quando este
clicado na lista.
Precisamos de algumas variveis para auxiliar na seleo dos contatos e na criao do adaptador da lista. A varivel FROM_COLUMNS, abaixo, so os dados que sero mostrados e que
nesse caso apenas o nome do contato. Observe que estamos fazendo uma pequena comparao da verso do SDK pois a partir da verso 3.0 do SDK, a classe Contacts foi alterada. J a
varivel TO_IDS serve para o adaptador saber onde colocar a informao, passamos para ele o
id do TextView que colocamos no XML. Como essa lio se baseia na lio da documentao
oficial, estamos usando um dos ids padres do Android.
1
2
3
4
5
@SuppressLint("InlinedApi")
private final static String[] FROM_COLUMNS =
{Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME };
private final static int[] TO_IDS = {android.R.id.text1};
As prximas variveis so aquelas da seleo dos contatos. Nesse exemplo vamos obter
todos os contatos e portanto deixar a varivel mSearchString vazia, mas caso queira obter
contatos especficos, basta fazer algo que preencha essa varivel. Temos a varivel SELECTION que funciona como a parte WHERE de uma consulta SQL, ela j est preparada para
a busca por algum nome, caso queira. A varivel PROJECTION uma constante que define
as colunas que voc quer retornar das consultas, nesse caso queremos 3: o id do contato, sua
chave de busca (lookup key) e o seu nome. Por fim, as variveis CONTACT_ID_INDEX e
LOOKUP_KEY_INDEX funcionam como ponteiros para o Cursor que ir se mover nos resultados da pesquisa, basta definir o valor da varivel como sendo a posio da coluna na projeo.
Como temos a coluna id sendo a primeira e a lookup sendo a segunda, colocamos os valores 0 e
1, respectivamente. Isso necessrio para se obter dados de uma coluna individual do Cursor.
3
http://developer.android.com/reference/android/support/v4/app/FragmentActivity.html
http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html
5
http://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener.html
4
12
1
2
3
4
5
6
7
8
9
Agenda e Contatos
127
@SuppressLint("InlinedApi")
private final static String[] PROJECTION = {
Contacts._ID,
Contacts.LOOKUP_KEY,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME,
};
private static final int CONTACT_ID_INDEX = 0;
private static final int LOOKUP_KEY_INDEX = 1;
10
11
12
13
14
15
@SuppressLint("InlinedApi")
private static final String SELECTION =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" :
Contacts.DISPLAY_NAME + " LIKE ?";
16
17
18
1
2
3
4
5
private
private
private
private
private
ListView mContactList;
long mContactId;
String mContactKey;
Uri mContactUri;
SimpleCursorAdapter mCursorAdapter;
Depois, precisamos implementar o mtodo onCreate(). Nesse mtodo, iremos configurar o adaptador da lista que ser um SimpleCursorAdapter6 . Esse adaptador liga os
resultados da busca com a ListView.
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
128
1
2
3
12
Agenda e Contatos
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
mSelectionArgs[0] = "%" + mSearchString + "%";
return new CursorLoader(
getActivity(),
Contacts.CONTENT_URI,
PROJECTION,
SELECTION,
mSelectionArgs,
null);
}
http://developer.android.com/reference/android/content/CursorLoader.html
12
Agenda e Contatos
129
o mtodo swapCursor() para trocar o cursor do adaptador pelo cursor do mtodo onLoadFinished(). J o segundo chamado quando o framework detecta que o cursor contm
dados desatualizados, nesse caso basta apagar a referrencia ao cursor no adaptador.
Por fim, voc deve implementar o mtodo onItemClick() para abrir uma nova activity
ao clicar no contato.
1
2
3
4
5
6
8
9
10
11
12
Primeiro ns obtemos a posio na lista atravs do parmetro position, em seguida colocamos o cursor nessa posio e obtemos os dados do contato. Usando o mtodo getLookupUri() ns conseguimos a URI do contato para que seja possvel acessar suas informaes
detalhadas.
12.1.1
Detalhes de um contato
130
1
2
3
4
5
6
7
8
9
12
Agenda e Contatos
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
12
Agenda e Contatos
131
a obteno dos dados do Intent e a referncia ao ViewGroup que iremos utilizar mais
tarde.
1
2
3
4
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_details);
6
7
8
9
10
11
12
13
14
getSupportLoaderManager().
restartLoader(ContactDetailsQuery.QUERY_ID, null, this);
getSupportLoaderManager().
restartLoader(ContactAddressQuery.QUERY_ID, null, this);
if(hasPhone())
getSupportLoaderManager().
restartLoader(ContactPhoneQuery.QUERY_ID, null, this);
10
11
12
13
14
15
16
17
132
12
Agenda e Contatos
contato, sem ser em outra thread, mas na mesma thread da UI (User Interface)8 .
Agora iremos implementar o mtodo onCreateLoader(), de forma semelhante ltima
vez, mas agora iremos criar um CursorLoader diferente dependendo do id que foi passado
para o mtodo - no caso o QUERY_ID que foi o parmetro do mtodo restartLoader(),
visto no algoritmo 12.12.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle arg1) {
switch (id) {
case ContactDetailsQuery.QUERY_ID:
return new CursorLoader(this,
mContactUri,
ContactDetailsQuery.PROJECTION,
null, null, null);
case ContactAddressQuery.QUERY_ID:
String addressArgs[] = {String.valueOf(mContactId)};
return new CursorLoader(this,
StructuredPostal.CONTENT_URI,
ContactAddressQuery.PROJECTION,
ContactAddressQuery.SELECTION,
addressArgs, null);
case ContactPhoneQuery.QUERY_ID:
String phoneArgs[] = { String.valueOf(mContactId) };
return new CursorLoader(this,
Phone.CONTENT_URI,
ContactPhoneQuery.PROJECTION,
ContactPhoneQuery.SELECTION,
phoneArgs, null);
default:
break;
}
return null;
}
Tudo que fizemos at agora (exceto o AsyncTask na lio de comunicao) est rodando na chamada UI
thread, isso significa que o Android est executando seu cdigo na mesma thread em que cria a interface do
usurio. Usar o Loader implica em fazer com que as consultas rodem em uma outra thread, liberando a UI
thread do servio e impedindo que o aplicativo parea estar travado enquanto busca informaes. O AsyncTask
uma outra forma de executar background threads de forma asscrona.
12
Agenda e Contatos
133
Note que no Android essas informaes dos contatos esto guardadas em um banco de dados e
o que estamos fazendo na realidade so SELECT comuns, mas usando as classes pr-definidas
para nos auxiliar. O Android tambm j junta vrias tabelas automaticamente para facilitar as
buscas.
Para finalizar, vamos implementar o mtodo onLoadFinished(), nesse mtodo que
adquirimos os dados do cursor e criamos as views para mostrar esses dados.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
134
12
Agenda e Contatos
Novamente, o mtodo ir tomar uma ao diferente dependendo de qual consulta foi realizada. Se existe um resultado, ento ns criado uma TextView e colocamos o texto adquirido
nela. Aqui que usamos a varivel container, usamos o mtodo addView() para colocar
essa view dentro dela.
Esse captulo tentou dar uma introduo obteno dos contatos da agenda. uma tema
especialmente difcil por haver muito rigor nos detalhes. altamente recomendvel estudar
mais a fundo a lio presente na documentao oficial e o exemplo oferecido por eles.
C APTULO
13
Acelermetro
Os dispositivos Android contam com um sensor chamado acelermetro que consegue captar
a acelerao do aparelho nos trs eixos. til para fazer jogos, saber a orientao do aparelho,
entre outras utilidades. Para isso o Android contm um framework para os sensores, uma das
classes a SensorManager que contm vrios mtodos para acessar, registrar listeners e
constantes para calibrar os sensores, reportar a preciso do sensor e configurar a taxa de aquisio dos dados. Para saber mais sobre o framework, acesse a documentao oficial1 .
Agora, para exemplificar vamos construir uma aplicao bem simples que apenas ir mostrar
na tela os valores lidos do acelermetro. Criaremos apenas uma activity com trs TextView
para mostrar os valores lidos do acelermetro.
1
2
3
4
5
6
7
8
9
10
11
12
http://developer.android.com/guide/topics/sensors/sensors_overview.html
135
136
1
2
3
13
Acelermetro
5
6
7
8
mSensorMan =
(SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
9
10
11
12
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
6
7
8
9
10
11
12
13
14
15
DecimalFormat df
xAxis.setText("X
yAxis.setText("Y
zAxis.setText("Z
16
17
18
19
20
= new
Axis:
Axis:
Axis:
DecimalFormat("##.####");
" + df.format(acceleration[0]));
" + df.format(acceleration[1]));
" + df.format(acceleration[2]));
http://developer.android.com/guide/topics/sensors/sensors_motion.html
13
Acelermetro
137
Por ltimo, deve-se registrar o listener quando a activity est em primeiro plano e desregistrar quando a activity for pausada. Isso necessrio para no ficar consumindo a bateria
de forma desnecessria. Logo, ser necessrio fazer isso nos mtodos onResume() e onPause().
1
2
3
4
5
6
7
8
9
10
138
13
Acelermetro
C APTULO
14
Bluetooth
O Android providencia uma API para conectar o aparelho em outros dispositivos Bluetooth,
sejam outros celulares, tablets, fones de ouvido e at mesmo HDP (Health Device Profile) que
um tipo de conexo Bluetooth para aparelhos mdicos. Com a API para Bluetooth voc pode:
sondar outros dispositivos Bluetooth, buscar por dispositivos j pareados, estabelecer conexes,
transferir dados e gerenciar mltiplas conexes.
Para exemplificar iremos construir uma pequena aplicao que envia uma mensagem para
um dispositivo pareado. Esse exemplo ir introduzir diversos novos conceitos do sistema Android e do prprio Java, entre eles: BroadcastReceiver, Thread, Handler, Runnable, alm claro, do Bluetooth.
Primeiro nossa aplicao deve recuperar todos os dispositivos bluetooth j conhecidos, ou
seja, aqueles que j foram pareados com o nosso aparelho. Colocaremos numa ListView
tanto os dispositivos pareados como aqueles novos que iremos procurar.
Iniciaremos com uma classe que chamei de DeviceListActivity, essa activity ir
mostrar a lista dos dispositivos encontrados, ao se clicar em um desses dispositivos, uma mensagem ser enviada atravs de um socket. Somente se o outro dispositivo estiver rodando a
aplicao no mesmo momento que a mensagem poder ser visualizada.
1
2
3
4
5
6
http://developer.android.com/reference/android/widget/ArrayAdapter.html
http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
139
140
14
Bluetooth
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device_list);
/* 1 */
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null) {
// Bluetooth nao suportado
}
6
7
8
9
10
11
/* 2 */
if(!mBluetoothAdapter.isEnabled()){
Intent enableBluetooth = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetooth, REQUEST_ENABLE_BT);
}
12
13
14
15
16
17
18
19
20
21
/* 3 */
Set<BluetoothDevice> pairedDevices =
mBluetoothAdapter.getBondedDevices();
if(pairedDevices.size() > 0){
for(BluetoothDevice device : pairedDevices){
mArrayAdapter.add(device.getName() + "\n"
+ device.getAddress());
}
}
... //[1]
deviceList.setAdapter(mArrayAdapter);
... //[2]
22
23
24
25
26
27
28
29
30
31
32
33
34
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html
http://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html
14
Bluetooth
141
O segundo passo verificar se o Bluetooth est ativado, essa verificao feita com uma
chamada ao mtodo isEnabled() como feito na linha 13. Se o retorno for falso ento ns
iremos perguntar ao usurio se ele gostaria de ativar o adaptador Bluetooth. Para isso necessrio lanar um Intent com action igual BluetoothAdapter.ACTION_REQUEST_ENABLE. Ao chamar o mtodo startActivityForResult() um alerta ir perguntar ao
usurio se ele quer ativar o Bluetooth. A varivel REQUEST_ENABLE_BT pode ser qualquer
valor maior que 0.
O terceiro passo obter todos os dispositivos j pareados, a classe BluetoothAdapter
mantm uma lista desses dispositivos que pode ser adquirida com a chamada ao mtodo getBondedDevices(). Depois, adicionaremos o nome e endereo MAC desses dispositivos
pareados ListView usando o ArrayAdapter.
O mtodo onActivityResult() no precisa de nada especial. Mostrar para o usurio
um feedback j suficiente.
1
2
3
4
5
6
7
8
9
10
11
12
@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == RESULT_OK){
Toast.makeText(this, "Bluetooth is on", Toast.LENGTH_LONG)
.show();
} else if(requestCode == RESULT_CANCELED){
Toast.makeText(this, "Bluetooth is off", Toast.LENGTH_LONG)
.show();
}
}
Voltando ao mtodo onCreate() Observe o comentrio // [1] na linha 31 do algoritmo 14.2, nesse pedao do cdigo iremos adicionar um rodap na ListView com um boto
que iniciar a varredura por novos dispositivos.
Apesar de no ter apresentado este conceito antes, rodaps e cabealhos em ListViews
so bem simples, construa um layout XML e use o LayoutInflater para obter a View,
depois adicione essa View lista usando addFooterView(). Rodaps e cabealhos precisam ser adicionados ListView antes de definir o adaptador. Tambm adicionaremos um
listener a um boto para que ele inicie a varredura. O mtodo startDiscovery() usado
para fazer a varredura.
142
1
14
Bluetooth
2
3
4
5
6
scan.setOnClickListener(new OnClickListener() {
7
8
9
10
11
12
@Override
public void onClick(View v) {
mBluetoothAdapter.startDiscovery();
}
});
13
14
deviceList.addFooterView(v);
2
3
4
5
6
7
8
9
10
11
12
13
14
http://developer.android.com/reference/android/content/IntentFilter.html
14
1
2
3
4
5
Bluetooth
143
@Override
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(mReceiver);
}
6
7
8
9
10
11
12
@Override
protected void onResume(){
super.onResume();
filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
}
Agora, iremos criar trs threads. A primeira, chamada de AcceptThread ser responsvel por instanciar um BluetoothSocketServer e aceitar uma nova conexo vinda de
um outro dispositivo. A segunda, ConnectThread ser usada quando a aplicao funcionar como cliente, essa thread ir tentar estabeceler uma conexo com outro dispositivo. J a
terceira, ConnectedThread ser usada em ambos os casos, para gerenciar a conexo e a entrada e sada de dados. Todas essas threads esto escritas como classes inline (dentro da classe
DeviceListActivity).
A primeira thread, AcceptThread, ir instanciar um BluetoothServerSocket6
usando o mtodo listenUsingRfcommWithServiceRecord(), esse mtodo cria um
socket seguro em um canal Bluetooth, portanto toda informao ser criptografada. Os parmetros so name e uuid, name o nome do servio que nesse caso pode ser qualquer coisa. J
o uuid um identificador universal nico para ser usado com a aplicao, pode-se obter um
nmero usando geradores aleatrios de UUID disponveis na web. A thread ir ficar tentando
escutar uma conexo com o mtodo accept(). Note que este mtodo bloqueante e ir retornar um socket se a conexo foi aceita ou ir gerar uma exceo. Como no queremos aceitar
mais nenhuma conexo, chamamos close() que ir fechar o BluetoothServerSocket
mas no ir fechar o BluetoothSocket criado, mantendo a conexo.
Se o socket conseguir ser instanciado corretamente, iremos chamar o mtodo manageConnection(), responsvel por instanciar a thread que gerencia a conexo.
http://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html
144
1
2
14
Bluetooth
3
4
5
public AcceptThread(){
BluetoothServerSocket tmp = null;
try {
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(
NAME, UUID.fromString(MY_UUID));
} catch(IOException e) { }
mServerSocket = tmp;
}
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if (socket != null) {
manageConnection(socket);
try {
mServerSocket.close();
break;
} catch (IOException e) { }
}
23
24
25
26
27
28
29
30
31
32
O algoritmo 14.8 abaixo mostra a segunda thread, essa thread responsvel por estabelecer
uma conexo com outro dispositivo que esteja rodando a mesma aplicao, por isso usado o
mesmo UUID. O construtor ir receber um BluetoothDevice, que foi selecionado da lista,
e tentar criar a conexo com o mtodo createRfcommSocketToServiceRecord().
A thread ir cancelar a varredura e ir tentar conectar ao socket usando connect(), que tambm uma chamada bloqueante. Se a conexo falhar ou ocorrer um timeout, ele ir gerar uma
exceo. Por segurana, chamamos close() dentro do bloco catch para tentar fechar o
socket e liberar os recursos do aparelho. Se tudo der certo, chamamos o mtodo manageConnection() que veremos logo. Por enquanto deixaremos a explicao da linha 29 em espera,
voltaremos logo nela.
14
1
2
3
Bluetooth
145
5
6
7
8
try {
tmp = device.createRfcommSocketToServiceRecord(
UUID.fromString(mUUID));
} catch (IOException e) {}
mSocket = tmp;
9
10
11
12
13
14
15
16
17
18
try {
mSocket.connect();
} catch (IOException openExc) {
try {
mSocket.close();
} catch (IOException closeExc) { }
return;
}
19
20
21
22
23
24
25
26
27
manageConnection(mSocket);
mHandler.post(mShowDialog);
28
29
30
31
1
2
3
4
Agora veremos a ltima thread, essa resposvel pela entrada e sada de dados atravs do
socket.
146
1
2
3
4
14
Bluetooth
6
7
8
9
10
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
11
12
13
14
15
mmInput = tmpIn;
mmOutput = tmpOut;
16
17
18
19
20
21
22
23
while(true) {
try {
bytes = mmInput.read(buffer);
mMessage = new String(buffer);
mHandler.post(mShowMessage);
} catch(IOException e) { break; }
}
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
14
Bluetooth
147
chamadas so bloqueantes. O mtodo read() ir bloquear enquanto no houver nada para ler
e o mtodo write() pode bloquear caso o outro lado esteja lendo os buffers muito lentamente.
A thread ir repetir enquanto no houver exceo e ficar tentando ler do stream usando
read(). Aqui novamente colocaremos a explicao da linha 28 em espera e voltaremos nela
posteriormente. Faremos tambm um mtodo write() para essa classe, para embrulhar o
mtodo do socket, que poder ser chamado da activity.
Agora temos dois mtodos, um para receber e mostrar a mensagem e outro para enviar a
mensagem. O mtodo writeMessage(), abaixo, abre um alerta com um EditText em
que o usurio pode escrever a mensagem para ser enviada.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
148
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Bluetooth
@Override
public void onItemClick(AdapterView<?> arg0, View v, int pos, long id) {
String address = mArrayAdapter.getItem(pos).split("\n")[1];
BluetoothDevice mDevice = mBluetoothAdapter.getRemoteDevice(address);
6
7
8
deviceList.setOnItemClickListener(this);
2
3
4
14
Bluetooth
149
pode ser enviado atravs do canal de comunicao Bluetooth. Nesse exemplo estamos enviando
apenas uma mensagem mas poderia ser qualquer tipo de arquivo.
Esse captulo tentou mostrar uma simples aplicao que utiliza o Bluetooth no envio de
dados. Hoje o Bluetooth est presente em diversos dispositivos: smartphones, fones de ouvido,
caixas de som, aparelhos mdicos, entre outros. O Android, por exemplo, utiliza o NFC para
abrir uma conexo Bluetooth entre dois aparelhos e enviar dados. Isso chamado Android
Beam.
150
14
Bluetooth
C APTULO
15
Internacionalizao
possvel fazer com que sua aplicao d suporte a diversos idiomas, o Android fornece
uma maneira fcil de internacionalizar suas strings e bitmaps.
Antes, ns usamos o arquivo de recursos strings.xml para armazenar qualquer tipo
de texto dos nossos exemplos. Dessa forma voc consegue manter esse tipo de informao
separada do cdigo. Isso permite separar os textos por idioma, quando isso acontece o Android
muda automaticamente o idioma do aplicativo de acordo com o idioma do aparelho.
Para adicionar suporte a mais idiomas, crie diretrios values/ adicionais dentro do diretrio res/ que incluam um hfen e o cdigo ISO do pas no final. Por exemplo, values-es/
para espanhol ou values-pt/ para portugus. Dentro de cada uma dessas pastas voc
deve ter um arquivo string.xml com os textos traduzidos. Por exemplo, em values/string.xml voc deve manter o idioma padro da aplicao, preferencialmente ingls:
1
2
3
4
5
152
15
Internacionalizao
Outros recursos tambm podem aproveitar da localizao, como o caso dos drawables.
Voc pode ter imagens traduzidas dentro dessas pastas.
Os cdigos do idioma seguem o padro ISO-639-11 .
Se voc quiser separar por pas, por exemplo entre portugus brasileiro e portugus de portugal, voc deve adicionar o cdigo do pas ao nome da pasta, precedido por um -r. Portugus
do brasil seria values-pt-rBR/ e de portugal seria values-pt-rPT/.
http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes