Você está na página 1de 29

Comeando a desenvolver aplicativos para Android

23 de maro de 2010 1 comentrio


Este post o primeiro de uma srie em que vou ensinar, passo a passo, como criar um
aplicativo para a plataforma android.
Android a plataforma do google para dispositivos mveis que equipa um grande nmero
de telefones no mercado. (g1, motorola dext, milestone, nexus one)
O que preciso para comear a desenvolver para android?
Uma idia e fora de vontade. E claro, saber programar em Java. Voc NO precisa de um
hardware (telefone) para isso. A grande maioria dos testes pode ser feito no emulador!
Alm disso, Android uma plataforma de cdigo aberto e o desenvolvimento de programas
amplamente incentivado pelo Google (e pela Motorola, como vamos ver no final do post).
Por onde comear?
O primeiro passo montar seu ambiente de desenvolvimento.
1) Montar o ambiente padro fornecido pelo Google. Para isso, voc precisar seguir os
seguintes passos:
- Instalar o Eclipse (www.eclipse.org)
- Instalar o Android SDK (developer.android.com/sdk)
- Instalar o ADT Plugin (developer.android.com/sdk/eclipse-adt.html)
Todos os links contm as instrues para instalao dos componentes. Caso haja dvidas,
coloque nos comentrios!
DICA: Voc pode economizar os passos acima usando o ambiente do Motodev que
basicamente a juno de todos os passos acima e mais algumas ferramentas. Para instalar
o Motodev Studio v at a pgina http://developer.motorola.com/docstools/motodevstudio/
importante dizer que os aplicativos gerados pelo Motodev Studio funcionaro em todos
os telefones, e no s em telefones Motorola.

Criando um projeto Android (Helloworld!)


No artigo da semana passada vimos como montar o ambiente de desenvolvimento android.
Caso seu ambiente ainda no esteja funcionando, volte l e veja o que faltou.
Hoje iremos criar nosso primeiro projeto android o nosso Helloworld.

Passo 1 Criando o projeto no Eclipse


Abra o Eclipse, v at File>New>Project
Na tela que aparecer, escolha Android Project e clique em Next.

Criando um "Android Project"


Aps isso, ir aparecer a tela com as configuraes de seu projeto android.
Nesta tela, voc precisa inserir os seguintes dados:

Project name - o nome do projeto no eclipse.


Build Target a verso do Android para a qual o seu projeto ser direcionado.
Application name o nome da sua aplicao o nome que aparecer no telefone.
Package name - o package no qual sero criadas as suas classes java.
Create Activity Marque este checkbox e coloque um nome na caixa de texto.
frente explicarei o que uma Activity.

Depois disso, basta clicar em Finish.

Configurando o projeto android

Passo 2 Imprimindo um texto


Aps isso, ser criado um novo projeto e dentro dele,
na pasta src/<nome_do_package>/ voc encontrar um
arquivo .java com o nome da Activity que voc
colocou no passo anterior.
Para fazer a sua aplicao imprimir um texto na tela,
modifique este arquivo dessa forma:
view plaincopy to clipboardprint?

1. package br.com.felipesilveira.hello_world;
2.
3. import android.app.Activity;
4. import android.os.Bundle;
5. import android.widget.TextView;
6.
7. public class HelloWorld extends Activity {
8.
/** Called when the activity is first created. */
9.
@Override
10. public void onCreate(Bundle savedInstanceState) {
11.
super.onCreate(savedInstanceState);
12.
TextView view = new TextView(this);
13.
view.setText("Hello, Android");
14.
setContentView(view);
15.
16. }
17. }

Parte 3 Rodando a aplicao no emulador


Para rodar nosso recm criado programa no emulador do google, v at Run>Run as
Android Application. Uma instncia do emulador ser criada, com o nosso HelloWorld
rodando.

O que uma Activity?


Neste HelloWorld tivemos contato com o primeiro elemento de um cdigo android: A
Activity.
Uma Activity basicamente uma classe gerenciadora de UI (Interface com o usurio).
Todo aplicativo android comea por uma Activity. Para saber mais, veja a documentao

da classe Activity. Nos prximos artigos falaremos bastante sobre ela, suas caractersticas,
seu ciclo de vida e como manipul-la corretamente.
DICA: Alm de rodar a aplicao, voc pode explorar um pouco o emulador, para
conhecer o sistema operacional Android, caso ainda no conhea. Durante o
desenvolvimento, o emulador ser seu melhor amigo, ento essa a oportunidade para
conhec-lo bem.

Trabalhando com layouts XML em Android


Ol pessoal, hoje vou falar sobre a definio do layout de sua aplicao Android usando
XML.
Definir os layouts atravs dessa tcnica a forma mais comum de se comear o
desenvolvimento de uma aplicao.
Para exemplificar os estudos que faremos a partir de agora, usaremos uma aplicao de
exemplo, que construiremos juntos, a partir dos prximos posts.
A idia fazer uma aplicao onde o usurio poder entrar com algumas anotaes, e
visualizar as ltimas entradas.
O layout ser mais ou menos assim:
Criando o main.xml
Para novos projetos android, o arquivo main.xml j
automaticamente criado. Ele fica no diretrio res/layout,
com o contedo:
view plaincopy to clipboardprint?
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.andr
oid.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. <TextView
8. android:layout_width="fill_parent"
9. android:layout_height="wrap_content"
10. android:text="@string/hello"
11. />
12. </LinearLayout>

Neste arquivo temos contato com os primeiros elementos de um arquivo de layout XML:

LinearLayout, que apenas um container.


TextView, que um elemento de texto. Nesse caso est imprimindo a string cujo id
@string/hello. (No se preocupe, falaremos sobre strings e seus ids frente nesse
curso)

Para criar um layout parecido com o rascunho do incio do post, iremos inserir outros dois
elementos:

EditText uma caixa de texto onde o usurio ir entrar com as anotaes;


ListView uma lista de anotaes previamente submetidas.

Assim, o nosso novo XML:


view plaincopy to clipboardprint?
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. <EditText
8. android:id="@+id/edit_box"
9. android:layout_width="fill_parent"
10. android:layout_height="wrap_content"
11. android:text="Nova nota..."
12. >
13. </EditText>
14. <ListView
15. android:id="@+id/notes_list"
16. android:layout_width="fill_parent"
17. android:layout_height="wrap_content"
18. >
19. </ListView>
20. </LinearLayout>

Carregando o arquivo XML na aplicao


Para que a nossa aplicao tenha o layout definido pelo arquivo XML, preciso carreg-lo.
Isso feito atravs da funo setContentView(), como no cdigo abaixo:
view plaincopy to clipboardprint?
1. public void onCreate(Bundle savedInstanceState) {
2.
super.onCreate(savedInstanceState);
3.
setContentView(R.layout.main);
4. }

O parmetro R.layout.main indica que o arquivo de layout a ser carregado o main.xml.


(Se o se arquivo se chamar abobrinha.xml, o parmetro dever ser R.layout.abobrinha)
possvel utilizar mais de um arquivo XML para uma mesma tela, para formar layouts
mais sofisticados. Trataremos disso frente nesse curso.
Compilando o nosso projeto e rodando no emulador, temos o seguinte resultado:

QuickNotes rodando no emulador


No prximo post iremos acrescentar um boto a este layout, e iremos aprender um pouco
mais sobre os parmetros de um documento XML.
DICA: Existe uma ferramenta online, gratuita, para edio de arquivos de layout XML. o
DroidDraw.
LEITURA RECOMENDADA: Para aprender mais sobre a definio de layout de
aplicaes android, visite a pgina User Interface da documentao oficial. (em ingls)

Adicionando um boto a um layout android


Para adicionar um boto clicvel ao nosso layout, usaremos o widget Button.
Queremos que ele fique ao lado esquerdo da caixa de texto. Como fazer isso?
1. Diminuir o tamanho da caixa de texto. Para fazer isso, s alterar a propriedade
android:layout_width. Originalmente o valor dela era fill_parent isso quer
dizer: ocupe todo o espao disponvel. Ao invs disso, vamos usar 240 pixels.
2. Inserir o boto logo aps a caixa de texto.
3. Inserir um novo LinearLayout que ir conter a caixa de texto e o boto. Isso
necessrio porque o LinearLayout que definimos anteriormente (e que ocupa toda a
tela) tem a propriedade android:orientation=vertical. Essa propriedade faz com
que seus elementos sejam dispostos verticalmente (um debaixo do outro) e no
isso que queremos para estes dois elementos (a caixa de texto e o boto queremos
que fiquem lado a lado).
Assim, temos o nosso novo main.xml:
view plaincopy to clipboardprint?
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="fill_parent"
4. android:layout_height="fill_parent"
5. android:orientation="vertical"
6. >
7. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
8. android:layout_width="fill_parent"
9. android:layout_height="fill_parent"
10. >
11. <EditText
12. android:id="@+id/edit_box"
13. android:layout_width="240px"
14. android:layout_height="wrap_content"
15. android:text="Nova nota..."
16. >
17. </EditText>
18. <Button
19. android:id="@+id/insert_button"
20. android:layout_width="80px"
21. android:layout_height="wrap_content"
22. android:text="Inserir"
23. >
24. </Button>
25. </LinearLayout>
26. <ListView
27. android:id="@+id/notes_list"
28. android:layout_width="fill_parent"

29. android:layout_height="wrap_content"
30. >
31. </ListView>
32. </LinearLayout>
Compilando as alteraes, temos a seguinte tela:

Novo layout da aplicao android - agora com o boto "Inserir"


No prximo post veremos como controlar o boto de inserir.

Activity o que isso?


Hoje iremos conhecer uma das mais importantes classes de uma aplicao Android: A
classe Activity.
No post Criando um projeto Android (Helloworld!) comecei a falar sobre ela:
Uma Activity basicamente uma classe gerenciadora de UI (Interface com o usurio).
Todo aplicativo android comea por uma Activity.
Ou seja, quando uma aplicao android executada, na verdade a sua Activity principal
que lanada.

Ciclo de vida de uma Activity


Uma das coisas que importante conhecer sobre a Activity o seu ciclo de vida. E para
explic-lo, nada melhor do que o seguinte diagrama*:

Ciclo de vida de uma Activity


Este diagrama de fundamental importncia para o correto entendimento do
funcionamento de uma aplicao android. Ele introduz, implicitamente, os estados que uma
Activity pode estar, os quais explico no desenho abaixo:

Estados de uma Activity


Voltando ao diagrama do ciclo de vida, temos as seguintes funes:

onCreate() a primeira funo a ser executada quando uma Activity lanada.


Geralmente a responsvel por carregar os layouts XML e outras operaes de
inicializao. executada somente uma vez durante a vida til da Activity.

onStart() chamada imediatamente aps a onCreate() e tambm quando uma


Activity que estava em background volta a ter foco.
onResume() Assim como a onStart(), chamada na inicializao da Activity (logo
aps a prpria onStart()) e tambm quando uma Activity volta a ter foco. Qual a
diferena entre as duas? A onStart() s chamada quando a Activity no estava
mais visvel na tela e volta a ter o foco, enquanto a onResume() sempre chamada
nas retomadas de foco.
onPause() a primeira funo a ser invocada quando a Activity perde o foco (ou
seja, uma outra Activity vem frente).

onStop() Anloga onStart(), s chamada quando a Activity fica completamente


encoberta por outra Activity (no mais visvel).

onDestroy() A ltima funo a ser executada. Depois dela, a Activity considerada


morta ou seja, nao pode mais ser relanada. Se o usurio voltar a requisitar essa
Activity, outro objeto ser contrudo.
onRestart() Chamada imediatamente antes da onStart(), quando uma Activity volta
a ter o foco depois de estar em background.

Executando uma Activity


J sabemos que quando a sua aplicao executada, a Activity definida como padro (na
criao do projeto) lanada. Mas eu posso criar outras Activities?
claro que sim.

E para executar outras Activities, basta usar as funes startActivity() e


startActivityForResult(). No exemplo abaixo, lanamos uma segunda Activity a partir da
principal, e esperamos um resultado dela como se fosse um retorno de funo.
view plaincopy to clipboardprint?
1. static final int PICK_CONTACT_REQUEST = 0;
2.
3. @Override
4. public void onCreate(Bundle savedInstanceState) {
5.
super.onCreate(savedInstanceState);
6.
setContentView(R.layout.main);
7.
startActivityForResult(
8.
new Intent(Intent.ACTION_CONTACT_REQUEST,
9.
new Uri("content://contacts")),
10.
CONTACT_REQUEST);
11. }
12.
13. protected void onActivityResult(int requestCode, int resultCode,
14.
Intent data) {
15.
if (requestCode == CONTACT_REQUEST) {
16. if (resultCode == RESULT_OK) {
17.
// fazer alguma coisa...
18. }
19. }
Quando a segunda Activity terminar a sua execuo, a funo onActivityResult() ser
invocada, com o resultado como parmetro.
Mas como uma Activity define o seu resultado, a ser lido por aquela que a chamou?
Isso feito invocando-se a funo setResult (int resultCode), como por exemplo:
1. setResult(Intent.RESULT_OK);
Algum percebeu que eu no disse nada sobre os parmetros da startActivityForResult()?
Isso porque este o assunto do meu prximo post o mecanismo de Uris em Android.
At l!

Criando uma Activity secundria


6 de maio de 2010 5 comentrios
No post passado vimos como lanar uma Activity a partir de outra, usando as funes
startActivity() e startActivityForResult().
Hoje usaremos esta tcnica para mostrar ao usurio uma tela de Boas Vindas na nossa
aplicao de exemplo, o QuickNotes.

Para criar essa nova Activity, usaremos alguma funes do Motodev. Se voc no est
usando a IDE da Motorola, no tem problema s criar os arquivos manualmente. Porm
recomendo o uso da IDE, por facilitar bastante a nossa vida.
Vamos comear criando a Activity que dar Boas Vindas ao usurio.
V at o menu MOTODEV >New > New Android Activity. Na tela de configurao,
entre com o nome da Activity a ser criada:

Configurando a Activity a ser criada


Aps clicar em Finish, j haver a classe WelcomeActivity no diretrio src do nosso
projeto.
Com a Activity criada, o prximo passo criar o arquivo XML que definir o seu layout.
Crie o arquivo welcome.xml no diretorio res/layout com o seguinte contedo:
view plaincopy to clipboardprint?
1. <?xml version="1.0" encoding="utf-8"?>
2. <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="fill_parent"
4. android:layout_height="fill_parent"
5. >
6. <TextView android:id="@+id/welcome_text_view"
7. android:layout_width="fill_parent"
8. android:layout_height="300dip"
9. android:gravity="center"
10. android:text="Bem vindo aplicao QuickNotes!\n\nEssa aplicao foi feita duran
te o curso
11. 'Desenvolvendo para Android' do site felipesilveira.com.br"
12. >
13. </TextView>

14. <Button
15. android:id="@+id/welcome_ok_button"
16. android:layout_width="fill_parent"
17. android:layout_height="wrap_content"
18. android:text="Continuar"
19. >
20. </Button>
21. </TableLayout>
Este arquivo XML define uma Activity com um texto e um boto logo abaixo, com a
palavra Continuar.
Aps criado o arquivo, vamos carreg-lo no mtodo onCreate() da WelcomeActivity():
1. setContentView(R.layout.welcome);

Lanando a WelcomeActivity
Para lanar a WelcomeActivity a partir da MainActivity, usaremos a funo startActivity().
Esta funo recebe como parmetro um Intent. Posteriormente iremos aprofundar nosso
conhecimento sobre essa importante classe, mas por enquanto o que voc precisa saber
que ela usada para fazer a comunicao entre Activities.
No cdigo abaixo instanciamos um Intent cuja nica funo lanar a WelcomeActivity, e
ento o usamos como parmetro para a startActivity.
Dessa forma, o cdigo da MainActivity fica assim:
view plaincopy to clipboardprint?
1. package br.com.felipesilveira.quicknotes;
2.
3. import android.app.Activity;
4. import android.os.Bundle;
5. import android.content.Intent;
6.
7. public class MainActivity extends Activity {
8.
/** Called when the activity is first created. */
9.
@Override
10. public void onCreate(Bundle savedInstanceState) {
11.
super.onCreate(savedInstanceState);
12.
setContentView(R.layout.main);
13.
14.
Intent i = new Intent(this, WelcomeActivity.class);
15.
startActivity(i);
16. }
17. }

Tratando os eventos de um boto


At agora, j temos a Activity secundria sendo lanada, mas o que deve acontecer quando
o usurio clicar no boto Continuar?
A WelcomeActivity deve morrer - Dessa forma, a ltima Activity instanciada ser mostrada
novamente que por sinal a nossa MainAcitivity!
Para fazer isso, devemos adicionar um listener ao boto para que o mtodo finish() seja
invocado ao clique do usurio. O mtodo finish() da classe Activity fora a morte desta.
O cdigo da WelcomeActivity fica assim:
view plaincopy to clipboardprint?
1. package br.com.felipesilveira.quicknotes;
2.
3. import android.app.Activity;
4. import android.os.Bundle;
5. import android.view.View;
6. import android.widget.Button;
7.
8. public class WelcomeActivity extends Activity {
9.
/**
10. * @see android.app.Activity#onCreate(Bundle)
11. */
12. @Override
13. protected void onCreate(Bundle savedInstanceState) {
14.
super.onCreate(savedInstanceState);
15.
setContentView(R.layout.welcome);
16.
17.
final Button button = (Button) findViewById(R.id.welcome_ok_button);
18.
19.
button.setOnClickListener(new View.OnClickListener() {
20.
public void onClick(View v) {
21.
finish();
22.
}
23.
});
24. }
25. }
Executando nosso projeto, temos a seguinte tela:

WelcomeActivity sendo executada

Trabalhando com logs em android


13 de maio de 2010 Sem comentrios
Hoje irei falar sobre um mecanismo simples porm muito til para uma aplicao android:
os logs.
Os logs permitem ao desenvolvedor debugar erros durante o desenvolvimento e tambm
investigar problemas com o software em produo, ou seja, com o usurio final.
Para este fim, android tem um classe especfica: A classe Log (android.util.Log).
Para criar os log, temos disposio as funes Log.v(), Log.d(), Log.i(), Log.w(), r
Log.e().
Mas por que tantas funes?
Porque os log em java tem alguns tipos ou nveis so eles:

DEBUG logs impressos pela funo Log.d()


ERROR logs impressos pela funo Log.e()
INFO logs impressos pela funo Log.i()
VERBOSE logs impressos pela funo Log.v()
WARN logs impressos pela funo Log.w()

Todas estas funes recebem como parmetros duas strings a primeira, chamada de TAG,
e a segunda que a mensagem em si. A TAG uma string que ir identificar a sua
aplicao, tornando mais fcil identificar quais logs foram impressos por ela. (Todas as
aplicaes imprimem o log no mesmo stream. Assim, a nica forma de separar os seus logs
filtrando pela sua Tag)
uma boa prtica definir a TAG como uma string constante:
view plaincopy to clipboardprint?
1. private static final String TAG = "QuickNotesMainActivity";
Dessa forma, para imprimir um log de DEBUG basta usar a linha abaixo:
view plaincopy to clipboardprint?
1. Log.d(TAG, "mensagem de debug");

Visualizando logs pelo DDMS


Para visualizar os logs de nossa aplicao, usaremos o DDMS. Abrindo a aba Logcat,
temos a seguinte tela:

Lendo logs pelo logcat

No ponto 1 marcado na imagem, temos os botes de filtragem de nveis. Estes botes


permitem que voc escolha quais logs quer ver DEBUG, por exemplo. J no ponto 3,
voc pode escrever um texto, que ser um filtro para os logs. Por exemplo, se digitar
QuickNotesMainActivity, ir ver s os logs que ns colocamos no cdigo acima.
Finalmente, no ponto 2 temos a mensagem de log em si.
DICA: Seja cuidadoso com os logs. Eles podem interferir na performance de sua aplicao
se, por exemplo, forem colocados dentro de um loop.

Content Providers
Os Content Providers so parte importantssima da arquitetura de um sistema android.
responsabilidade deles prover s aplicaes o contedo que elas precisam para funcionar,
ou seja, os dados.
Mas por que so realmente necessrios?
As aplicaes poderiam muito bem acessar diretamente um banco de dados, por exemplo.
Porm, uma boa prtica tornar o modo como os dados so gravados transparente
aplicao. Dessa forma, a aplicao pode manter o foco nas interaes com o usurio.
Alm disso, essa tcnica permite a criao de Shared Content Providers, que so providers
pblicos que podem ser acessados por vrias aplicaes. Por exemplo, existe o content
provider de SMS/MMS que permite a qualquer aplicao ler as mensagens recebidas por
um telefone celular.
E como feita a comunicao entre Content Providers e Aplicaes?
Uri. Guarde bem este nome, pois voc ir precisar muito dele durante a sua carreira como
desenvolvedor android.
Toda a comunicao entre aplicaes e providers feita atravs dos mtodos da interface
ContentProvider, que sempre recebem um objeto Uri como parmetro. O formato da
Uri definido pelo content provider. Por exemplo, a Uri content://sms/inbox acessa as
mensagens de inbox no Content Provider de SMS. Falaremos um pouco mais sobre as Uris
a seguir, mas primeiro, vamos conhecer os mtodos que usaremos para envi-las para o
provider:

query(Uri, String[], String, String[], String)-

usado para recuperar

dados.

insert(Uri, ContentValues) usado para inserir dados.


update(Uri, ContentValues, String, String[]) usado

para atualizar

dados.

delete(Uri, String, String[]) usado para deletar dados.


getType(Uri) usado para obter o MIME type de certo dado.

O QuickNotes Content Provider


Depois dessa rpida introduo, vamos colocar a mo na massa.
Iremos criar um content provider para o QuickNotes, que servir para gravar e recuperar as
anotaes do usurio, da seguinte forma:

Intencionalmente coloquei a caixa que


define como o provider ir gravar os dados para mostrar que isso irrelevante para a
aplicao.

A estrutura das URIs


Uma Uri usada para acessar Content Provider segue o formato:
content://<authority>/<parametro1>/<parametro2>//<parametroN>
Onde authority o nome do provider, e os parmetros so aqueles definidos pelo
provider. Por exemplo, a seguinte Uri:
content://sms/conversations/10
Acessa o Content Provider de SMS, e seleciona a conversation de Id nmero 10.

Criando um Content Provider


Para criar seu prprio content provider, preciso fazer 2 coisas:
1. Criar uma sub-classe da ContentProvider, implementando os mtodos pblicos que
eu citei no comeo do artigo;
2. Registrar o provider no AndroidManifest.xml
Vamos comear criando a classe QuickNotesProvider:
view plaincopy to clipboardprint?
1. package br.com.felipesilveira.quicknotes;
2.
3. import android.content.ContentProvider;
4. import android.net.Uri;

5. import android.content.ContentValues;
6. import android.database.Cursor;
7.
8. public class QuickNotesProvider extends ContentProvider {
9.
// Aqui definimos os formatos possveis de Uri que
10. // o nosso provider ir aceitar.
11. public static final Uri CONTENT_URI = Uri
12. .parse("content://br.com.felipesilveira.quicknotes.quicknotesprovider");
13.
14. @Override
15. public int delete(Uri uri, String selection, String[] selectionArgs) {
16.
return 0;
17. }
18.
19. @Override
20. public String getType(Uri uri) {
21.
return null;
22. }
23.
24. @Override
25. public Uri insert(Uri uri, ContentValues values) {
26.
return null;
27. }
28.
29. @Override
30. public boolean onCreate() {
31.
return false;
32. }
33.
34. @Override
35. public Cursor query(Uri uri, String[] projection, String selection,
36.
String[] selectionArgs, String sortOrder) {
37.
return null;
38. }
39.
40. @Override
41. public int update(Uri uri, ContentValues values, String selection,
42.
String[] selectionArgs) {
43.
return 0;
44. }
45. }
Agora, vamos registrar o nosso provider no AndroidManifest, adicionando a seguinte linha
entre as tags <application > e </application>
<provider
android:authorities="br.com.felipesilveira.quicknotes.quicknotesprovider"
android:name=".QuickNotesProvider"/>

E assim o nosso Content Provider est pronto para receber requisies da aplicao. Ainda
no retorna nenhum resultado significativo mas isso faremos no prximo artigo, onde

ensinarei como acessar um banco de dados SQLite, para fazer esse provider realmente
efetivo.
DICA: Usando o MOTODEV Studio, a tarefa de criar um content provider fica muito mais
fcil. Basta acessar New > Android Content Provider, que um template ser criado, com
todos os mtodos! da s implementar a lgica deles.

Como usar banco de dados em uma aplicao android


Um dos grandes diferenciais da plataforma android a grande quantidade de mdulos e
APIs que as aplicaes tem disposio para usar. Eles do muito poder ao
desenvolvedores, permitindo que estes faam coisas que eram impossveis em outras
plataformas mveis.
Um dos mais importantes mdulos o SQLite. Sim, amigos, j temos um SGDB (Sistema
gerenciador de bancos de dados) instalado e pronto para usar! E exatamente o que
faremos no artigo de hoje.
No artigo anterior vimos como criar um Content Provider. Usaremos este provider para
acessar o banco de dados.
Para fazer isso, precisamos implementar os mtodos da classe ContentProvider que vimos
no artigo passado (query(), delete(), update(), etc) para prover ao usurio os mtodos
para criar, atualizar, deletar e recuperar os dados. Alm disso, usaremos a classe
SQLiteOpenHelper para gerenciar a conexo com o banco de dados.

A classe SQLiteOpenHelper
A classe SQLiteOpenHelper, como dito anteriormente, ser usada para gerenciar o banco
de dados. Para us-la, preciso criar uma subclasse implementando os mtodos abaixo:

onCreate() Este mtodo chamado quando a conexo com o banco de dados for
aberta pela primeira vez. aqui que criaremos o banco de dados, com o comando
sql CREATE.
onUpdate() Este mtodo chamado quando a verso do banco de dados muda.
Por exemplo, digamos que voc criou uma nova verso de seu aplicativo que usa
uma tabela a mais no banco de dados. Quando esta nova verso for instalada (em
um telefone que j possuir a primeira verso) este mtodo ser chamado, ento voc
poder criar apenas a nova tabela, mantendo os dados do usurio.

O cdigo
O cdigo do QuickNotesProvider fica assim, acessando o banco de dados. A seguir, eu
explico algumas coisas que podem gerar dvidas.
view plaincopy to clipboardprint?
1. package br.com.felipesilveira.quicknotes;
2.
3. import java.util.HashMap;

4.
5. import android.content.ContentProvider;
6. import android.content.ContentUris;
7. import android.content.Context;
8. import android.content.UriMatcher;
9. import android.net.Uri;
10. import android.provider.BaseColumns;
11. import android.content.ContentValues;
12. import android.database.Cursor;
13. import android.database.sqlite.SQLiteDatabase;
14. import android.database.sqlite.SQLiteOpenHelper;
15. import android.database.sqlite.SQLiteQueryBuilder;
16.
17. public class QuickNotesProvider extends ContentProvider {
18.
19. // Authority do nosso provider, a ser usado nas Uris.
20. public static final String AUTHORITY =
21.
"br.com.felipesilveira.quicknotes.quicknotesprovider";
22.
23. // Nome do arquivo que ir conter o banco de dados.
24. private static final String DATABASE_NAME = "quicknotes.db";
25.
26. // Versao do banco de dados.
27. // Este valor importante pois usado em futuros updates do DB.
28. private static final int DATABASE_VERSION = 1;
29.
30. // Nome da tabela que ir conter as anotaes.
31. private static final String NOTES_TABLE = "notes";
32.
33. // 'Id' da Uri referente s notas do usurio.
34. private static final int NOTES = 1;
35.
36. // Tag usada para imprimir os logs.
37. public static final String TAG = "QuickNotesProvider";
38.
39. // Instncia da classe utilitria
40. private DBHelper mHelper;
41.
42. // Uri matcher - usado para extrair informaes das Uris
43. private static final UriMatcher mMatcher;
44.
45. private static HashMap<string, string=""> mProjection;
46.
47. static {
48.
mProjection = new HashMap<string, string="">();
49.
mProjection.put(Notes.NOTE_ID, Notes.NOTE_ID);
50.
mProjection.put(Notes.TEXT, Notes.TEXT);
51. }
52.
53. static {

54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.

mMatcher = new UriMatcher(UriMatcher.NO_MATCH);


mMatcher.addURI(AUTHORITY, NOTES_TABLE, NOTES);
}
/////////////////////////////////////////////////////////////////
//
Mtodos overrided de ContentProvider
//
/////////////////////////////////////////////////////////////////
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = mHelper.getWritableDatabase();
int count;
switch (mMatcher.match(uri)) {
case NOTES:
count = db.delete(NOTES_TABLE, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException(
"URI desconhecida " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public String getType(Uri uri) {
switch (mMatcher.match(uri)) {
case NOTES:
return Notes.CONTENT_TYPE;
default:
throw new IllegalArgumentException(
"URI desconhecida " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
switch (mMatcher.match(uri)) {
case NOTES:
SQLiteDatabase db = mHelper.getWritableDatabase();
long rowId = db.insert(NOTES_TABLE, Notes.TEXT, values);
if (rowId > 0) {
Uri noteUri = ContentUris.withAppendedId(
Notes.CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(
noteUri, null);
return noteUri;
}
default:
throw new IllegalArgumentException(

104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.

"URI desconhecida " + uri);


}
}
@Override
public boolean onCreate() {
mHelper = new DBHelper(getContext());;
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Aqui usaremos o SQLiteQueryBuilder para construir
// a query que ser feito ao DB, retornando um cursor
// que enviaremos aplicao.
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
SQLiteDatabase database = mHelper.getReadableDatabase();
Cursor cursor;
switch (mMatcher.match(uri)) {
case NOTES:
// O Builer receber dois parametros: a tabela
// onde ser feita a busca, e uma projection // que nada mais que uma HashMap com os campos
// que queremos recuperar do banco de dados.
builder.setTables(NOTES_TABLE);
builder.setProjectionMap(mProjection);
break;
default:
throw new IllegalArgumentException(
"URI desconhecida " + uri);
}
cursor = builder.query(database, projection, selection,
selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = mHelper.getWritableDatabase();
int count;
switch (mMatcher.match(uri)) {
case NOTES:
count = db.update(NOTES_TABLE, values,
selection, selectionArgs);

154.
break;
155.
default:
156.
throw new IllegalArgumentException(
157.
"URI desconhecida " + uri);
158.
}
159.
160.
getContext().getContentResolver().notifyChange(uri, null);
161.
return count;
162.
}
163.
164.
/////////////////////////////////////////////////////////////////
165.
//
Inner Classes utilitrias
//
166.
/////////////////////////////////////////////////////////////////
167.
public static final class Notes implements BaseColumns {
168.
public static final Uri CONTENT_URI = Uri.parse("content://"
169.
+ QuickNotesProvider.AUTHORITY + "/notes");
170.
171.
public static final String CONTENT_TYPE =
172.
"vnd.android.cursor.dir/" + QuickNotesProvider.AUTHORITY;
173.
174.
public static final String NOTE_ID = "_id";
175.
176.
public static final String TEXT = "text";
177.
}
178.
179.
private static class DBHelper extends SQLiteOpenHelper {
180.
181.
DBHelper(Context context) {
182.
super(context, DATABASE_NAME, null, DATABASE_VERSION)
;
183.
}
184.
185.
/* O mtodo onCreate chamado quando o provider executado pela
186.
* primeira vez, e usado para criar as tabelas no database
187.
*/
188.
@Override
189.
public void onCreate(SQLiteDatabase db) {
190.
db.execSQL("CREATE TABLE " + NOTES_TABLE + " (" +
191.
Notes.NOTE_ID + " INTEGER PRIMARY KEY AUTOINCR
EMENT," +
192.
Notes.TEXT + " LONGTEXT" + ");");
193.
}
194.
195.
/* O mtodo onUpdate invocado quando a verso do banco de dados
196.
* muda. Assim, usado para fazer adequaes para a aplicao
197.
* funcionar corretamente.
198.
*/
199.
@Override
200.
public void onUpgrade(SQLiteDatabase db,
201.
int oldVersion, int newVersion) {

202.
203.
204.
205.
206.
207.

// Como ainda estamos na primeira verso do DB,


// no precisamos nos preocupar com o update agora.
}
}
}
</string,></string,>

Cursores
O primeiro conceito importante a se falar o conceito dos Cursores. Como voc deve
percebido, este o tipo de retorno do mtodo query(), e no por acaso: Os cursores so
apontadores de dados do banco de dados ou seja, uma interface que permite o acesso
aos dados retornados pela query enviada pelo usurio.

notifyChanges()
Em todos os mtodos em que alteramos o banco de dados (inserimos, deletamos ou
modificamos dados) importante chamar o mtodo modifyChanges(). Isso far com que as
aplicaes que estejam utilizando este conjunto de dados sejam notificadas, permitindo a
estas atualizar tambm os dados mostrados ao usurio.

Acessando um Content Provider


No artigo de hoje comearemos a integrar a nossa aplicao QuickNotes com o
QuickNotesProvider, que criamos no artigo anterior.
Vamos comear inserindo uma anotao do usurio no banco de dados. Para fazer isso, o
primeiro passo adicionar um Listener ao boto Inserir, da seguinte forma:
1. Button insertButton = (Button)findViewById(R.id.insert_button);
2. insertButton.setOnClickListener(mInsertListener);
E agora, criando o objeto mInsertListener. Ele precisa ser um objeto que implementa a
interface OnClickListener,. Assim, precisamos implementar o mtodo onClick(), que ser
chamado assim que o usurio pressionar o boto.
view plaincopy to clipboardprint?
1. // Definindo um OnClickListener para o boto "Inserir"
2. private OnClickListener mInsertListener = new OnClickListener() {
3.
public void onClick(View v) {
4.
EditText editBox = (EditText)findViewById(R.id.edit_box);
5.
addNote(editBox.getText().toString());
6.
editBox.setText("");
7.
}
8. };
No cdigo acima eu fiz uma chamada a um mtodo que ainda no est implementado o
mtodo addNote(), que recebe um String que ser inserida no banco de dados. Ele ser o

mtodo responsvel por efetivamente conversar com o content provider. Vamos


implement-lo:
view plaincopy to clipboardprint?
1.
/*
2.
* Mtodo responsvel por inserir um registro no content provider
3.
*/
4.
protected void addNote(String text) {
5.
ContentValues values = new ContentValues();
6.
values.put(QuickNotesProvider.Notes.TEXT, text);
7.
8.
getContentResolver().insert(
9.
QuickNotesProvider.Notes.CONTENT_URI, values);
10. }
Assim, a MainActivity fica dessa forma:
view plaincopy to clipboardprint?
1. package br.com.felipesilveira.quicknotes;
2.
3. import android.app.Activity;
4. import android.os.Bundle;
5. import android.view.View;
6. import android.view.View.OnClickListener;
7. import android.widget.Button;
8. import android.widget.EditText;
9. import android.content.ContentValues;
10. import android.content.Intent;
11.
12. public class MainActivity extends Activity {
13.
14. private static final String TAG = "QuickNotesMainActivity";
15.
16. /** Called when the activity is first created. */
17. @Override
18. public void onCreate(Bundle savedInstanceState) {
19.
super.onCreate(savedInstanceState);
20.
setContentView(R.layout.main);
21.
22.
Intent i = new Intent(this, WelcomeActivity.class);
23.
startActivity(i);
24.
25.
Button insertButton = (Button)findViewById(R.id.insert_button);
26.
insertButton.setOnClickListener(mInsertListener);
27.
28.
// adicionando um 'Hint' ao Editbox.
29.
EditText editBox = (EditText)findViewById(R.id.edit_box);
30.
editBox.setHint("Nova nota...");

31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52. }

}
// Definindo um OnClickListener para o boto "Inserir"
private OnClickListener mInsertListener = new OnClickListener() {
public void onClick(View v) {
EditText editBox = (EditText)findViewById(R.id.edit_box);
addNote(editBox.getText().toString());
editBox.setText("");
}
};
/*
* Mtodo responsvel por inserir um registro no content provider
*/
protected void addNote(String text) {
ContentValues values = new ContentValues();
values.put(QuickNotesProvider.Notes.TEXT, text);
getContentResolver().insert(
QuickNotesProvider.Notes.CONTENT_URI, values);
}

importante salientar que estamos apenas inserindo o dado no banco de dados no


estamos lendo-o em nenhum lugar na nossa aplicao, ainda.
Mas como saber se o dado realmente foi inserido no banco de dados?
Vou aproveitar esta pergunta para mostrar como acessar o banco de dados pelo shell do
android. Isso muito til para auxiliar no desenvolvimento de aplicaes que lidam com
banco de dados.

Acessando banco de dados atravs do shell


Para acessar o banco de dados pelo shell, iremos iniciar uma sesso com o comando adb
shell e ento usar o comando sqlite3 <caminho-do-db>. A partir da, basta usar comandos
SQL normais. Para ver a estrutura do banco de dados, o comando .schema deve ser usado.
Veja no exemplo abaixo:
$ adb shell
# sqlite3 /data/data/br.com.felipesilveira.quicknotes/databases/quicknotes.db
SQLite version 3.5.9
Enter .help for instructions
sqlite> .schema
.schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE notes (_id INTEGER PRIMARY KEY AUTOINCREMENT,text
LONGTEXT);
sqlite> select * from notes;

select * from notes;


1|teste
Como podemos ver, a primeira entrada do nosso DB est l, ento sinal que o
QuickNotesProvider est funcionando corretamente!
No prximo artigo, iremos usar o provider para ler os dados j gravados no DB para
mostr-los ao usurio. At l!

Você também pode gostar