Atualmente, o poder de processamento dos celulares e outros aparelhos mveis salta
vista. Com esse avano, tambm h sensveis melhorias nas telas e na usabilidade desses dispositivos.
Imagine o quo elegante seria, nesse cenrio, poder mostrar seu portflio de aplicaes j diretamente na sua mo, sem necessidade de sequer um laptop?
Por essas e outras razes, plataformas mveis como Blackberry, iOS e Android, esto cada vez mais em evidncia e o mercado para tais dispositivos est em plena ascenso. A exploso do Android a mais recente dentre essas plataformas, e seu crescimento no tem previso de declnio.
O Android um sistema operacional que roda sobre o ncleo Linux. Ele foi inicialmente desenvolvido pela Android Inc., e depois passou para as mos do Google (que a comprou em 2005) e posteriormente pela Open Handset Alliance. A plataforma permite que os desenvolvedores escrevam software na linguagem Java controlando o dispositivo via bibliotecas desenvolvidas pela Google, com o objetivo de ser uma plataforma flexvel, aberta e de fcil migrao para os fabricantes.
Site para desenvolvedores
O link para documentao, downloads e outros : http://developer.android.com/
Se est procurando um livro para se aprofundar nos estudos, indicamos o da editora Casa do Cdigo: http://www.CasaDoCodigo.com.br
No mercado j existem inmeras opes de dispositivos com Android. Desde vrios fabricantes a vrios modelos. J existem tablets e at uma ideia para Google TV Android:
Samsung Galaxy Tab 10 Samsung Galaxy S, S2 e S3 Google Nexus S, Google Nexus 4, Google Nexus7 e Nexus 10 HTC Legend Motorola Xoom e Xoom 2 Xperia X10 Motorola Defy
Primeiramente, devemos baixar o Bundle Android para o nosso sistema operacional. Voc pode baixar o arquivo da seguinte URL:
O Bundle vem com o SDK, Eclipse e ADT j configurado e customizado para voc programar no Android.
Aps o download ser necessrio rodar o SDK e fazer o update das verses Android que voc deseja usar.
Durante o curso
Note que, durante o curso, o Bundle est pronto na Caelum j tem os diversos "Installed Packages". Isso porque so 1.00Gb de downloads e nosso tempo de curso precioso!
bom tambm baixar o Google APIs para todos os levels, para poder usar outras APIs opcionais.
Como todo incio de aprendizado, nosso primeiro projeto ser um Hello World. Criar uma aplicao inicial para Android muito fcil.
Vamos criar um projeto em branco, e preencher nome da aplicao e pacotes de instalao.
No Eclipse, v em New... e escolha Android Application Project:
Na tela de criao, preencha o nome do Application Name, Package Name e as configuraes de verses da SDK.
Preencha o nome da aplicao como sendo OlaMundo e o package como br.com.caelum.olamundo como na seguinte figura:
Aperte Next.
Na tela de Configurao do Projeto desmarque a opo Create custom launcher icon.
Aperte Next.
Na tela de criao da Activity, selecione a opo Blank Activity. Como na seguinte figura:
V para a prxima tela.
Nesse tela vai ser configurado como vamos chamar nossa Activity e o seu respectivo layout. Altere o Layout Name paraprincipal . Como na seguinte figura:
Agora clique em Finish.
Muitos arquivos foram gerados automaticamente quando criamos um projeto do Android. Para comearmos a entender o que acontece na nossa aplicao, vamos explorar um pouco a estrutura desse projeto.
A classe OlaMundoActivity
Comece abrindo o arquivo OlaMundoActivity.java (em src, no pacote br.com.caelum.helloworld). Voc ver algo como: 1 2 3 4 public class OlaMundoActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { 5 6 7 8 super.onCreate(savedInstanceState); setContentView(R.layout.principal); } } Note que essa classe uma Activity, pois ela herda dessa classe. Isso quer dizer que ela representa uma tela da nossa aplicao e implementa a forma como essa tela reagir interao com o usurio e o contedo mostrado nela, entre outros.
Layouts moda do Android
A forma e disposio com que os elementos so apresentados na tela, contudo, responsabilidade dos Layouts. Veja o arquivo principal.xml em res/layout/: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" >
</RelativeLayout> Nesse exemplo, estamos declarando um layout linear e avisando que, mesmo quando no houver contedo o bastante para preencher a tela, a aplicao se esticar e vai ocup-la por completo. Isso se deve aos parmetros com fill_parent.
J na tag TextView, note que a altura determinada como o apenas necessrio para mostrar seu contedo, configurada como wrap_content.
Agora, repare na linha em destaque: @string/hello. Ela define o texto que aparecer na tela quando a aplicao rodar. Perceba que ela apenas uma chave para algum texto. Esse texto est definido em res/values, dentro do arquivo string.xml.
Essa uma ideia simples que facilita na internacionalizao da sua aplicao. Para traduzi- la para outras lnguas, basta criar outros arquivos de value com as tradues.
Imagens e afins
Frequentemente, precisamos de imagens para complementar nossa aplicao. Entretanto, quando pensamos em dispositivos pequenos, necessrio considerar as capacidades de resoluo da tela.
Assim, um projeto Android guarda imagens nas pastas res/drawable-[lmh]dpi/, onde ldpi corresponde baixa resoluo, mdpi mdia e hdpi alta resoluo.
Caso no haja um device disponvel para testarmos nosso cdigo possvel utilizarmos emuladores no ADT. Para isso basta escolhermos as especificaes do device que desejamos.
O emulador bastante til porque nem sempre possumos vrios dispositivos com diferentes tamanhos de tela e verses do Android disponveis para teste.
Para criar um novo simulador precisamos seguir os seguintes passos:
Clique no menu Window e depois em Android Virtual Device Manager.
Na janela que foi aberta, clique sobre o boto New.
Agora preencha as informaes conforme a figura abaixo.
Pronto!!! Agora, basta rodar sua aplicao no simulador de Android.
Para isso, v em Run -> Run Configurations... e crie uma nova configurao para Android, nomeando-a e escolhendo a aplicao OlaMundo.
O plugin far o upload da aplicao para o simulador e o instalar, rodando sua aplicao logo em seguida.
O simulador demora um tanto para inicializar, j que est realmente dando boot num Android para o teste. Mas, quando finalmente terminar, voc deve ver uma tela assim:
Para rodar um simulador de Android, preciso configur-lo no Eclipse. Vamos criar um Virtual Device no Android SDK e usar a verso do OS. Siga as instrues sobre a verso (Target) a ser utilizada no curso.
Verso do Target
Utilizaremos as verses:
Minimum Required SDK: Api 8: Android 2.2 Target SDK: Api 17: Android 4.2 Compile With: Api 17: Android 4.2 Theme: None
Pronto! Agora voc j consegue simular suas aplicaes no Android virtual e utilizar os servios j prontos da plataforma. Basta escolher o AVD e clicar em Start....
Agora que j conhecemos o funcionamento bsico de uma aplicao para Android, preciso criar uma base maior, teremos que ir mais a fundo no SDK. Veja a estrutura do sistema do Android na figura abaixo:
As aplicaes e os frameworks do Android rodam sobre uma mquina virtual diferente, chamada Dalvik, que roda um bytecode especfico. No entanto, a linguagem de alto nvel que utilizamos para programar o Java.
O que acontece a SDK do Android j vem munida de um tradutor do formato bytecode de um class para o formato dex da virtual machine Dalvik, que, alm de traduzir, j faz uma srie de otimizaes focadas em reduzir o espao do executvel gerado.
Entendamos, agora, os componentes e seus ciclos de vida para que possamos montar um sistema robusto, expansvel e com uma performance aceitvel para o usurio.
J comentamos que uma Activity corresponde usualmente a uma tela da sua aplicao, mas, mais do que isso, o executvel da sua aplicao Android tem que estender a classe Activity. Essa a maneira do framework saber o que chamar no seu executvel.
O mtodo onCreate chamado quando uma Activity executada e ele faz a chamada no sistema.
As classes que estendem Activity, de uma forma mais abrangente, interagem tanto com usurios como com servios ou intenes.
Ciclo de vida de uma Activity
Toda Activity tem o ciclo de vida representado na figura a seguir. Os mtodos chamados sero os mtodos que sobrescreveremos quando criarmos nossas prprias Activities.
onCreate() Chamado quando a aplicao criada. onde se criam as Views, faz chamadas de banco de dados. Quando executado, o sistema recebe um Bundle com o estado da ltima execuo da atividade.
onStart() Chamado antes da aplicao ficar visvel na tela. Se der tudo certo, vai para onResume(), seno, para onStop().
onResume() Chamado aps o onStart() se a sua aplicao for para primeiro plano. Neste ponto, voc est interagindo com o usurio. aqui que sua aplicao pode iniciar ou retornar as aes necessrias para atualizar as interfaces como usurio.
onPause() Acontece quando o Android chama uma atividade diferente. Voc perde os direitos da tela, ento o momento de parar animaes e todo o suprfluo que consuma recursos do sistema e bateria.
onStop() Chamado quando outra atividade obteve o primeiro plano, ou quando sua atividade est sendo eliminada.
onDestroy() ltima oportunidade da sua aplicao fazer alguma coisa antes de ser eliminada. Lembre-se que este mtodo pode ser chamado quando o Android precisa de recursos, ou porque o usurio optou por finalizar a aplicao.
onDestroy() na verso 1.5
Por alguma razo, o mtodo onDestroy() no era chamado na verso 1.5 do SDK.
Se voc estiver desenvolvendo para essa verso em particular, tome cuidado com esse detalhe!
No final do OlaMundo, vimos algumas pastas internas /res, como layout, values e drawable, e, alm delas, h algumas outras que aparecem em aplicaes mais complexas e ricas. Vamos, agora, mais a fundo nesses importante arquivos:
res/layout/
Esse o local para armazenar suas telas, escritas em XML. Veja, por exemplo, o arquivo main.xml em OlaMundo/res/layout/. 1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> Nesse exemplo, estamos declarando um layout linear e avisando que, mesmo que no houver contedo o bastante para preencher a tela, a aplicao se esticar para ocupar toda a tela. Isso se deve aos parmetros com fill_parent.
J na tag TextView, note que a altura determinada como o apenas necessrio para mostrar seu contedo, configurada como wrap_content.
res/values/
Repare na linha em destaque no layout acima: @string/hello. Ela define o texto que aparecer na tela quando a aplicao rodar. Perceba que ela apenas uma chave para algum texto. Esse texto est definido em res/values, dentro do arquivo string.xml. 1 2 3 <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World!</string> 4 5 <string name="app_name">Curso</string> </resources> Essa uma ideia simples que facilita na internacionalizao da sua aplicao. Para traduzi -la para outras lnguas, basta criar outros arquivos de value com as tradues. Alm disso, isolar as Strings do sistema, tambm potencializa a clareza de alguns pontos do cdigo como por exemplos, chamadas ao banco de dados do Android.
res/raw/
Esse o local para armazenar arquivos de mdia que futuramente sero utilizados no sistema, como mp3, vdeos e outros.
res/XML/
Nessa pasta armazenaremos arquivos XML. Se ela no existir, s cri-la na pasta /res
res/drawable
Local para armazenar imagens, sejam *.gif, *.jpg ou *.png.
Vale relembrar que as imagens da sua aplicao so guardadas em trs resolues, cada uma com sua pasta no sistema:
res/drawable-ldpi/: low, dispositivos de baixa resoluo (quase inexistentes); res/drawable-mdpi/: medium, dispositivos de mdia resoluo (raros); res/drawable-hdpi/: high, dispositivos com alta resoluo (maioria). Existe tambm uma classe central e automaticamente gerada que responsvel pelo mapeamento dos elementos da view com o model e o controller. Veja que tudo o que criado ou declarado na pasta res ganha uma representao em Java, que utilizaremos bastante para pegar valores e referenciar itens.
Note, no entanto, que essa classe no deve ser alterada a mo. Ela apenas um recurso que o Android disponibiliza para facilitar a referncia a objetos visuais, imagens, strings, etc. 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 public final class R { public static final class attr { } public static final class drawable { public static final int caelum=0x7f020000; public static final int icon=0x7f020001; } public static final class id { public static final int FrameLayout01=0x7f060000; public static final int botao=0x7f060002; public static final int dest=0x7f060003; public static final int linearl=0x7f060001; public static final int send=0x7f060005; public static final int texto=0x7f060004; } public static final class layout { public static final int helloworld=0x7f030000; public static final int layout1=0x7f030001; public static final int main=0x7f030002; public static final int player=0x7f030003; public static final int smsexample=0x7f030004; public static final int widgets=0x7f030005; } public static final class raw { public static final int musica=0x7f040000; public static final int video=0x7f040001; } public static final class string { public static final int app_name=0x7f050001; public static final int hello=0x7f050000; 28 29 30 31 32 } } Note que, dessa forma, das nossas classes java, para acessar qualquer recurso declarado na pasta res/, fazemos uma referncia aos atributos pblicos dessa estranha classe R. Por exemplo:
Acesso a imagens:
R.drawable.icon R.drawable.caelum Acesso a itens da tela declarados nos XMLs de layout:
R.id.botao R.id.texto Acesso a arquivos:
R.raw.musica R.raw.video Acesso a strings:
R.string.app_name R.string.hello Veremos com frequncia cdigos que pegam esses componentes, strings, imagens atravs do mtodo findViewById, para depois utiliz-los, definir listeners, etc: 1 Button botaoDeOk = (Button) findViewById(R.id.botao); Essa classe R gerada pelo plugin do Eclipse e no deve ter seus valores alterados por ns. Ela ser utilizada como referncia para acessar os diversos componentes da nossa interface. como uma grande coleo de identificadores, que a plataforma saber utilizar para localizar seus valores e propriedades de maneira otimizada.
O R.java gerado de acordo com os diversos arquivos utilizados para configurao da sua aplicao. Se houver algum erro nesses diversos arquivos, capaz de que o plugin no consiga reger-lo, dessa forma propagando um erro em quase todos os seus arquivos fonte, dada a ausncia da classe R. Devemos ento ficar atento e buscar o erro que est impedido sua gerao, e tomar cuidado para no importar a classe android.R, que no a da sua aplicao, e sim uma de uso interno ao Android.
Como voc j sabe, todas as telas do Android so feitas num arquivo XML, que ficam dentro de res/layout. L configuramos os detalhes de cada componente, que so itens grficos.
Dentro do XML, cada componente declarado poder ser manipulado em cdigo Java. Todos esses componentes so filhos de android.view.View. Esses Views sero futuramente agrupados dentro de ViewGroup. No coincidentemente, ViewGroup filha de View, formando o composite pattern que aparece tambm no Swing, onde Container filha de Component.
Uma ViewGroup pode conter Views e inclusive ViewGroups conforme imagem a seguir:
Algumas pessoas vo chamar esses components de widget, porm h um outro conceito no android, que uma pequena aplicao que pode rodar dentro da home do dispositivo mvel, tambm chamado de widget.
Durante o curso vamos apresentar alguns dos componentes mais usados em aplicaes Android. No momento vamos apresentar algumas importantes propriedades que podem ser configuradas nesses componentes. Precisamos tambm aprender a vincular comportamento aos componentes da tela, para que possamos interagir com o usurio da aplicao.
No momento vamos focar nos componentes mais bsicos:
Serve para escrevermos um texto na tela do Android, como um label. 1 2 3 4 5 <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Caelum explica..." /> Cada componente possui diversas propriedades. Alis, layout_width e layout_height so obrigatrios para todos eles. Voc poderia utilizar uma medida especfica, como em pixels, mas no recomendado. As opes relativas so mais frequentes, como o wrap_content e match_parent (a partir da verso 2.2, match_parent) aqui utilizados, e veremos mais adiante o significado das principais opes.
Serve como campo de edio para o usurio do sistema. 1 2 3 4 5 <EditText android:id="@+id/cidade" android:layout_width="match_parent" android:layout_height="wrap_content" /> Para ler o valor do campo, deve-se invocar getText e depois toString: 1 2 EditText cidade = (EditText) findViewById(R.id.cidade); Log.i("Meu Texto: ", cidade.getText().toString()) ; Log.i a forma de utilizarmos o DDMS, o sistema de gerenciamento da mquina Dalvik. Esse log ser guardado em uma localizao especfica do seu dispositivo, e pode ser facilmente visto atravs do emulador.
Este widget um boto como na web ou em sistemas desktop. 1 2 3 4 5 6 <Button android:id="@+id/botaoConfirmar" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Boto" /> Para usarmos na lgica, devemos buscar o boto e adicionar o listener desejado. Esse listener ser disparado quando houver um clique no boto. Para fazer isso, precisamos de uma classe que implemente a interface interna View.OnClickListener: 1 2 3 4 5 6 class BotaoDeConfirmarListener implements View.OnClickListener { public void onClick(View view) { // pega os dados da Activity e // grava os dados na base SQL } } Dentro de nossa activity, podemos registrar uma instncia desse listener para o boto: 1 2 3 Button cadastrar = (Button) findViewById(R.id.botaoConfirmar);
cadastrar.setOnClickListener(new BotaoDeConfirmarListener())); Mas como a instncia de BotaoDeConfirmarListener pode pegar os dados dos campos que esto na activity? Uma hiptese seria ter diversos getters, e passar this como argumento para o construtor.
Ou ento j definir o construtor e passar apenas os itens necessrios para que o listener funcione.
Apesar das duas possibilidades, a forma mais comum utilizar classes annimas: 1 2 3 4 5 6 7 8 9 Button cadastrar = (Button) findViewById(R.id.botaoConfirmar);
cadastrar.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { // pega os dados da Activity // (agora que temos acesso a todos componentes, fica mais simples) // grava os dados na base SQL } }); O cdigo fica mais curto, mas pode atrapalhar a legibilidade e tornar a classe muito grande e com responsabilidades demais. Caso conhea pouco de classes annimas, recomendamos o post no blog da Caelum a respeito delas: http://blog.caelum.com.br/classes-aninhadas-o-que-sao-e-quando-usar/
Se quiser um alerta que precise de uma confirmao do usurio, utilize um AlertDialog. 1 2 3 4 5 6 AlertDialog.Builder builder = new AlertDialog.Builder(Aplicacao.this); builder.setMessage(mensagem); builder.setNeutralButton("OK", null); AlertDialog dialog = builder.create(); dialog.setTitle(titulo); dialog.show(); Utilizado frequentemente para confirmar operaes. O alerta pode ser muito customizado, e em vez de apresentar um texto, pode at mesmo apresentar uma view customizada dentro de seu espao.
Componentes possuem atributos especficos a seu comportamento, mas muitos deles possuem atributos que so comuns e que aparecem com frequncia. J vimos alguns deles, outros so:
android:id: Especifica a identificao no programa android:layout_width: Especifica a largura android:layout_height: Especifica a altura android:text: Essa propriedade serve para mostrar o texto que passado como parmetro. android:textColor: Essa propriedade serve para definir uma cor para o texto exibido. android:background: Essa propriedade serve para definir uma cor de fundo. android:textStyle: Essa propriedade serve para definir um estilo a fonte (negrito e/ou itlico). android:textSize: Essa propriedade serve para definir o tamanho da fonte. O tamanho da fonte pode ser especificado em vrias notaes : px (pixels),sp(scaled-pixels) , mm(milmetros), in (inches) e etc. android:typeface: Essa propriedade serve para definir uma fonte ao texto (Arial , Times NewRoman, Courier New e etc). android:capitalize: Essa propriedade serve para definir o tipo capitalizao das palavras. Por padro, o valor e "none"(nenhum). android:password: Com essa propriedade voc habilita a digitao de senhas. android:visibility: Define se o componente deve ser visvel desde a primeira apario dessa tela. android:inputType: Define o teclado para a insero de dados. Entrou no lugar de algumas propriedades que foram depreciadas Nome dos componentes
Cada objeto utilizado nos xmls tem a forma @+<tipo>/<nome>. Quando o id de um componente visual (View), utilizamos @+<id>/<nome>.
Quando voc identifica o id de um widget, ele compilado e aparece na classe R.java. Por exemplo, se o id for @+telaDeCadastro/botaoConfirmacao, na identificao da sua lgica, apareceria R.telaDeCadastro.botaoConfirmacao.
Outra abordagem criao de listeners configurar no xml da view um mtodo para ser invocado na Activity relacionada a ela. Fazemos isso colocando o nome do mtodo a ser executado no atributo onClick da tag Button: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <LinearLayout...>
<TextView ...> </LinearLayout> Agora basta implementarmos na Acivity um mtodo chamado imprime que recebe uma View 1 2 3 4 public class OlaMundoActivity extends Activity { //... outros mtodos
public void imprime(View view) { 5 6 7 Log.i("Informao:", "Botao clicado!"); } } Quando definimos um arquivo de layout, jogamos dentro dele todos os componentes que gostaramos de ter na tela. Uma questo que fica : como esses componentes estaro dispostos? Apesar deles possurem diretivas em relao a sua altura e largura, quem vem primeiro? Quem estar prximo do outro? Como definir com mais exatido esse posicionamento?
Assim como o Swing possui seus LayoutManagers, o Android possui classes filhas de ViewGroup, sendo que alguns deles agem como os layout managers. Eles definiro como seu layout ser aplicado aos diversos componentes (Views) contidos nele. comum misturar diferentes layouts em uma mesma tela para obter um resultado mais agradvel visualmente.
Por default, e um dos mais usados, temos o LinearLayout, que utilizamos at esse momento.
Este layout utilizado para alinhar horizontalmente ou verticalmente o contedo da tela do Android. 1 2 3 4 5 6 7 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> : </LinearLayout> No modo horizontal podemos ter um resultado estranho:
Utilizado para definir exatamente as posies na tela. Esse layout foi depreciado, a Google recomenda que no usemos em produo. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?xml version="1.0" encoding="utf-8"?> <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:text="Texto Centralizado" android:textColor="#FFFF00" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_x="100px" android:layout_y="20px" /> <TextView android:text="Texto Esquerdo" android:textColor="#FF0000" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_y="40px" android:layout_x="15px" /> </AbsoluteLayout>
O RelativeLayout tem sido cada vez mais usado para a organizao das telas do dispositivo por permitir que os componentes sejam alocados na tela com relao outros componentes ou prpria tela. Com este layout podemos usar algumas tags para fazer este alinhamento. Segue uma pequena lista:
android:layout_alignTop="@+id/item" - Alinha o topo do componente em relao a outro android:layout_alignLeft="@+id/item" - Alinha a esquerda do componente em relao a outro android:layout_toLeftOf="@+id/item" - Alinhado esquerda do componente android:layout_toRightOf="@+id/item" - Alinhado direita do componente android:layout_below="@+id/item" - Alinha abaixo de outro componente android:layout_centerHorizontal="true" - Alinhado no centro horizontal android:layout_centerVertical="true" - Alinhado no centro vertical android:layout_alignParentTop="true" - Alinhado em cima da tela android:layout_alignParentBottom="true" - Alinhado em baixo da tela android:layout_alignParentLeft="true" - Alinhado esquerda android:layout_alignParentRight="true" - Alinhado direita Mas lembre-se que o Graphical Layout vai te ajudar a fazer esta organizao. A dica de ouro, colocar id's adequados aos seus componentes.
comum misturarmos diferentes layouts para fazer telas um pouco mais complexas, um nico layout nem sempre o suficiente. Alm do que vimos, ainda temos:
FrameLayout - Praticamente sem layout. As Views ficam umas em cima das outras. As vezes o que precisamos para a nossa tela, como quando vamos montar um video com legendas. TableLayout - Ele monta uma tabela na tela com diversas linhas (TableRow). Nestas linhas, as colunas so a quantidade de views nelas colocadas GridView - Serve para voc mostrar diversas views numa mesma tela TabLayout - Como o nome diz, possibilita a colocao de abas na nossa aplicao
Um importante recurso de Layout no Android o atributo layout_gravity. Atravs dele podemos influenciar no posicionamento de nossas Views.
Se criarmos um texto dentro de um FrameLayout ele ficar no topo da tela, na esquerda por padro. 1 2 3 4 5 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
Vamos agora customizar o posicionamento do TextView. Se quisermos que ele seja um ttulo e aparea centralizado no topo da tela podemos utilizar o layout_gravity com o valor center_horizontal. Conforme cdigo abaixo: 1 2 3 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" 4 5 6 7 8 9 10 11 12 13 14 android:layout_height="fill_parent">
Repare que o TextView encontra-se no centro vertical, mas voltou a estar alinhado esquerda. Se quisermos que ele esteja centralizado tanto vertical quanto horizontalmente podemos utilizar mais de um valor para o layout_gravity usando o caractere | ("pipe") para concatenar os valores. Isso no necessrio para o caso do centro da tela j que existe o valor center. No exemplo abaixo demonstramos como colocar um TextView centralizado na tela e outro no canto inferior direito utilizando o layout_gravity. 1 2 3 4 5 6 7 8 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
Quando criamos um elemento de nossa View podemos tambm estar preocupados em como posicionar seu interior. Suponha agora que desejamos colocar um texto na cor preta em um fundo branco. Esse elemento da nossa tela dever estar dentro de um FrameLayout que por sua vez ter um fundo preto. Podemos customizar um TextView para que ele tenha essa aparncia: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
</FrameLayout> O cdigo anterior vai gerar uma tela conforme a imagem a seguir:
Nosso TextView de fundo branco est centralizado na tela, porm no interior do TextView o texto encontra-se posicionado na parte superior esquerda. Para centralizarmos o texto no interior do TextView podemos usar o atributo gravity juntamente com o layout_gravity previamente utilizado. 1 2 3 4 5 6 7 8 9 10 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
Quando o assunto layout, outro artifcio do desenvolvedor Android o uso do layout_weight.
Quando existe um espao sobrando na tela, atravs da propriedade layout_weight podemos orientar o Android a dividir esse espao aplicando um peso maior ou menor para os elementos da View. Para ilustrar no cdigo abaixo vamos colocar trs Button's ocupando toda a largura da tela, porm a altura queremos dividir de tal maneira que o segundo boto tenha o dobro da altura do primeiro e o terceiro boto, por sua vez tenha o triplo da altura do primeiro. Queremos tambm que o conjunto dos trs os botes ocupem toda a nossa tela.
Nosso objetivo encontra-se ilustrado na imagem abaixo:
Para atingir nosso objetivo vamos utilizar o layout_weight para dar peso diviso do espao na tela. Nosso primeiro boto ter peso 1, o segundo ter peso 2 e o terceiro ter peso 3, conforme o cdigo abaixo: 1 2 3 4 5 6 7 8 9 10 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >
</LinearLayout> Lint uma ferramenta que verifica pequenos erros na construo de layouts como:
id duplicado layout duplicados layout no usado texto no externalizado no arquivo strings.xml tamanhos no externalizados no arquivo de dimens.xml outros erros apis de verses superiores usadas em verses inferiores uma boa ferramenta para verificar se a construo de seu layout est seguindo as regras do Android.
O Lint est disponvel somente em verses do plugin ADT superiores a verso 14.
Para rodar o Lint, basta clicar no menu Window -> Run Android Lint. Explicao Para estudar os conceitos do curso e aplic-los na prtica, desenvolveremos incrementalmente um projeto para cadastrar alunos de uma instituio de ensino.
Precisamos de uma aplicao capaz de registrar alunos com suas notas com funcionalidades especficas como fazer ligaes, navegao web, envio de dados para a web e envio/recebimento de SMS. Alm disso, encontraremos os alunos num mapa e numa galeria.
Para comear, faremos:
Incio do sistema de cadastro de alunos Integrar alguns componentes de tela e navegao Vamos comear criando a funcionalidade de listar os alunos em uma tela. Vamos criar o novo projeto e pedir para ao wizard criar a tela inicial de nossa aplicao, controlada pela ListaAlunosActivity e associada ao layout listagem_alunos.xml.
Vamos comear editando o layout criado para colocar um componente usado para apresentar listas na tela do Android, um ViewGroup chamado ListView: 1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<ListView android:id="@+id/lista_alunos" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout> Agora precisamos manipular o ListView e colocar uma lista de nomes para serem apresentados na tela. Na ListaAlunosActivity podemos buscar o ListView criado e criar um Array de nomes: 1 2 3 4 5 6 7 8 9 10 11 12 public class ListaAlunosActivity extends Activity { private ListView listaAlunos;
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.listagem_alunos);
listaAlunos = (ListView) findViewById(R.id.lista_alunos); } } Agora precisamos fazer o ListView apresentar os nomes do Array. O problema que o Array contm Strings e a tela do Android s aceita objetos do tipo View, precisamos fazer o trabalho de converter um objeto comum do Java em uma View. Soma-se a essa tarefa mais uma dificuldade: Como definir a aparncia da linha do ListView?
Abaixo podemos observar dois exemplos de uso de ListView, um deles mais simples outro mais complexo:
Para conseguirmos atingir nosso objetivo e criar uma tela com um ListView populado vamos utilizar um Adapter, uma classe do Android especializada em adaptar para a tela um objeto do Java atravs da criao de uma objeto do tipo View. Um dos adapters disponveis o ArrayAdapter que capaz de converter listas ou arrays em views. Em seu construtor o ArrayAdapter nos pede 3 argumentos:
um Context j que ser necessrio impactar na tela o id do layout da linha a lista ou array de objetos que queremos no ListView 1 2 3 4 5 6 7 String[] alunos = {"Anderson", "Filipe", "Guilherme"};
int layout = android.R.layout.simple_list_item_1;
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, layout, alunos);
listaAlunos = (ListView) findViewById(R.id.lista_alunos); 8 Agora basta associarmos nosso Adapter ao Para que o ListView possa buscar seus elementos atravs do adapter vamos associ-los usando o mtodo setAdapter: 1 2 3 4 5 6 //... ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, layout, alunos);
listaAlunos = (ListView) findViewById(R.id.lista_alunos); listaAlunos.setAdapter(adapter); Para que seja possvel a criao de um sistema com esta capacidade, ser necessria a criao de um projeto Android no Eclipse, utilizando o plugin que instalamos.
Pequenos avisos podem ser mostrador atravs da classe Toast (Torradeira), que faz exatamente o que o nome diz... ele faz "brotar" um aviso na tela por um certo tempo. A durao pode ser Toast.LENGTH_LONG = 1 eToast.LENGTH_SHORT = 0. 1 Toast.makeText(context, "Meu texto de aviso", Toast.LENGTH_SHORT).show(); Quando um Toast criado, uma mensagem fica pronta para ser mostrada na tela, na forma de um balozinho de texto informativo. Ele s mostrado, contudo, quando chamamos o mtodo show().
Diferente de um alerta comum, voc pode continuar a utilizar sua aplicao normalmente enquanto o Toast exibido.
Podemos integr-lo nossa aplicao para que, quando o usurio clicar no aluno listado, mostremos a posio daquele aluno na lista.
Para vincularmos um Toast ao clique em uma View qualquer precisamos vincular a lista a um OnClickListener como no cdigo abaixo: 1 2 3 4 5 public class MinhaActivity extends Activity {
public void onCreate(Bundle savedInstanceState) { // chamada a super, setContentView e outros..
6 7 8 9 10 11 12 13 14 15 16 17 ListView minhaLista = (ListView) findViewById( //algum id de um ListView
listaAlunos.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> adapter, View view, int posicao, long id) {
Toast.makeText(MinhaActivity.this, "Meu texto de aviso", Toast.LENGTH_SHORT).show(); } }); } } Repare que na chamada ao Toast estamos passando o Context que no caso a instncia da MinhaActivity fazendo MinhaActivity.this. Isso porqu this seria a instncia da classe annima que uma classe sem nome que implementa a interface OnItemClickListener. A classe annima no extende Activity que o nico Context que conhecemos at o momento, portanto essa instncia da classe annima no pode ser usada como um Context. Explicao Vamos criar uma nova tela para que possamos cadastrar novos alunos.
Para atingir esse objetivo vamos precisar criar uma nova Activity. Vamos cham-la de FormularioActivity e vincul-la a um novo layout que chamaremos de formulario.xml. 1 2 3 4 5 6 7 8 public class FormularioActivity extends Activity{
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.formulario); } } Podemos realizar essa tarefa sem muita dificuldade com um atalho do ADT:
Aperte CTRL + N e digite Android Activity. Agora clique em Next e na prxima tela escolha a opo Blank Activity. Preencha o campo Activity Name com o nome FormularioActivity. Escolha como nome do layout para essa Activity o nome formulario.xml.
Agora precisamos alterar o layout formulario.xml at atingirmos o seguinte resultado:
Para isso precisamos criar vrios componentes orientados verticalmente. Por esse motivo a tag raiz de nosso layout dever ser um LinearLayout com a orientao vertical: 1 2 3 4 5 6 7 8 <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" >
<!-- outros elementos em breve aqui! -->
</LinearLayout> Dentro do LinearLayout o primeiro elemento que desejamos colocar uma imagem para que mais tarde possamos ter a foto do aluno cadastrado.
Para isso vamos criar um ImageView. Ele deve estar centralizado horizontalmente na tela portanto vamos configurar o atributo layout_gravity de nosso ImageView: 1 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" 3 4 5 6 7 8 9 10 11 12 13 14 15 android:layout_height="wrap_content" android:orientation="vertical" >
</LinearLayout> Devemos criar varias entradas de dados, ou seja EditText's e cada um deles deve ter um texto indicativo de qual informao desejamos que seja preenchida. Ou seja para cada EditText vamos criar um TextView logo acima.
No ltimo elemento da tela ser um Button com o texto Gravar. Ento nosso layout ficar dessa maneira: 1 2 3 4 5 6 7 8 9 10 11 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" >
</LinearLayout> Logo acima do boto gravar precisaremos pedir que o usurio escolha a nota to aluno. No lugar de pedir para que ele digite em um EditText vamos fazer a seleo em um SeekBar com um valor mximo de 10. 1 2 3 4 5 6 7 8 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" >
</LinearLayout> O problema que podemos enfrentar a variedade de dispositivos Android disponveis no mercado. Para os dispositivos de tela pequena no ser possvel visualizar todos os componentes que colocamos no layout e nossa tela no foi configurada para permitir scroll.
Vamos melhorar a compatibilidade de nossa App fazendo com que o LinearLayout fique dentro de uma ScrollView que ser a nova tag raiz do layout formulario.xml: 1 2 3 4 5 6 7 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
</LinearLayout> </ScrollView> Repare que a tag raiz sempre deve conter o namespace (xmlns) do Android, para definir quais tags podemos usar!
Para que seja possvel buscar esses elementos no cdigo devemos criar id's para cada um dos campos de entrada de dados (os EditText's e o SeekBar).
Agora possumos duas telas, precisamos encontrar alguma forma de fazer o usurio navegar entre elas.
Na maioria das vezes precisamos de diversas telas numa mesma aplicao e de menus de acesso a funes especficas.
Felizmente, toda Activity do Android j vem preparada para lidar com menus. Para cri-lo, basta sobrescrever o mtodo onCreateOptionsMenu(Menu menu) da Activity. Faremos isso na nossa ListaAlunosActivity.
Quando criamos um item no menu de uma aplicao, quem se encarrega de encaix-lo na posio correta da tela o prprio sistema, voc no precisa se preocupar. Para isso, dentro do onCreateOptionsMenu(Menu menu), faramos: 1 2 3 4 5 menu.add("Novo"); menu.add("Mapa"); menu.add("Sincronizar"); menu.add("Baixar Provas"); menu.add("Preferncias"); Para que o menu de opes aparea precisamos apenas clicar no boto Menu de nosso aparelho:
Como comportamento padro, o sistema colocar como nome do boto, o parmetro passado no mtodo add, mas, se preferir, pode-se trocar por um cone. Basta chamar no item de menu recm-criado, que devolvido pelo mtodo add, o mtodo setIcon, passando um R.drawable.nomeDaImagem. 1 2 MenuItem mapa = menu.add(0, 3, 0, "Mapa"); mapa.setIcon(R.drawable.mapa); O mtodo onCreateOptionsMenu(Menu menu) deve retornar true (ou o resultado do super) para indicar que o menu deve aparecer na tela.
Apesar da possibilidade da criao programtica do menu, como ele um elemento de tela damos a preferncia de criar seus itens atravs de um xml. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_novo" android:icon="@drawable/ic_novo" android:title="Novo"/> <item android:id="@+id/menu_mapa" android:icon="@drawable/ic_mapa" android:title="Mapa"/> <item android:id="@+id/menu_enviar_alunos" android:icon="@drawable/ic_enviar" android:title="Sincronizar"/> <item android:id="@+id/menu_receber_provas" android:icon="@drawable/ic_receber" android:title="Baixar Provas"/> <item android:id="@+id/menu_preferencias" android:icon="@drawable/ic_preferencias" android:title="Preferncias"/> </menu> Repare inclusive que j estamos escolhendo arquivos dentro da pasta drawable para cones de nossos itens de menu.
Agora precisamos fazer o Android criar elementos na tela - Views - para cada item do menu descrito no xml.
O Android precisa ter a capacidade de ler os xmls que criamos e criar objetos do tipo View a partir das tags, essa a especialidade dos Inflaters.
No caso especfico de um xml de menu podemos utilizar um Inflater especializado em interpretar esse tipo de arquivo, trata-se do MenuInflater.
No mtodo onCreateOptionsMenu podemos fazer uma chamada a getMenuInflater(), um mtodo da classe Activity que nos d acesso a um MenuInflater.
Repare que o mtodo onCreateOptionsMenu j nos fornece um objeto do tipo Menu, basta utilizarmos o inflater para ler nosso xml e criar a partir deles os itens que sero colocados no menu. Para isso podemos utilizar o mtodo mais importante de um Inflater: o inflate. 1 2 3 4 public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.meu_arquivo_de_menu, menu); } A abordagem de utilizar botes fsicos no aparelho foi um diferencial competitivo dos aparelhos Android em relao ao iPhone. Enquanto o produto da Apple baseava toda sua usabilidade em Gestures (inclusive o boto voltar, que ocupa espao na tela) os aparelhos Android podiam combinar cliques na tela com botes no aparelho, possibilitando a fabricao de aparelhos com telas bem menores e utilizando telas com sensibilidade inferior, se necessrio.
Hoje a qualidade dos aparelhos Android evoluiu e o mercado consumidor optou por utili zar principalmente aparelhos com telas maiores, fazendo com que a usabilidade nos aparelhos Android mudassem. Hoje a tendncia minimizar a utilizao de botes fsicos no aparelho (boa parte dos devices mais novos j no possuem botes como o Search e a tendncia minimizar ainda mais).
Para a maior parte dos dispositivos quando uma tela possui um OptionsMenu no existe nenhum indicativo visual na tela dessa presena, fazendo com que a usabilidade da app seja prejudicada.
Em nossa aplicao vamos seguir a tendncia do Android e colocar o Menu em um elemento visual na tela atravs do uso de um componente que surgiu na verso 3.0 do Android: a Action Bar.
Para configurarmos os itens de menu para aparecerem na Action Bar simplesmente configuramos o atributo showAsAction da tag item: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_novo" android:showAsAction="always" android:icon="@drawable/ic_novo" android:title="Novo"/>
Para evitar que o nome de nossa aplicao desaparea nos devices de tela pequena e para tornar a tela mais agradvel, vamos deixar visveis no menu principal apenas as opes mais teis. Para atingir esse objetivo vamos criar um submenu de opes: 1 2 3 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
Nem s de Toast's e menus viver a nossa aplicao: precisamos chamar outras Activity's para trabalhar com outras telas do nosso sistema. Dessa forma, ser possvel navegar pelas telas da nossa aplicao atravs dos menus e botes.
O processo simples: criaremos uma outra Activity, que controlar as aes da nova tela, e um novo Android XML para montar a diagramao da tela.
Em seguida, bastar fazer com que o clique em determinado menu chame o mtodo startActivity(...), passando para ele um Intent: uma inteno de ir para outra Activity. O Intent, por sua vez, precisar receber o objeto de contexto atual (usualmente o this) e a classe que controla a tela para onde queremos ir. 1 2 Intent intent = new Intent(ContextoAtual.this, NovaActivity.class); startActivity(intent); Veremos em captulos posteriores que podemos abrir outras funcionalidades atravs dos Intents, e no apenas outras activities. Aqui, pedimos explicitamente que a atividade NovaActivity seja iniciada.
Na nova activity, dentro do onCreate utilizamos o mtodo setContentView para renderizar a nova tela, puxando as informaes do XML: 1 setContentView(R.layout.novaActivity); J outra Activity, deve ser chamada com o mtodo startActivity, com a Activity e a desejada. Explicao De nada adianta fazermos um formulrio para adicionar novos alunos se no temos como guard-los. necessrio persisti-los de alguma forma.
Apesar da grande e crescente capacidade dos aparelhos mveis, em particular aqueles que usam Android, ainda no vivel guardar um banco de dados completo nesses dispositivos. Ento, usaremos o SQLite e alguns arquivos do sistema (SharedPreferences) para persistir os dados no Android.
Seguindo a ideia do padro MVC, que pode ser visto mais a fundo no curso FJ21, dividiremos a nossa aplicao em trs camadas. Uma camada que j temos trabalhado bastante a de visualizao. Alm dela, j criamos alguns listeners que foram usados justamente para controlar a integrao entre as nossas Views e as outras classes, essa camada conhecida como Controller. Para completar o padro vamos implementar nossa camada de modelo.
A camada de Modelo, a qual comearemos a trabalhar agora, onde basicamente ficaro as lgicas da aplicao. Por exemplo, implementaremos nosso acesso ao Banco de Dados e criaremos algumas classes que representam os conceitos importantes da aplicao.
Agora que temos uma tela com um formulrio vamos criar a funcionalidade de extrair os dados preenchidos.
Na FormularioActivity podemos buscar os componentes de tela e ento extrair os dados preenchidos: 1 2 3 4 5 6 7 EditText editText = (EditText) findViewById(R.id.nome); EditText editSite = (EditText) findViewById(R.id.site); // ...
String nome = campoNome.getText().toString(); String site = campoSite.getText().toString(); //... Em nosso sistema as informaes nome, site, telefone, nota e endereco constituem os dados de um aluno. Em um sistema Orientado a Objetos criamos classes de modelo para tudo o que for importante. No nosso caso, gostaramos de guardar os dados de um aluno. Para isso, criaremos uma classe que representa a entidade Aluno com alguns atributos para guardar as informaes que so relevantes. 1 2 3 4 5 6 7 8 9 10 11 12 public class Aluno {
//getters e setters } Assim podemos lidar com todas as informaes de um aluno em um lugar isolado. Se tivermos algum comportamento especfico de um aluno podemos criar mtodos com regras de negcio nessa entidade.
Agora somos capazes de extrair os dados da tela de formulario e colocar em um objeto do tipo Aluno. Na classe FormularioActivity que controla a tela de formulario podemos fazer: 1 2 3 4 5 6 7 8 9 EditText editText = (EditText) findViewById(R.id.nome); EditText editSite = (EditText) findViewById(R.id.site); // ...
Aluno aluno = new Aluno();
aluno.setNome(campoNome.getText().toString()); aluno.setSite(campoSite.getText().toString()); //... Como podemos ter muita funcionalidade em uma tela a tendncia acabarmos um uma Activity com muitas linhas de cdigo. Sempre que possvel uma boa prtica isolar pequenas responsabilidades em outras classes para que a Activity faa seu trabalho interagindo com outros pequenos especialistas. Essa abordagem facilita o reuso de cdigo (sem necessariamente fazer-se uso de herana) e tambm a manuteno.
Vamos criar uma nova classe responsvel por extrair os dados do formulario para a FormularioActivity. Vamos cham-la de FormularioHelper, ela receber no construtor a instncia do FormularioActivity e cuidar da parte de extrair um aluno a partir dos dados dos campos: 1 2 3 4 5 6 7 8 9 10 11 12 13 public class FormularioHelper { private EditText nome; private EditText telefone; //... outros campos private Aluno aluno;
public FormularioHelper(FormularioActivity activity) { nome = (EditText) activity.findViewById(R.id.nome); telefone = (EditText) activity.findViewById(R.id.telefone); //... find no restante dos campos aluno = new Aluno(); }
return aluno; } } Agora somos capazes de fazer com que o clique no botao de salvar crie um um objeto do tipo Aluno a partir dos dados preenchidos no formulrio: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 protected void onCreate(Bundle savedInstanceState) { //...
Toast.makeText(Formulario.this, "Objeto aluno criado: "+aluno.getNome(), Toast.LENGTH_SHORT).show(); } }); } Agora que fomos capazes de criar um objeto do tipo Aluno como vamos armazenar essa informao de forma que quando sairmos da aplicao e voltarmos sejamos capazes de restaur-la?
Para nossa sorte os aparelhos Android vm com um banco de dados relacional instalado, o SQLite.
Mas, como vamos traduzir os dados do mundo relacional com o mundo Orientado a Objetos? Para isso, utilizaremos um padro de projeto (Design Pattern) conhecido como Data Access Object (DAO).
Para trabalhar com ele, basta seguir a abordagem padro: criar uma classe chamada AlunoDAO. A diferena ser que ela deve estender de SQLiteOpenHelper e ter um construtor que recebe um objeto do tipo Context, o qual traz informaes sobre a aplicao.
Precisamos receber esse objeto porque, para construir corretamente o DAO, necessrio chamar o construtor da classe me, passando o contexto e algumas configuraes do seu banco em particular.
Logo de cara teremos dois mtodos:
onCreate: executado na criao do banco; onUpgrade: executado na alterao da estrutura do banco. O onCreate vai ser invocado sempre que a tabela no existir, por exemplo no primeiro acesso aplicao. J o mtodo onUpgrade mais especifico. Sempre que quisermos atualizar a estrutura da nossa tabela, este mtodo sera chamado para executar o SQL necessrio para realizar a atualizao. No nosso caso sempre apagaremos a tabela e criaremos uma nova.
Para podermos invocar mtodos para executar operaes no banco como insert, update ou delete usaremos objeto do tipo SQLiteDatabase, recebido atravs do mtodo getWritableDatabase que herdamos de SQLiteOpenHelper, e tambm recebemos no onCreate.
H tambm o mtodo getReadableDatabase, que tambm devolve uma referncia para SQLiteDatabase, gastando menos recursos porm possibilitando apenas leitura.
Para criarmos o banco, precisaremos executar uma query SQL indicando as colunas da nossa tabela e seus respectivos tipos. Queremos armazenar cada atributo da classe Aluno nessa tabela, ento teremos uma query assim:
"CREATE TABLE " + TABELA + "(id INTEGER PRIMARY KEY," + " nome TEXT UNIQUE NOT NULL," + " telefone TEXT," + " endereco TEXT," + " site TEXT," + " nota REAL," + " foto TEXT" + ");"
Essa query deve ser executada na criao do banco de dados, portanto, no mtodo onCreate e ela preparar nossa infraestrutura para guardar alunos. O SQLiteDatabase tem o mtodo execSQL para isso.
Agora que temos a infraestrutura criada, basta adicionarmos mtodos no nosso DAO para as aes que queremos executar.
Se voc j trabalha com Java, vai se lembrar bastante do estilo da API do JDBC, isto , teremos que converter manualmente um objeto na estrutura da tabela - sem a maior parte das facilidades de uma ferramenta ORM.
Contudo, no ser necessrio escrever a query, j que ela vem encapsulada pelos mtodos do SQLiteDatabase, provido pelo Android. Apenas preencheremos os parmetros.
Um objeto SQLiteDatabase j tem pronto o mtodo insert, que recebe o nome da tabela, um parmetro que no nos importante no momento e o objeto a ser inserido.
Para inserir um novo registro neste banco, no precisamos de cdigo SQL, basta usar o mtodo insert e o SQL correto j ser gerado, desde que tenhamos preenchido corretamente os valores a serem adicionados. Faremos o seguinte: 1 getWritableDatabase().insert(TABELA, null, valores); No mtodo insert, o primeiro parmetro uma String indicando a tabela onde os valores devero ser inseridos. O segundo parmetro indica o valor padro das colunas caso o valor para ela no seja definido.
Para preencher os valores corretamente, basta usar um objeto do tipo ContentValues, que bem similar a um Map. Nele guardamos o contedo da linha do registro a ser adicionada e vamos preench-lo usando o mtodo put("nomeDaColuna", valor). Veja um exemplo abaixo: 1 ContentValues values = new ContentValues(); 2 3 values.put("nome", aluno.getNome()); values.put("nota", aluno.getNota()); Para fazer a transformao de uma entidade para ContentValues, podemos criar um mtodo auxiliar no prprio DAO. H aqui uma questo de gosto. Alguns vo preferir colocar na prpria classe Aluno um mtodo toContentValues, porm quebra a um pouco da responsabilidade da entidade.
Com nosso DAO criado podemos fazer com que o clique no boto salva persista no SQLite o objeto Aluno criado: 1 2 3 4 5 6 7 8 9 10 botao.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Aluno aluno = helper.pegaAlunoDoFormulario();
AlunoDAO dao = new AlunoDAO(this); dao.insere(aluno); dao.close(); } }); Repare que invocamos o mtodo close herdado da classe SQLiteOpenHelper. Quando nosso DAO instanciado ele acessa o banco, quando no precisamos mais utiliz-lo devemos fechar a conexo!
O que fazer agora que o usurio de nossa aplicao conseguiu salvar o novo Aluno? Provavelmente ele vai querer voltar para a tela de listagem para certificar-se que o aluno foi realmente inserido. Para isso ele clicar no boto voltar do aparelho. Vamos melhorar a usabilidade da aplicao e fazer isso para o usurio: se quisermos programaticamente fazer o papel do boto de voltar podemos invocar o mtodo finish de nossa Activity: 1 2 3 4 5 botao.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Aluno aluno = helper.pegaAlunoDoFormulario();
6 7 8 9 10 11 12 AlunoDAO dao = new AlunoDAO(this); dao.insere(aluno); dao.close();
finish(); } }); Agora que fomos capazes de inserir alunos no SQLite vamos alterar a ListaAlunosActivity para que os elementos da lista no sejam as constantes de um Array de Strings criados por ns.
Vamos adicionar ao nosso DAO um mtodo que vai retornar a lista de alunos cadastrados no nosso sistema.
Buscar todos os alunos , contudo, ligeiramente mais complicado: teremos que lidar com o cursor do banco de dados. Similarmente ao insert, contamos com outro mtodo que nos permite mais liberdade na busca a ser realizada. Esse o mtodo query, que recebe a tabela e um conjunto de colunas a serem recuperadas. 1 2 3 4 5 6 String[] colunas = {"nome", "telefone"};
cursor.moveToFirst(); Como comum buscarmos por todas as colunas, podemos definir uma array de string como constante, contendo todas as colunas da nossa tabela.
Para saber mais...
Os outros muitos parmetros que deixamos nulos, nos permitem tambm fazer select, groupBy, having e orderBy. Explore a API para aprender mais sobre essas opes.
Do resultado dessa busca, receberemos um cursor e, com ele em mos, basta iterar sobre suas diversas linhas, preenchendo objetos Aluno para cada registro do banco: 1 2 3 Aluno aluno = new Aluno(); aluno.setNome(cursor.getString(1)); aluno.setTelefone(cursor.getString(2)); Como desejamos obter uma lista de alunos precisaremos repetir o procedimento de extrair os dados do Cursor enquanto existir um prximo registro. Podemos atingir esse objetivo criando um lao e usando o cursor para verificar se existe um prximo registro salvo, fazendo cursor.moveToNext() e adicionando cada aluno em uma lista criada. 1 2 3 4 5 6 7 8 9 List<Aluno> alunos = new ArrayList<Aluno>();
while(cursor.moveToNext()) { Aluno aluno = new Aluno(); aluno.setNome(cursor.getString(1)); //...
alunos.add(aluno); } Note que poderamos, talvez, devolver o prprio cursor, mas no faremos isso porque essa prtica vai contra o padro dos DAOs - a funo de um DAO abstrair, para quem o utiliza, a interao com o banco de dados e suas classes especficas.
Muitos dos mtodos que estamos trabalhando aqui podem lanar android.database.SQLException, que uma exceo de runtime, logo no somos obrigados a fazer o bloco de try/catch nem de declarar seu throws. Em especial, ao se trabalhar com recursos que podem ficar abertos, como o Cursor, boa prtica deixar seu fechamento dentro de um bloco finally, garantindo seu fechamento.
Agora desejamos deletar um aluno de nossa listagem, podemos criar um mtodo em nosso DAO que deleta um aluno passado como argumento: 1 2 3 4 public void deletar(Aluno aluno) { String[] args = { aluno.getId().toString() }; getWritableDatabase().delete(TABELA, "id=?", args); } Quando vamos invocar esse mtodo?
Vamos pensar na usabilidade de nossa aplicao. Quando clicamos no item da lista de alunos somos redirecionados para a o formulrio de cadastro para fazer a alterao do aluno clicado.
Normalmente em sistemas operacionais o clique simples em um item na tela significa a seleo do item. Quando desejamos outras opes de aes em um item normalmente o que fazemos clicar nele com o boto direito e esperamos que um menu de opes aparea para que possamos escolher qual ao desejamos.
No Android no temos boto direito mas esse papel nos devices realizado pelo clique longo. Podemos fazer com que o clique longo em um item cause a abertura de um menu de opes semelhante ao dos demais sistemas operacionais. O detalhe que as opes disponveis podem variar em funo do item clicado, devido a esse fato esse tipo de menu no Android chamado do Menu de Contexto ou Context Menu.
No Android possumos o Menu de contexto. Ele nos d conforto ao tratar um item especfico, abrindo um menu exclusivo para tal.
Para avisarmos ao Android que uma view possui um menu de contexto associado precisamos registr-la utilizando o mtodo registerForContextMenu(aReferenciaParaAView) da classe Activity.
Em nossa aplicao queremos que o clique longo na ListView que contm a listagem culmine com a abertura do menu de contexto. Vamos ento registrar nossa listagem: 1 2 3 4 5 6 7 8 9 10 11 public class ListaAlunos extends Activity {
lista = (ListView) findViewById(R.id.lista); //...
12 13 14 registerForContextMenu(lista); } Mas quais sero os itens que aparecero no menu de contexto quando clicarmos na listagem?
Quando fazemos um clique longo em uma View registrada para Menu de Contexto, o Android invoca o mtodo onCreateContextMenu da Activity que estiver rodando. Para customizar o contedo do menu de contexto utilizaremos esse mtodo de maneira muito parecida com a criao dos itens do Options Menu: 1 2 3 4 5 6 7 8 9 10 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
menu.add("Ligar"); menu.add("Enviar SMS"); menu.add("Achar no Mapa"); menu.add("Navegar no site"); menu.add("Deletar"); menu.add("Enviar E-mail"); } Em uma mesma tela vrias Views podem ser registradas para Menus de Contexto. Nesse caso talvez precisssemos criar menus diferenciados para cada uma delas. Pensando exatamente nesse problema que o mtodo onCreateContextMenu recebe uma View passada como argumento. Podemos verificar qual View foi criada e programaticamente criar menus diferentes em funo da View clicada.
O comportamento de clique no item do menu de contexto pode ser criado no ato de criao desse item. Quando adicionamos programaticamente um item no menu de contexto criado um MenuItem ao qual podemos associar um Listener: 1 2 3 4 //... menu.add("Navegar no site");
MenuItem deletar = menu.add("Deletar"); 5 6 7 8 9 10 11 deletar.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { //... comportamento do clique em deletar return false; } }); Podemos tambm optar pela criao dos itens do menu atravs de xml. Poderamos fazer a mesma abordagem que vimos com o MenuInflater, declarando um XML com suas opes, batizando cada uma com um id em particular: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/ligar" android:title="Ligar"/> <item android:id="@+id/sms" android:title="Enviar SMS"/> <item android:id="@+id/mapa" android:title="Achar no Mapa"/> <item android:id="@+id/site" android:title="Navegar no Site"/> <item android:id="@+id/deletar" android:title="Deletar"/> <item android:id="@+id/email" android:title="Enviar E-mail"/> </menu> 21 No onCreateContextMenu basta fazer tambm getMenuInflater().inflate(R.menu.menu_contexto, menu).
Para lidarmos com o clique no item do menu de contexto podemos sobrescrever o mtodo onContextItemSelected e, baseado no id que demos para o item do menu podemos ter um comportamento diferenciado. 1 2 3 4 5 6 7 8 9 10 @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.deletar: //??? qual aluno ??? break; }
return super.onContextItemSelected(item); } O problema no caso da deleo que no sabemos qual item da lista foi clicado quando o menu de contexto aparece.
Removendo o aluno selecionado utilizando o Context Menu
J possumos o mtodo deleta em nosso AlunoDAO e j criamos um menu de contexto para o clique no item da ListView que contm os alunos cadastrados. Agora basta descobrirmos o aluno que foi selecionado para deleo.
Sabemos que o usurio far um clique longo no item da ListView para disparar a criao do Menu de Contexto podemos alterar a implementao do OnItemLongClickListener para guardarmos o aluno selecionado em um atributo de nossa ListaAlunosActivity. No mtodo onCreate da ListaAlunosActivity: 1 2 listaAlunos.setOnItemLongClickListener(new OnItemLongClickListener() { @Override 3 4 5 6 7 8 9 10 public boolean onItemLongClick(AdapterView<?> adapter, View view, int posicao, long id) {
// guarda aluno escolhido em atributo alunoSelecionado = (Aluno) adapter.getItemAtPosition(posicao); return false; } }); Note que importante recarregar a lista, para que o elemento deletado no aparea na tela. Explicao J possumos a capacidade de listar e inserir alunos em nossa aplicao.
Vamos agora prepar-la para alterar o dados do aluno e apagar um aluno!
Agora desejamos deletar um aluno de nossa listagem, podemos criar um mtodo em nosso DAO que deleta um aluno passado como argumento: 1 2 3 4 public void deletar(Aluno aluno) { String[] args = { aluno.getId().toString() }; getWritableDatabase().delete(TABELA, "id=?", args); } Quando vamos invocar esse mtodo?
Vamos pensar na usabilidade de nossa aplicao. Quando clicamos no item da lista de alunos somos redirecionados para a o formulrio de cadastro para fazer a alterao do aluno clicado.
Normalmente em sistemas operacionais o clique simples em um item na tela significa a seleo do item. Quando desejamos outras opes de aes em um item normalmente o que fazemos clicar nele com o boto direito e esperamos que um menu de opes aparea para que possamos escolher qual ao desejamos.
No Android no temos boto direito mas esse papel nos devices realizado pelo clique longo. Podemos fazer com que o clique longo em um item cause a abertura de um menu de opes semelhante ao dos demais sistemas operacionais. O detalhe que as opes disponveis podem variar em funo do item clicado, devido a esse fato esse tipo de menu no Android chamado do Menu de Contexto ou Context Menu.
No Android possumos o Menu de contexto. Ele nos d conforto ao tratar um item especfico, abrindo um menu exclusivo para tal.
Para avisarmos ao Android que uma view possui um menu de contexto associado precisamos registr-la utilizando o mtodo registerForContextMenu(aReferenciaParaAView) da classe Activity.
Em nossa aplicao queremos que o clique longo na ListView que contm a listagem culmine com a abertura do menu de contexto. Vamos ento registrar nossa listagem: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class ListaAlunos extends Activity {
lista = (ListView) findViewById(R.id.lista); //...
registerForContextMenu(lista); } Mas quais sero os itens que aparecero no menu de contexto quando clicarmos na listagem?
Quando fazemos um clique longo em uma View registrada para Menu de Contexto, o Android invoca o mtodo onCreateContextMenu da Activity que estiver rodando. Para customizar o contedo do menu de contexto utilizaremos esse mtodo de maneira muito parecida com a criao dos itens do Options Menu: 1 public void onCreateContextMenu(ContextMenu menu, View view, 2 3 4 5 6 7 8 9 10 ContextMenuInfo menuInfo) {
menu.add("Ligar"); menu.add("Enviar SMS"); menu.add("Achar no Mapa"); menu.add("Navegar no site"); menu.add("Deletar"); menu.add("Enviar E-mail"); } Em uma mesma tela vrias Views podem ser registradas para Menus de Contexto. Nesse caso talvez precisssemos criar menus diferenciados para cada uma delas. Pensando exatamente nesse problema que o mtodo onCreateContextMenu recebe uma View passada como argumento. Podemos verificar qual View foi criada e programaticamente criar menus diferentes em funo da View clicada.
O comportamento de clique no item do menu de contexto pode ser criado no ato de criao desse item. Quando adicionamos programaticamente um item no menu de contexto criado um MenuItem ao qual podemos associar um Listener: 1 2 3 4 5 6 7 8 9 10 11 //... menu.add("Navegar no site");
MenuItem deletar = menu.add("Deletar"); deletar.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { //... comportamento do clique em deletar return false; } }); Podemos tambm optar pela criao dos itens do menu atravs de xml. Poderamos fazer a mesma abordagem que vimos com o MenuInflater, declarando um XML com suas opes, batizando cada uma com um id em particular: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/ligar" android:title="Ligar"/> <item android:id="@+id/sms" android:title="Enviar SMS"/> <item android:id="@+id/mapa" android:title="Achar no Mapa"/> <item android:id="@+id/site" android:title="Navegar no Site"/> <item android:id="@+id/deletar" android:title="Deletar"/> <item android:id="@+id/email" android:title="Enviar E-mail"/> </menu> No onCreateContextMenu basta fazer tambm getMenuInflater().inflate(R.menu.menu_contexto, menu).
Para lidarmos com o clique no item do menu de contexto podemos sobrescrever o mtodo onContextItemSelected e, baseado no id que demos para o item do menu podemos ter um comportamento diferenciado. 1 2 3 4 @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.deletar: 5 6 7 8 9 10 //??? qual aluno ??? break; }
return super.onContextItemSelected(item); } O problema no caso da deleo que no sabemos qual item da lista foi clicado quando o menu de contexto aparece.
Removendo o aluno selecionado utilizando o Context Menu
J possumos o mtodo deleta em nosso AlunoDAO e j criamos um menu de contexto para o clique no item da ListView que contm os alunos cadastrados. Agora basta descobrirmos o aluno que foi selecionado para deleo.
Sabemos que o usurio far um clique longo no item da ListView para disparar a criao do Menu de Contexto podemos alterar a implementao do OnItemLongClickListener para guardarmos o aluno selecionado em um atributo de nossa ListaAlunosActivity. No mtodo onCreate da ListaAlunosActivity: 1 2 3 4 5 6 7 8 9 10 listaAlunos.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapter, View view, int posicao, long id) {
// guarda aluno escolhido em atributo alunoSelecionado = (Aluno) adapter.getItemAtPosition(posicao); return false; } }); Note que importante recarregar a lista, para que o elemento deletado no aparea na tela.
Seguindo a mesma filosofia j estudada, a busca por id ser uma query passando a String id=? como argumento, e o prximo parmetro uma array de string que contm um nico element, o id que procuramos: 1 2 String[] args = {id.toString()}; Cursor c = getWritableDatabase().query(TABELA, COLS, "id=?",args , null, null, null); Agora basta mover o cursor para o primeiro resultado e popular um novo aluno com seus dados: 1 2 3 4 5 6 7 8 9 10 11 12 c.moveToFirst();
c.close(); Esse cdigo pode ficar dentro do nosso DAO, em um mtodo como getAlunoPorId(Long id). Como comum popularmos uma entidade atravs dos dados adquiridos no cursor, pode ser interessante isolar esse cdigo em um mtodo auxiliar, assim como possvel fazer para gerar um ContentValues a partir de um Aluno e evitar repetio.