android avançado.pdf

98
Minicurso Android Avançado Flávio Augusto de Freitas [email protected] http://flavioaf.blogspot.com

Upload: edson-morais

Post on 25-Nov-2015

422 views

Category:

Documents


2 download

TRANSCRIPT

  • Minicurso

    Android Avanado

    Flvio Augusto de Freitas

    [email protected]

    http://flavioaf.blogspot.com

  • Sumrio Passos Iniciais .................................................................................................................................................................... 3

    Montando um Ambiente de Desenvolvimento para Android ...................................................................................... 4

    Configurando um Dispositivo Android com o AVD Manager ....................................................................................... 9

    Tutoriais Avanados ........................................................................................................................................................ 12

    Persistncia em Banco de Dados ................................................................................................................................ 13

    Editando Registros do Banco de Dados ...................................................................................................................... 22

    Configurando Preferncias ......................................................................................................................................... 36

    Ajustando o Layout para Paisagem (II) ....................................................................................................................... 41

    Integrando Bibliotecas de Terceiros (Twitter) ............................................................................................................ 44

    Utilizando um IntentService........................................................................................................................................ 53

    Integrando o GPS ........................................................................................................................................................ 57

    Alterando o cone do Launcher ................................................................................................................................... 65

    Integrando com o Google Maps ................................................................................................................................. 67

    Alarmes ....................................................................................................................................................................... 69

    Notificaes ................................................................................................................................................................ 76

    Internacionalizao (i18n) ........................................................................................................................................... 78

    Widgets ....................................................................................................................................................................... 84

    Fazendo Ligaes (Chamadas) .................................................................................................................................... 91

    Terminamos .................................................................................................................................................................... 97

    Contatos .......................................................................................................................................................................... 98

  • Passos Iniciais

  • Montando um Ambiente de Desenvolvimento para Android Hoje vou mostrar como montar um ambiente de desenvolvimento para Android! Pra quem nunca ouviu falar, o

    Android um sistema operacional da Google para dispositivos mveis. Hoje em dia, milhes de celulares e tablets

    utilizam o Android como sistema.

    Uma coisa bem legal que voc pode disponibilizar seus aplicativos no Market do Android (aps o pagamento de

    uma taxa) e talvez at ganhar um dinheiro com isso! Legal, n?

    O desenvolvimento de aplicativos para Android feito utilizando a linguagem Java, com a utilizao de arquivos XML

    para a criao das interfaces. Apesar de parecer complexo, relativamente simples criar seus aplicativos. Alm disso,

    bem fcil ter acesso a diversos recursos geralmente disponveis em dispositivos mveis, tais como cmera, GPS,

    Bluetooth, etc.

    Para facilitar o desenvolvimento, foi criado um plug-in para o Eclipse. Atravs dele, fcil gerenciar as plataformas

    (diversas verses do Android) e as mquinas virtuais para executar seus aplicativos.

    Bom, ento pra comear, vamos fazer o download da JDK. Se voc j programa em Java, este passo no necessrio.

    No momento em que escrevo este tutorial, a verso mais recente a Java 7 update 2. Siga at esta pgina e faa o

    download.

    A instalao deve ocorrer sem problemas (o famoso, next, next, next, finish). O prximo passo baixar o Eclipse. V

    at esta pgina e faa o download relacionado a verso de seu sistema operacional. Para os nossos propsitos, a

    verso Eclipse IDE for Java Developers deve ser suficiente.

  • Ao concluir o download, basta descompactar o arquivo em algum lugar da sua mquina. Eu recomendo, no caso do

    Windows, na raiz C: ou em sua pasta de usurio (C:\Users\). Neste exemplo, vou referenciar a pasta

    do Eclipse como C:\eclipse.

    Prosseguindo, devemos agora baixar o Android SDK. ele quem nos fornecer todas as ferramentas da plataforma,

    como emulador, bibliotecas, etc. V at essa pgina e baixe a verso zipada da SDK (apesar de recomendarem a

    verso instalvel) isso pra evitarmos problemas de permisso na hora de baixar as SDKs, caso esteja na pasta

    de programas do sistema (Program Files ou Arquivos de Programas). No momento em que escrevo este tutorial, a

    verso mais recente a 16.

    Aps a concluso do download, descompacte o arquivo (pode ser no mesmo local onde voc colocou o Eclipse).

    Aqui, por exemplo, vai ficar C:\android-sdk-windows. Aps extrair, vamos executar o SDK Manager para baixar uma

    SDK para comearmos a programar. Ao executar pela primeira vez, o SDK Manager ir verificar os repositrios do

    Android em busca das ltimas verses do SDK.

  • Para comear, vamos baixar o SDK da verso 2.2, j que os aplicativos desenvolvidos nela funcionam na grande

    maioria dos dispositivos Android de hoje. Se quiser instalar outras verses, fique vontade. Expanda a pasta Android

    2.2 (API 8 ) e marque as opes SDK Platform. Alm disso, na categoria Tools, marque a opo Android SDK Platform-

    tools. Clique em Install 2 packages (ou mais, se voc selecionou mais alguma coisa), marque Accept All e ento

    clique em Install.

    Aps a concluso dos downloads, hora de configurar o Eclipse. V at o diretrio onde ele foi descompactado e

    execute-o.

  • Ao ser consultado sobre qual workspace utilizar, basta confirmar e utilizar o padro (workspace o local onde seus

    projetos sero salvos; ele fica na pasta C:\Users\\workspace). Vamos agora adicionar o plugin para

    integrar o SDK Manager e o AVD Manager ao Eclipse. Clique no menu Help -> Install New Software e na janela que

    abrir, clique no boto Add. Na tela seguinte, preencha o nome do plugin (ADT Plugin) e coloque o endereo

    https://dl-ssl.google.com/android/eclipse, conforme a imagem abaixo:

    Clique em OK e aguarde o carregamento do repositrio. Ao concluir, marque a caixa Developer Tools e clique em

    Next > duas vezes. Na tela seguinte, aceite os termos da licena e clique em Finish. Agora aguarde a instalao e,

    caso seja alertado sobre contedo no-assinado, clique em OK para continuar.

    Ao final, clique em Restart Now para reiniciar o Eclipse e concluir a instalao. O prximo passo configurar o local

    onde as SDKs esto. No Eclipse, v ao menu Window -> Preferences. Clique no boto Browse e aponte para a pasta

    que voc descompactou. Aps a confirmao, devero ser exibidas as SDKs que voc baixou.

  • Pronto! Seu ambiente Android j est pronto para ser utilizado! No prximo tutorial veremos como configurar um

    dispositivo para executar nossa aplicao.

  • Configurando um Dispositivo Android com o AVD Manager Ol pessoal! No ltimo tutorial sobre Android, vimos como configurar o ambiente para programarmos, utilizando o

    Eclipse. Neste tutorial, vamos ver como criar um dispositivo para a execuo dos aplicativos que sero criados.

    Assim, voc no precisa necessariamente de um celular com Android para comear a desenvolver para a plataforma.

    Bom, o primeiro passo abrir o Eclipse e clicar no cone do AVD Manager (AVD = Android Virtual Device), ou ir at o

    menu Window -> AVD Manager.

    Ser, ento, aberta a janela com a listagem de dispositivos criados (no nosso caso, nenhum ainda).

    Ento, para criarmos um novo dispositivos, clicamos no boto New. Nesta tela, devemos preencher os dados

    relativos ao nosso dispositivo, como nome (Name), verso do Android que ir executar (Target), alm de dados

    como tamanho do carto SD virtual (caso desejado), tamanho da tela e perifricos (cmera, GPS, Acelermetro,

    Teclado fsico, etc.).

  • Aps montar seu dispositivo, clique em Create AVD e ter seu dispositivo listado!

  • Quando estiver desenvolvendo, recomendvel criar diferentes tipos de dispositivos, com verses diferentes do

    Android e tamanhos de tela variados, de forma a fazer seu aplicativo ser executado corretamente em diversas

    configuraes.

  • Tutoriais Avanados

  • Persistncia em Banco de Dados Ol leitores! No tutorial de hoje, vamos criar um sistema de persistncia para a nossa Lista de Restaurantes. Assim,

    os restaurantes cadastrados sero mantidos a cada execuo do aplicativo.

    O sistema Android nos fornece nativamente as opes de persistir dados utilizando arquivos ou em banco de dados,

    utilizando o SQLite. Se voc no conhece o projeto, interessante dar uma lida sobre ele. um banco de dados

    bastante leve, que nos permite facilmente trabalhar com SQL sobre um arquivo.

    Neste tutorial, estou assumindo que voc tenha um conhecimento bsico em SQL. Se voc nunca mexeu com isso,

    no se preocupe, pois os conceitos no so complicados de entender.

    Bom, comeando o nosso tutorial, vamos criar uma classe que gerenciar a criao e abertura do nosso banco de

    dados. Vamos cham-la de GerenciadorRestaurantes. Coloque-a no pacote com.blogspot.flavioaf.restaurante.

    1 package com.blogspot.flavioaf.restaurante;

    2

    3 import android.content.Context;

    4 import android.database.sqlite.SQLiteDatabase;

    5 import android.database.sqlite.SQLiteOpenHelper;

    6

    7 public class GerenciadorRestaurantes extends SQLiteOpenHelper {

    8

    9 private static final String NOME_BANCO = "restaurantes.db";

    10 private static final int VERSAO_SCHEMA = 1;

    11

    12 public GerenciadorRestaurantes(Context context) {

    13 super(context, NOME_BANCO, null, VERSAO_SCHEMA);

    14 }

    15

    16 @Override

    17 public void onCreate(SQLiteDatabase db) {

    18 db.execSQL("CREATE TABLE restaurantes (_id INTEGER PRIMARY KEY AUTOINCREMENT,"

    19 + " nome TEXT, endereco TEXT, tipo TEXT, anotacoes TEXT);");

    20

    21 }

    22

    23 @Override

    24 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    25

    26 }

    27 }

    A princpio, definimos que nosso banco de dados ser armazenado no arquivo restaurantes.db e que utilizaremos a

    primeira verso do schema do banco. Neste ponto o projeto ainda deve compilar sem problemas.

    Em seguida, vamos implementar o mtodo onCreate() para que ele crie o nosso banco de dados.

    18 @Override

    19 public void onCreate(SQLiteDatabase db) {

    20 db.execSQL("CREATE TABLE restaurantes (_id INTEGER PRIMARY KEY AUTOINCREMENT," +

    21 " nome TEXT, endereco TEXT, tipo TEXT, anotacoes TEXT);");

    22 }

    Neste trecho simplesmente criamos a tabela restaurantes com seus campos. O mtodo onUpgrade() no ser til

    para ns por enquanto. Em um aplicativo real, voc poderia implement-lo para fazer backup dos dados em uma

    tabela temporria, atualizar a estrutura do banco e ento retornar os dados.

  • O prximo passo remover partes do cdigo da classe ListaRestaurantes que no nos sero teis daqui pra frente

    (como os trechos que manipulam a nossa barra de progresso). As primeiras excluses so os atributos estaAtivo e

    progresso. Em seguida, podemos remover a chamada ao mtodo requestWindowFeature() dentro do mtodo

    onCreate(). Podemos tambm excluir as implementaes dos mtodos onPause(), onResume(),

    onCreateOptionsMenu() e onOptionsItemSelected(). Por fim, podemos excluir tambm os mtodos iniciarTarefa(),

    fazerAlgoDemorado() e a nossa tarefaLonga.

    A classe GerenciadorRestaurantes ser a nossa ponte entre a aplicao e o banco de dados. Dessa forma, vamos

    criar um atributo na classe ListaRestaurantes chamado gerenciador do tipo GerenciadorRestaurante.

    34 GerenciadorRestaurantes gerenciador;

    L no mtodo onCreate(), aps a chamada a setContentView(), vamos ento instanciar o atributo:

    40 gerenciador = new GerenciadorRestaurantes(this);

    Complementando, implemente o mtodo onDestroy() na classe ListaRestaurantes.

    67 @Override

    68 public void onDestroy() {

    69 super.onDestroy();

    70 gerenciador.close();

    71 }

    Ns vamos agora, substituir nosso objeto de modelo (e seu ArrayList associado) pelo banco de dados, utilizando

    tambm a classe Cursor do Android para controlar as instncias. Primeiramente, vamos adicionar o mtodo inserir()

    na classe GerenciadorRestaurantes:

    27 public void inserir(String nome, String endereco, String tipo, String anotacoes) {

    28 ContentValues valores = new ContentValues();

    29

    30 valores.put("nome", nome);

    31 valores.put("endereco", endereco);

    32 valores.put("tipo", tipo);

    33 valores.put("anotacoes", anotacoes);

    34

    35 getWritableDatabase().insert("restaurantes", "nome", valores);

    36 }

    Neste mtodo, recebemos os valores individuais dos campos que compem a classe Restaurante e adicionamos a

    um objeto ContentValues, relacionando os valores com as colunas da tabela do nosso banco de dados. Por fim,

    obtemos uma instncia do banco para escrita e inserimos os valores na tabela restaurantes.

    Agora, devemos realizar a chamada a este mtodo ao pressionarmos o boto Salvar em nosso formulrio (onSave).

    93 private OnClickListener onSave = new OnClickListener() {

  • 94

    95 public void onClick(View arg0) {

    96 String tipo = null;

    97

    98 switch (tipos.getCheckedRadioButtonId()) {

    99 case R.id.rodizio:

    100 tipo = "rodizio";

    101 break;

    102 case R.id.fast_food:

    103 tipo = "fast_food";

    104 break;

    105 case R.id.a_domicilio:

    106 tipo = "a_domicilio";

    107 break;

    108 }

    109

    110 gerenciador.inserir(nome.getText().toString(),

    111 endereco.getText().toString(), tipo,

    112 anotacoes.getText().toString());

    113 }

    114 };

    Em seguida, vamos fazer com que a listagem de restaurantes seja realizada a partir do nosso banco de dados. Se

    voc j mexeu com banco de dados no Java, j deve ter visto o funcionamento de um ResultSet. Ele armazena o

    contedo de uma consulta ao banco de dados. No Android, utilizamos a classe Cursor que tem funcionamento

    semelhante.

    Assim, vamos criar um mtodo na classe GerenciadorRestaurantes para obter a lista de restaurantes salvos no

    banco. Vamos implementar o mtodo obterTodos():

    39 public Cursor obterTodos() {

    40 return getReadableDatabase().rawQuery("select id, nome, endereco, tipo, " +

    41 "anotacoes FROM restaurantes ORDER BY nome", null);

    42 }

    Precisaremos tambm de mtodos que nos forneam acesso a determinados campos do Cursor. Dessa forma,

    adicione estes mtodos classe GerenciadorRestaurantes:

    44 public String obterNome(Cursor c) {

    45 return c.getString(1);

    46 }

    47

    48 public String obterEndereco(Cursor c) {

    49 return c.getString(2);

    50 }

    51

    52 public String obterTipo(Cursor c) {

    53 return c.getString(3);

    54 }

    55

    56 public String obterAnotacoes(Cursor c) {

    57 return c.getString(4);

    58 }

    Na nossa implementao atual, a classe Adaptador estende a classe ArrayAdapter, de forma que ela no conseguir

    manipular os dados contidos no Cursor. Assim, modificaremos sua implementao para, ento, estender no mais

    ArrayAdapter, mas sim CursorAdapter.

  • 118 class AdaptadorRestaurante extends CursorAdapter {

    119 AdaptadorRestaurante(Cursor c) {

    120 super(ListaRestaurantes.this, c);

    121 }

    122

    123 @Override

    124 public void bindView(View view, Context context, Cursor cursor) {

    125 ArmazenadorRestaurante armazenador = (ArmazenadorRestaurante) view.getTag();

    126 armazenador.popularFormulario(cursor, gerenciador);

    127 }

    128

    129 @Override

    130 public View newView(Context context, Cursor cursor, ViewGroup parent) {

    131 LayoutInflater inflater = getLayoutInflater();

    132 View linha = inflater.inflate(R.layout.linha, parent, false);

    133 ArmazenadorRestaurante armazenador = new ArmazenadorRestaurante(linha);

    134 linha.setTag(armazenador);

    135 return linha;

    136 }

    137 }

    Como pode ser percebido, a classe ArmazenadorRestaurante tambm necessita de alguns ajustes, para manipular o

    objeto da classe Cursor. Mas antes, vamos modificar o atributo listaRestaurantes do tipo List para Cursor.

    28 Cursor listaRestaurantes;

    Agora, no mtodo onCreate(), substitua o cdigo que populava o antigo ArrayList por este:

    53 listaRestaurantes = gerenciador.obterTodos();

    54 startManagingCursor(listaRestaurantes);

    55 adaptador = new AdaptadorRestaurante(listaRestaurantes);

    56 lista.setAdapter(adaptador);

    Prosseguindo, vamos atualizar a classe ArmazenadorRestaurante para trabalhar com o Cursor:

    138 static class ArmazenadorRestaurante {

    139 private TextView nome = null;

    140 private TextView endereco = null;

    141 private ImageView icone = null;

    142

    143 ArmazenadorRestaurante(View linha) {

    144 nome = (TextView) linha.findViewById(R.id.titulo);

    145 endereco = (TextView) linha.findViewById(R.id.endereco);

    146 icone = (ImageView) linha.findViewById(R.id.icone);

    147 }

    148

    149 void popularFormulario(Cursor c, GerenciadorRestaurantes gerenciador) {

    150 nome.setText(gerenciador.obterNome(c));

    151 endereco.setText(gerenciador.obterEndereco(c));

    152

    153 if (gerenciador.obterTipo(c).equals("rodizio")) {

    154 icone.setImageResource(R.drawable.rodizio);

    155 } else if (gerenciador.obterTipo(c).equals("fast_food")) {

    156 icone.setImageResource(R.drawable.fast_food);

    157 } else {

  • 158 icone.setImageResource(R.drawable.entrega);

    159 }

    160 }

    161 }

    Por fim, vamos modificar todas as referncias ao ArrayList que tnhamos no nosso onListClick.

    78 private OnItemClickListener onListClick = new OnItemClickListener() {

    79 public void onItemClick(AdapterView parent, View view, int position,

    80 long id) {

    81 listaRestaurantes.moveToPosition(position);

    82 nome.setText(gerenciador.obterNome(listaRestaurantes));

    83 endereco.setText(gerenciador.obterEndereco(listaRestaurantes));

    84 anotacoes.setText(gerenciador.obterAnotacoes(listaRestaurantes));

    85

    86 if (gerenciador.obterTipo(listaRestaurantes).equals("rodizio")) {

    87 tipos.check(R.id.rodizio);

    88 } else if (gerenciador.obterTipo(listaRestaurantes).equals("fast_food")) {

    89 tipos.check(R.id.fast_food);

    90 } else {

    91 tipos.check(R.id.a_domicilio);

    92 }

    93

    94 getTabHost().setCurrentTab(1);

    95 }

    96 };

    Como ltimo passo precisamos adicionar uma linha para que a lista seja atualizada a cada insero. Insira a seguinte

    linha aps a insero l no onSave:

    117 listaRestaurantes.requery();

    Pronto! Voc j pode executar a sua verso persistente do Lista de Restaurantes!

    Segue a listagem completa da classe ListaRestaurantes:

    1 package com.blogspot.flavioaf.restaurante;

    2

    3 import com.blogspot.flavioaf.restaurante.model.Restaurante;

    4 import android.app.TabActivity;

    5 import android.content.Context;

    6 import android.database.Cursor;

    7 import android.os.Bundle;

    8 import android.view.LayoutInflater;

    9 import android.view.View;

    10 import android.view.View.OnClickListener;

    11 import android.view.ViewGroup;

    12 import android.widget.AdapterView;

    13 import android.widget.AdapterView.OnItemClickListener;

    14 import android.widget.Button;

    15 import android.widget.CursorAdapter;

    16 import android.widget.EditText;

    17 import android.widget.ImageView;

    18 import android.widget.ListView;

    19 import android.widget.RadioGroup;

    20 import android.widget.TabHost.TabSpec;

    21 import android.widget.TextView;

  • 22 public class ListaRestaurantes extends TabActivity {

    23

    24 Cursor listaRestaurantes;

    25 AdaptadorRestaurante adaptador = null;

    26 Restaurante atual = null;

    27

    28 EditText nome = null;

    29 EditText endereco = null;

    30 EditText anotacoes = null;

    31 RadioGroup tipos = null;

    32 GerenciadorRestaurantes gerenciador;

    33

    34 @Override

    35 public void onCreate(Bundle savedInstanceState) {

    36 super.onCreate(savedInstanceState);

    37 setContentView(R.layout.main);

    38 gerenciador = new GerenciadorRestaurantes(this);

    39

    40 nome = (EditText) findViewById(R.id.nome);

    41 endereco = (EditText) findViewById(R.id.end);

    42 anotacoes = (EditText) findViewById(R.id.anotacoes);

    43 tipos = (RadioGroup) findViewById(R.id.tipos);

    44

    45 Button salvar = (Button) findViewById(R.id.salvar);

    46 salvar.setOnClickListener(onSave);

    47

    48 ListView lista = (ListView) findViewById(R.id.restaurantes);

    49

    50 listaRestaurantes = gerenciador.obterTodos();

    51 startManagingCursor(listaRestaurantes);

    52 adaptador = new AdaptadorRestaurante(listaRestaurantes);

    53 lista.setAdapter(adaptador);

    54

    55 TabSpec descritor = getTabHost().newTabSpec("tag1");

    56 descritor.setContent(R.id.restaurantes);

    57 descritor.setIndicator("Lista",

    58 getResources().getDrawable(R.drawable.lista));

    59 getTabHost().addTab(descritor);

    60

    61 descritor = getTabHost().newTabSpec("tag2");

    62 descritor.setContent(R.id.detalhes);

    63 descritor.setIndicator("Detalhes",

    64 getResources().getDrawable(R.drawable.restaurante));

    65 getTabHost().addTab(descritor);

    66

    67 getTabHost().setCurrentTab(0);

    68

    69 lista.setOnItemClickListener(onListClick);

    70 }

    71

    72 @Override

    73 public void onDestroy() {

    74 super.onDestroy();

    75 gerenciador.close();

    76 }

    77

    78 private OnItemClickListener onListClick = new OnItemClickListener() {

    79 public void onItemClick(AdapterView parent, View view, int position,

    80 long id) {

    81 listaRestaurantes.moveToPosition(position);

    82 nome.setText(gerenciador.obterNome(listaRestaurantes));

    83 endereco.setText(gerenciador.obterEndereco(listaRestaurantes));

    84 anotacoes.setText(gerenciador.obterAnotacoes(listaRestaurantes));

    85

    86 if (gerenciador.obterTipo(listaRestaurantes).equals("rodizio")) {

    87 tipos.check(R.id.rodizio);

    88 } else if (gerenciador.obterTipo(listaRestaurantes).equals("fast_food")) {

    89 tipos.check(R.id.fast_food);

    90 } else {

    91 tipos.check(R.id.a_domicilio);

  • 92 }

    93

    94 getTabHost().setCurrentTab(1);

    95 }

    96 };

    97

    98 private OnClickListener onSave = new OnClickListener() {

    99

    100 public void onClick(View arg0) {

    101 String tipo = null;

    102

    103 switch (tipos.getCheckedRadioButtonId()) {

    104 case R.id.rodizio:

    105 tipo = "rodizio";

    106 break;

    107 case R.id.fast_food:

    108 tipo = "fast_food";

    109 break;

    110 case R.id.a_domicilio:

    111 tipo = "a_domicilio";

    112 break;

    113 }

    114

    115 gerenciador.inserir(nome.getText().toString(), endereco.getText()

    116 .toString(), tipo, anotacoes.getText().toString());

    117 listaRestaurantes.requery();

    118 }

    119 };

    120

    121 class AdaptadorRestaurante extends CursorAdapter {

    122 AdaptadorRestaurante(Cursor c) {

    123 super(ListaRestaurantes.this, c);

    124 }

    125

    126 @Override

    127 public void bindView(View view, Context context, Cursor cursor) {

    128 ArmazenadorRestaurante armazenador = (ArmazenadorRestaurante) view.getTag();

    129 armazenador.popularFormulario(cursor, gerenciador);

    130 }

    131

    132 @Override

    133 public View newView(Context context, Cursor cursor, ViewGroup parent) {

    134 LayoutInflater inflater = getLayoutInflater();

    135 View linha = inflater.inflate(R.layout.linha, parent, false);

    136 ArmazenadorRestaurante armazenador = new ArmazenadorRestaurante(linha);

    137 linha.setTag(armazenador);

    138 return linha;

    139 }

    140 }

    141

    142 static class ArmazenadorRestaurante {

    143 private TextView nome = null;

    144 private TextView endereco = null;

    145 private ImageView icone = null;

    146

    147 ArmazenadorRestaurante(View linha) {

    148 nome = (TextView) linha.findViewById(R.id.titulo);

    149 endereco = (TextView) linha.findViewById(R.id.endereco);

    150 icone = (ImageView) linha.findViewById(R.id.icone);

    151 }

    152

    153 void popularFormulario(Cursor c, GerenciadorRestaurantes gerenciador) {

    154 nome.setText(gerenciador.obterNome(c));

    155 endereco.setText(gerenciador.obterEndereco(c));

    156

    157 if (gerenciador.obterTipo(c).equals("rodizio")) {

    158 icone.setImageResource(R.drawable.rodizio);

    159 } else if (gerenciador.obterTipo(c).equals("fast_food")) {

    160 icone.setImageResource(R.drawable.fast_food);

    161 } else {

  • 162 icone.setImageResource(R.drawable.entrega);

    163 }

    164 }

    165 }

    166 }

    e GerenciadorRestaurantes

    1 package com.blogspot.flavioaf.restaurante;

    2

    3 import android.content.ContentValues;

    4 import android.content.Context;

    5 import android.database.Cursor;

    6 import android.database.sqlite.SQLiteDatabase;

    7 import android.database.sqlite.SQLiteOpenHelper;

    8

    9 public class GerenciadorRestaurantes extends SQLiteOpenHelper {

    10

    11 private static final String NOME_BANCO = "restaurantes.db";

    12 private static final int VERSAO_SCHEMA = 1;

    13

    14 public GerenciadorRestaurantes(Context context) {

    15 super(context, NOME_BANCO, null, VERSAO_SCHEMA);

    16 }

    17

    18 @Override

    19 public void onCreate(SQLiteDatabase db) {

    20 db.execSQL("CREATE TABLE restaurantes (_id INTEGER PRIMARY KEY AUTOINCREMENT," +

    21 " nome TEXT, endereco TEXT, tipo TEXT, anotacoes TEXT);");

    22 }

    23

    24 @Override

    25 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    26

    27 }

    28

    29 public void inserir(String nome, String endereco, String tipo, String anotacoes) {

    30 ContentValues valores = new ContentValues();

    31

    32 valores.put("nome", nome);

    33 valores.put("endereco", endereco);

    34 valores.put("tipo", tipo);

    35 valores.put("anotacoes", anotacoes);

    36

    37 getWritableDatabase().insert("restaurantes", "nome", valores);

    38 }

    39

    40 public Cursor obterTodos() {

    41 return getReadableDatabase().rawQuery("select _id, nome, endereco, tipo, " +

    42 "anotacoes FROM restaurantes ORDER BY nome", null);

    43 }

    44

    45 public String obterNome(Cursor c) {

    46 return c.getString(1);

    47 }

    48

    49 public String obterEndereco(Cursor c) {

    50 return c.getString(2);

    51 }

    52

    53 public String obterTipo(Cursor c) {

    54 return c.getString(3);

    55 }

    56

    57 public String obterAnotacoes(Cursor c) {

    58 return c.getString(4);

  • 59 }

    60 }

  • Editando Registros do Banco de Dados No ltimo tutorial, tornamos o nosso aplicativo Lista de Restaurantes persistente. No tutorial de hoje, vamos

    aprimorar a forma como ele lida com o banco de dados, fazendo com que os registros inseridos possam ser editados.

    Alm disso, tambm faremos uma mudana no visual da aplicao, retirando as abas e incluindo a tela de adio de

    restaurantes como uma opo no menu.

    O primeiro passo criarmos uma nova Activity, que ser onde ficar, a partir de agora, o nosso formulrio de

    cadastro (e consequentemente, de edio). Separaremos as funes da nossa Activity inicial. Ento, crie a classe

    FormularioDetalhes.

    1 package com.blogspot.flavioaf.restaurante;

    2

    3 import android.app.Activity;

    4 import android.os.Bundle;

    5

    6 public class FormularioDetalhes extends Activity {

    7

    8 @Override

    9 public void onCreate(Bundle savedInstanceState) {

    10 super.onCreate(savedInstanceState);

    11 }

    12 }

    Por enquanto, esta Activity no tem nenhum layout atribudo, j que ainda no criamos o seu layout.

    Antes de utilizar esta Activity em nosso projeto, precisamos declar-la no arquivo AndroidManifest.xml. Ele

    encontra-se na raiz da rvore do projeto.

  • Abra-o e selecione a aba inferior AndroidManifest.xml para abri-lo para a edio. Dentro do n application,

    adicionaremos um novo n activity.

    1

    2

    6

    7

    8

    9

    12

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

  • Prosseguindo, precisamos iniciar esta Activity quando clicarmos sobre um dos itens da lista. Assim, modifique o

    onListClick dessa forma:

    80 private OnItemClickListener onListClick = new OnItemClickListener() {

    81 public void onItemClick(AdapterView parent, View view, int position,

    82 long id) {

    83 Intent i = new Intent(ListaRestaurantes.this, FormularioDetalhes.class);

    84 startActivity(i);

    85 }

    86 };

    Se quiser testar a aplicao, ela deve exibir uma tela vazia ao clicar em algum item da lista.

    Continuando, vamos agora fazer a migrao do formulrio para a nova Activity. Primeiramente, crie o arquivo

    form_detalhes.xml na pasta res/layout, podendo utilizar o main.xml como base para ele:

    1

    2

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    19

    21

    23

    24

    25

    26

    27

    34

    35

    39

    Agora, volte a Activity FormularioDetalhes e adicione esta linha ao final do mtodo onCreate:

  • 11 setContentView(R.layout.form_detalhes);

    O prximo passo mover toda a lgica do formulrio para a nossa classe FormularioDetalhes. Primeiramente,

    adicione os atributos da classe que estavam na ListaRestaurantes para a FormularioDetalhes:

    10 EditText nome = null;

    11 EditText endereco = null;

    12 EditText anotacoes = null;

    13 RadioGroup tipos = null;

    14 GerenciadorRestaurantes gerenciador;

    Agora, copie a busca aos widgets no formulrio do mtodo onCreate() do ListaRestaurantes para o

    FormularioDetalhes, no mesmo local.

    22 gerenciador = new GerenciadorRestaurantes(this);

    23

    24 nome = (EditText) findViewById(R.id.nome);

    25 endereco = (EditText) findViewById(R.id.end);

    26 anotacoes = (EditText) findViewById(R.id.anotacoes);

    27 tipos = (RadioGroup) findViewById(R.id.tipos);

    28

    29 Button salvar = (Button) findViewById(R.id.salvar);

    30 salvar.setOnClickListener(onSave);

    Por fim, vamos copiar a implementao do nosso listener onSave para a classe FormularioDetalhes, porm retirando

    a parte que trata da insero no banco de dados:

    35 private OnClickListener onSave = new OnClickListener() {

    36

    37 public void onClick(View arg0) {

    38 String tipo = null;

    39

    40 switch (tipos.getCheckedRadioButtonId()) {

    41 case R.id.rodizio:

    42 tipo = "rodizio";

    43 break;

    44 case R.id.fast_food:

    45 tipo = "fast_food";

    46 break;

    47 case R.id.a_domicilio:

    48 tipo = "a_domicilio";

    49 break;

    50 }

    51 }

    52 };

    Agora hora de limparmos a interface original do aplicativo, no main.xml. Retiraremos o formulrio que existia e

    as abas, alm do ajuste no layout para abrigar somente a lista. O que nos resta isso:

    1

  • 2

    Aps isso, exclua a pasta layout_land e o arquivo main.xml dentro dela.

    No momento, ListaRestaurantes estende TabActivity. Porm, como modificamos a estrutura de nossa aplicao, isso

    no mais necessrio. Modifique a classe, de forma que ListaRestaurante estenda ListActivity. Em seguida,

    modifique o mtodo onCreate() para retirar os cdigos que diziam respeito s abas que utilizvamos:

    34 @Override

    35 public void onCreate(Bundle savedInstanceState) {

    36 super.onCreate(savedInstanceState);

    37 setContentView(R.layout.main);

    38

    39 gerenciador = new GerenciadorRestaurantes(this);

    40 listaRestaurantes = gerenciador.obterTodos();

    41 startManagingCursor(listaRestaurantes);

    42 adaptador = new AdaptadorRestaurante(listaRestaurantes);

    43 setListAdapter(adaptador);

    44 }

    Antes de seguirmos em frente, vamos analisar o que vamos fazer: o FormularioDetalhes ser utilizado tanto na

    criao de novos restaurantes quando na edio de restaurantes j cadastrados. Alm disso, ele precisa saber,

    quando estiver editando, qual restaurante se trata. Para isso, precisamos do identificador do restaurante (o campo

    _id do banco de dados).

    Primeiramente, vamos criar um atributo para a classe ListaRestaurantes:

    27 public final static String _ID = "com.blogspot.flavioaf.restaurante._ID";

    Aps isso, vamos mudar o objeto onListClick para um onListItemClick(), onde vamos passar o valor do id para a outra

    Activity:

    53 @Override

    54 public void onListItemClick(ListView l, View v, int position, long id) {

    55 Intent i = new Intent(ListaRestaurantes.this, FormularioDetalhes.class);

    56 i.putExtra(_ID, String.valueOf(id));

    57 startActivity(i);

    58 }

    Em seguida, adicione o seguinte atributo na classe FormularioDetalhes:

    18 String idRestaurante = null;

    Este atributo ser nulo se estivermos adicionando um novo restaurante, ou o identificador, caso estejamos editando

    um restaurante.

  • Como criamos o GerenciadorRestaurantes no mtodo onCreate(), precisamos encerr-lo no mtodo onDestroy():

    36 @Override

    37 public void onDestroy() {

    38 super.onDestroy();

    39 gerenciador.close();

    40 }

    Como agora temos o ID como controle dos restaurantes, precisamos de um mtodo que nos retorne o Restaurante

    com o identificador correspondente. Adicione o seguinte mtodo a classe GerenciadorRestaurantes:

    61 public Cursor obterPorId(String id) {

    62 String[] argumentos = {id};

    63

    64 return getReadableDatabase().rawQuery(

    65 "SELECT _id, nome, endereco, tipo, anotacoes " +

    66 "FROM restaurantes WHERE _id = ?", argumentos);

    67 }

    Agora, adicione o seguinte trecho ao fim do mtodo onCreate() da classe FormularioDetalhes:

    35 idRestaurante = getIntent().getStringExtra(ListaRestaurantes._ID);

    36

    37 if (idRestaurante != null) {

    38 carregar();

    39 }

    Adicione, ento, a implementao do mtodo carregar():

    66 private void carregar() {

    67 Cursor c = gerenciador.obterPorId(idRestaurante);

    68

    69 c.moveToFirst();

    70 nome.setText(gerenciador.obterNome(c));

    71 endereco.setText(gerenciador.obterEndereco(c));

    72 anotacoes.setText(gerenciador.obterAnotacoes(c));

    73

    74 if (gerenciador.obterTipo(c).equals("rodizio")) {

    75 tipos.check(R.id.rodizio);

    76 } else if (gerenciador.obterTipo(c).equals("fast_food")) {

    77 tipos.check(R.id.fast_food);

    78 } else {

    79 tipos.check(R.id.a_domicilio);

    80 }

    81

    82 c.close();

    83 }

    Agora, vamos adicionar a opo de menu Adicionar para que possamos, a partir da listagem (que agora ser a tela

    principal do aplicativo), inserir um novo restaurante. Modifique o arquivo opcao.xml que encontra-se em res/menu.

  • 1

    2

    3

    6

    Este item de mdia padro do Android, e pode ser encontrado no seu diretrio de instalao do SDK, em

    platforms -> verso do Android que est usando (no meu caso, android-8 (ou 2.2)) -> data -> res -> tamanho de tela

    (podemos utilizar drawable-mdpi). Procure pelo cone ic_menu_add.png. Copie-o e coloque na pasta res/drawable

    da sua aplicao. Para padronizar o nome, eu o renomeei para adicionar.png.

    Agora que j temos o menu, vamos ajustar a classe ListaRestaurantes para manipul-lo corretamente. Vamos

    novamente implementar o mtodo onCreateOptionsMenu():

    62 @Override

    63 public boolean onCreateOptionsMenu(Menu menu) {

    64 new MenuInflater(this).inflate(R.menu.opcao, menu);

    65

    66 return super.onCreateOptionsMenu(menu);

    67 }

    E adicione, tambm, a implementao de onOptionsItemSelected():

    70 @Override

    71 public boolean onOptionsItemSelected(MenuItem item) {

    72 if (item.getItemId() == R.id.adicionar) {

    73 startActivity(new Intent(ListaRestaurantes.this, FormularioDetalhes.class));

    74 return true;

    75 }

    76

    77 return super.onOptionsItemSelected(item);

    78 }

    Bom, l na nossa classe GerenciadorRestaurantes, temos o mtodo para inserir um novo restaurante, mas no

    temos o mtodo para atualizar. Portanto, adicione o seguinte mtodo classe:

    40 public void atualizar(String id, String nome, String endereco, String tipo, String anotacoes) {

    41 ContentValues valores = new ContentValues();

    42 String[] argumentos = {id};

    43

    44 valores.put("nome", nome);

    45 valores.put("endereco", endereco);

    46 valores.put("tipo", tipo);

    47 valores.put("anotacoes", anotacoes);

    48

    49 getWritableDatabase().update("restaurantes", valores, "_id=?", argumentos);

    50 }

  • Por fim, precisamos adicionar o comportamento do boto Salvar no formulrio. Modifique a implementao do

    onSave na classe FormularioDetalhes para verificar se a operao de incluso ou alterao:

    47 private OnClickListener onSave = new OnClickListener() {

    48 public void onClick(View arg0) {

    49 String tipo = null;

    50

    51 switch (tipos.getCheckedRadioButtonId()) {

    52 case R.id.rodizio:

    53 tipo = "rodizio";

    54 break;

    55 case R.id.fast_food:

    56 tipo = "fast_food";

    57 break;

    58 case R.id.a_domicilio:

    59 tipo = "a_domicilio";

    60 break;

    61 }

    62

    63 if (idRestaurante == null) {

    64 gerenciador.inserir(nome.getText().toString(),

    65 endereco.getText().toString(),

    66 tipo, anotacoes.getText().toString());

    67 } else {

    68 gerenciador.atualizar(idRestaurante,

    69 nome.getText().toString(),

    70 endereco.getText().toString(),

    71 tipo, anotacoes.getText().toString());

    72 }

    73

    74 finish();

    75 }

    76 };

    Verifique se no h cdigo duplicado, corrija os imports (Ctrl + Shift + O) e pronto! J temos nossa aplicao

    funcionando!

  • Pra simplificar, a vo as listagens completas:

    Restaurante.java:

    1 package com.blogspot.flavioaf.restaurante.model;

    2

    3 public class Restaurante {

    4

    5 private String nome = "";

    6 private String endereco = "";

    7 private String tipo = "";

    8 private String anotacoes = "";

    9

    10 public String getNome() {

    11 return nome;

    12 }

    13

    14 public void setNome(String nome) {

    15 this.nome = nome;

    16 }

    17

    18 public String getEndereco() {

    19 return endereco;

    20 }

    21

    22 public void setEndereco(String endereco) {

    23 this.endereco = endereco;

    24 }

    25

    26 public String getTipo() {

    27 return tipo;

    28 }

    29

    30 public void setTipo(String tipo) {

    31 this.tipo = tipo;

  • 32 }

    33

    34 public String getAnotacoes() {

    35 return anotacoes;

    36 }

    37

    38 public void setAnotacoes(String anotacoes) {

    39 this.anotacoes = anotacoes;

    40 }

    41

    42 @Override

    43 public String toString() {

    44 return getNome();

    45 }

    46 }

    FormularioDetalhes.java:

    1 package com.blogspot.flavioaf.restaurante;

    2

    3 import android.app.Activity;

    4 import android.database.Cursor;

    5 import android.os.Bundle;

    6 import android.view.View;

    7 import android.view.View.OnClickListener;

    8 import android.widget.Button;

    9 import android.widget.EditText;

    10 import android.widget.RadioGroup;

    11

    12 public class FormularioDetalhes extends Activity {

    13

    14 EditText nome = null;

    15 EditText endereco = null;

    16 EditText anotacoes = null;

    17 RadioGroup tipos = null;

    18 GerenciadorRestaurantes gerenciador;

    19 String idRestaurante = null;

    20

    21 @Override

    22 public void onCreate(Bundle savedInstanceState) {

    23 super.onCreate(savedInstanceState);

    24 setContentView(R.layout.form_detalhes);

    25

    26 gerenciador = new GerenciadorRestaurantes(this);

    27

    28 nome = (EditText) findViewById(R.id.nome);

    29 endereco = (EditText) findViewById(R.id.end);

    30 anotacoes = (EditText) findViewById(R.id.anotacoes);

    31 tipos = (RadioGroup) findViewById(R.id.tipos);

    32

    33 Button salvar = (Button) findViewById(R.id.salvar);

    34 salvar.setOnClickListener(onSave);

    35

    36 idRestaurante = getIntent().getStringExtra(ListaRestaurantes._ID);

    37

    38 if (idRestaurante != null) {

    39 carregar();

    40 }

    41 }

    42

    43 @Override

    44 public void onDestroy() {

    45 super.onDestroy();

    46 gerenciador.close();

    47 }

    48

    49 private OnClickListener onSave = new OnClickListener() {

    50

  • 51 public void onClick(View arg0) {

    52 String tipo = null;

    53

    54 switch (tipos.getCheckedRadioButtonId()) {

    55 case R.id.rodizio:

    56 tipo = "rodizio";

    57 break;

    58 case R.id.fast_food:

    59 tipo = "fast_food";

    60 break;

    61 case R.id.a_domicilio:

    62 tipo = "a_domicilio";

    63 break;

    64 }

    65

    66 if (idRestaurante == null) {

    67 gerenciador.inserir(nome.getText().toString(),

    68 endereco.getText().toString(),

    69 tipo, anotacoes.getText().toString());

    70 } else {

    71 gerenciador.atualizar(idRestaurante,

    72 nome.getText().toString(),

    73 endereco.getText().toString(),

    74 tipo, anotacoes.getText().toString());

    75 }

    76

    77 finish();

    78 }

    79 };

    80

    81 private void carregar() {

    82 Cursor c = gerenciador.obterPorId(idRestaurante);

    83

    84 c.moveToFirst();

    85 nome.setText(gerenciador.obterNome(c));

    86 endereco.setText(gerenciador.obterEndereco(c));

    87 anotacoes.setText(gerenciador.obterAnotacoes(c));

    88

    89 if (gerenciador.obterTipo(c).equals("rodizio")) {

    90 tipos.check(R.id.rodizio);

    91 } else if (gerenciador.obterTipo(c).equals("fast_food")) {

    92 tipos.check(R.id.fast_food);

    93 } else {

    94 tipos.check(R.id.a_domicilio);

    95 }

    96

    97 c.close();

    98 }

    99 }

    GerenciadorRestaurantes.java:

    1 package com.blogspot.flavioaf.restaurante;

    2

    3 import android.content.ContentValues;

    4 import android.content.Context;

    5 import android.database.Cursor;

    6 import android.database.sqlite.SQLiteDatabase;

    7 import android.database.sqlite.SQLiteOpenHelper;

    8

    9 public class GerenciadorRestaurantes extends SQLiteOpenHelper {

    10

    11 private static final String NOME_BANCO = "restaurantes.db";

    12 private static final int VERSAO_SCHEMA = 1;

    13

    14 public GerenciadorRestaurantes(Context context) {

    15 super(context, NOME_BANCO, null, VERSAO_SCHEMA);

    16 }

  • 17

    18 @Override

    19 public void onCreate(SQLiteDatabase db) {

    20 db.execSQL("CREATE TABLE restaurantes (_id INTEGER PRIMARY KEY AUTOINCREMENT," +

    21 " nome TEXT, endereco TEXT, tipo TEXT, anotacoes TEXT);");

    22 }

    23

    24 @Override

    25 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    26

    27 }

    28

    29 public void inserir(String nome, String endereco, String tipo, String anotacoes) {

    30 ContentValues valores = new ContentValues();

    31

    32 valores.put("nome", nome);

    33 valores.put("endereco", endereco);

    34 valores.put("tipo", tipo);

    35 valores.put("anotacoes", anotacoes);

    36

    37 getWritableDatabase().insert("restaurantes", "nome", valores);

    38 }

    39

    40 public void atualizar(String id, String nome, String endereco, String tipo, String anotacoes) {

    41 ContentValues valores = new ContentValues();

    42 String[] argumentos = {id};

    43

    44 valores.put("nome", nome);

    45 valores.put("endereco", endereco);

    46 valores.put("tipo", tipo);

    47 valores.put("anotacoes", anotacoes);

    48

    49 getWritableDatabase().update("restaurantes", valores, "_id=?", argumentos);

    50 }

    51

    52 public Cursor obterTodos() {

    53 return getReadableDatabase().rawQuery("select _id, nome, endereco, tipo, " +

    54 "anotacoes FROM restaurantes ORDER BY nome", null);

    55 }

    56

    57 public String obterNome(Cursor c) {

    58 return c.getString(1);

    59 }

    60

    61 public String obterEndereco(Cursor c) {

    62 return c.getString(2);

    63 }

    64

    65 public String obterTipo(Cursor c) {

    66 return c.getString(3);

    67 }

    68

    69 public String obterAnotacoes(Cursor c) {

    70 return c.getString(4);

    71 }

    72

    73 public Cursor obterPorId(String id) {

    74 String[] argumentos = {id};

    75

    76 return getReadableDatabase().rawQuery(

    77 "SELECT _id, nome, endereco, tipo, anotacoes " +

    78 "FROM restaurantes WHERE _id = ?", argumentos);

    79 }

    80 }

    ListaRestaurantes.java:

  • 1 package com.blogspot.flavioaf.restaurante;

    2

    3 import android.app.ListActivity;

    4 import android.content.Context;

    5 import android.content.Intent;

    6 import android.database.Cursor;

    7 import android.os.Bundle;

    8 import android.view.LayoutInflater;

    9 import android.view.Menu;

    10 import android.view.MenuInflater;

    11 import android.view.MenuItem;

    12 import android.view.View;

    13 import android.view.ViewGroup;

    14 import android.widget.CursorAdapter;

    15 import android.widget.ImageView;

    16 import android.widget.ListView;

    17 import android.widget.TextView;

    18

    19 public class ListaRestaurantes extends ListActivity {

    20

    21 Cursor listaRestaurantes = null;

    22 AdaptadorRestaurante adaptador = null;

    23 public final static String _ID = "com.blogspot.flavioaf.restaurante._ID";

    24 GerenciadorRestaurantes gerenciador;

    25

    26 @Override

    27 public void onCreate(Bundle savedInstanceState) {

    28 super.onCreate(savedInstanceState);

    29 setContentView(R.layout.main);

    30

    31 gerenciador = new GerenciadorRestaurantes(this);

    32 listaRestaurantes = gerenciador.obterTodos();

    33 startManagingCursor(listaRestaurantes);

    34 adaptador = new AdaptadorRestaurante(listaRestaurantes);

    35 setListAdapter(adaptador);

    36 }

    37

    38 @Override

    39 public void onDestroy() {

    40 super.onDestroy();

    41 gerenciador.close();

    42 }

    43

    44 @Override

    45 public void onListItemClick(ListView l, View v, int position, long id) {

    46 Intent i = new Intent(ListaRestaurantes.this, FormularioDetalhes.class);

    47 i.putExtra(_ID, String.valueOf(id));

    48 System.out.println("ID VALUE: " + id);

    49 startActivity(i);

    50 }

    51

    52 @Override

    53 public boolean onCreateOptionsMenu(Menu menu) {

    54 new MenuInflater(this).inflate(R.menu.opcao, menu);

    55

    56 return super.onCreateOptionsMenu(menu);

    57 }

    58

    59 @Override

    60 public boolean onOptionsItemSelected(MenuItem item) {

    61 if (item.getItemId() == R.id.adicionar) {

    62 startActivity(new Intent(ListaRestaurantes.this, FormularioDetalhes.class));

    63 return true;

    64 }

    65

    66 return super.onOptionsItemSelected(item);

    67 }

    68

    69 class AdaptadorRestaurante extends CursorAdapter {

    70 AdaptadorRestaurante(Cursor c) {

  • 71 super(ListaRestaurantes.this, c);

    72 }

    73

    74 @Override

    75 public void bindView(View view, Context context, Cursor cursor) {

    76 ArmazenadorRestaurante armazenador = (ArmazenadorRestaurante) view.getTag();

    77 armazenador.popularFormulario(cursor, gerenciador);

    78 }

    79

    80 @Override

    81 public View newView(Context context, Cursor cursor, ViewGroup parent) {

    82 LayoutInflater inflater = getLayoutInflater();

    83 View linha = inflater.inflate(R.layout.linha, parent, false);

    84 ArmazenadorRestaurante armazenador = new ArmazenadorRestaurante(linha);

    85 linha.setTag(armazenador);

    86 return linha;

    87 }

    88 }

    89

    90 static class ArmazenadorRestaurante {

    91 private TextView nome = null;

    92 private TextView endereco = null;

    93 private ImageView icone = null;

    94

    95 ArmazenadorRestaurante(View linha) {

    96 nome = (TextView) linha.findViewById(R.id.titulo);

    97 endereco = (TextView) linha.findViewById(R.id.endereco);

    98 icone = (ImageView) linha.findViewById(R.id.icone);

    99 }

    100

    101 void popularFormulario(Cursor c, GerenciadorRestaurantes gerenciador) {

    102 nome.setText(gerenciador.obterNome(c));

    103 endereco.setText(gerenciador.obterEndereco(c));

    104

    105 if (gerenciador.obterTipo(c).equals("rodizio")) {

    106 icone.setImageResource(R.drawable.rodizio);

    107 } else if (gerenciador.obterTipo(c).equals("fast_food")) {

    108 icone.setImageResource(R.drawable.fast_food);

    109 } else {

    110 icone.setImageResource(R.drawable.entrega);

    111 }

    112 }

    113 }

    114 }

  • Configurando Preferncias Vamos adicionar ao nosso aplicativo Lista de Restaurantes a opo do usurio configurar de que forma deve ocorrer

    a listagem dos restaurantes (nome, tipo, ordem alfabtica, etc.).

    Pra comear, vamos criar um arquivo XML que tomar conta das configuraes de preferncia. Dessa forma, crie o

    arquivo preferencias.xml e coloque-o em res/xml (a pasta ainda no existe ento crie-a). O contedo dele ser:

    1

    2

    9

    Em seguida, vamos criar o arquivo arrays.xml que definir os dois arrays referenciados no XML definido acima. O

    arquivo arrays.xml dever ser salvo na pasta res/values. Seu contedo listado a seguir:

    1

    2

    3

    4 Por Nome, Ascendente

    5 Por Nome, Descendente

    6 Por Tipo

    7 Por Endereo, Ascendente

    8 Por Endereo, Descendente

    9

    10

    11 nome ASC

    12 nome DESC

    13 tipo, nome ASC

    14 endereco ASC

    15 endereco DESC

    16

    17

    O prximo passo a criao da Activity responsvel pelas preferncias. Vamos criar a classe EdicaoPreferencias, que

    estender PreferenceActivity, dentro do pacote com.blogspot.flavioaf.restaurante:

    1 package com.blogspot.flavioaf.restaurante;

    2

    3 import android.os.Bundle;

    4 import android.preference.PreferenceActivity;

    5

    6 public class EdicaoPreferencias extends PreferenceActivity {

    7

    8 @Override

    9 public void onCreate(Bundle savedInstanceState) {

    10 super.onCreate(savedInstanceState);

    11

    12 addPreferencesFromResource(R.xml.preferencias);

    13 }

    14 }

  • Tambm necessrio atualizar o arquivo AndroidManifest.xml, j que adicionamos uma nova Activity ao nosso

    projeto.

    1

    2

    6

    7

    8

    9

    12

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    Continuando, vamos agora vincular a nossa nova Activity ao menu de opes. Primeiramente, vamos editar o

    arquivo opcao.xml, que se encontra em res/menu.

    1

    2

    3

    6

    9

    O cone referenciado padro do sistema e, como mostrado no ltimo tutorial, pode ser encontrado na prpria

    instalao da SDK. Este cone utilizado se chama ic_menu_preferences (aqui foi renomeado para

    menu_preferencias em nosso projeto).

    Agora, vamos modificar o mtodo onOptionsItemSelected na classe ListaRestaurantes para mapear esta nova opo

    adicionada ao menu:

    58 @Override

    59 public boolean onOptionsItemSelected(MenuItem item) {

    60 if (item.getItemId() == R.id.adicionar) {

    61 startActivity(new Intent(ListaRestaurantes.this, FormularioDetalhes.class));

    62 return true;

    63 } else if (item.getItemId() == R.id.prefs) {

    64 startActivity(new Intent(this, EdicaoPreferencias.class));

  • 65 return true;

    66 }

    67

    68 return super.onOptionsItemSelected(item);

    69 }

    Neste ponto, se voc rodar a aplicao, j poder conferir o menu:

    Agora, j que a parte visual est pronta, vamos aplicar a ordenao a nossa lista. Primeiramente, precisamos que o

    mtodo obterTodos() da classe GerenciadorRestaurantes precisa receber o mtodo de ordenao por parmetro e

    aplic-lo a SQL. Modifique-o para que fique assim:

    52 public Cursor obterTodos(String ordenacao) {

    53 return getReadableDatabase().rawQuery("select _id, nome, endereco, tipo, " +

    54 "anotacoes FROM restaurantes ORDER BY " + ordenacao, null);

    55 }

    Agora, precisamos de um atributo na classe ListaRestaurantes que nos permita saber a ordenao selecionada e

    aplic-la a listagem. Adicione um atributo classe chamado prefs do tipo SharedPreferences.

    26 SharedPreferences prefs = null;

    Em seguida, adicione a inicializao do atributo no mtodo onCreate(), prximo ao seu incio.

    34 prefs = PreferenceManager.getDefaultSharedPreferences(this);

  • E modifique a chamada ao mtodo obterTodos() logo em seguida:

    36 listaRestaurantes = gerenciador.obterTodos(prefs.getString("ordenacao", "nome"));

    Por fim, vamos fazer com que seja aplicada as alteraes realizadas pelo usurio em tempo de execuo, j que, por

    enquanto, necessrio fechar a aplicao para que a nova ordenao tenha efeito. Adicione esta linha ao fim do

    mtodo onCreate():

    40 prefs.registerOnSharedPreferenceChangeListener(prefListener);

    Em seguida, vamos criar o listener dentro da classe ListaRestaurantes:

    1 private OnSharedPreferenceChangeListener prefListener = new OnSharedPreferenceChangeListener() {

    2

    3 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,

    4 String key) {

    5 if (key.equals("ordenacao")) {

    6

    7 }

    8 }

    9 };

    Continuando, vamos isolar a inicializao da lista em um mtodo parte, deixando o mtodo onCreate() mais limpo.

    Crie o mtodo inicializarLista():

    77 private void inicializarLista() {

    78 if (listaRestaurantes != null) {

    79 stopManagingCursor(listaRestaurantes);

    80 listaRestaurantes.close();

    81 }

    82

    83 listaRestaurantes = gerenciador.obterTodos(prefs.getString("listagem", "nome"));

    84 startManagingCursor(listaRestaurantes);

    85 adaptador = new AdaptadorRestaurante(listaRestaurantes);

    86 setListAdapter(adaptador);

    87 }

    Agora, referenciamos o recm-criado mtodo inicializarLista() no mtodo onCreate():

    30 @Override

    31 public void onCreate(Bundle savedInstanceState) {

    32 super.onCreate(savedInstanceState);

    33 setContentView(R.layout.main);

    34

    35 prefs = PreferenceManager.getDefaultSharedPreferences(this);

    36 gerenciador = new GerenciadorRestaurantes(this);

    37 inicializarLista();

    38 prefs.registerOnSharedPreferenceChangeListener(prefListener);

    39 }

  • E ento, tambm fazemos uma chamada ao mtodo inicializarLista() dentro do nosso prefListener:

    86 private OnSharedPreferenceChangeListener prefListener = new OnSharedPreferenceChangeListener() {

    87

    88 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,

    89 String key) {

    90 if (key.equals("listagem")) {

    91 inicializarLista();

    92 }

    93 }

    94 };

    E pronto! J temos o nosso aplicativo funcionando!

  • Ajustando o Layout para Paisagem (II) Vamos tratar da adaptao do layout da aplicao Lista de Restaurantes tambm para o modo paisagem.

    Neste tutorial vamos fazer a rotao de uma maneira mais organizada, evitando alguns problemas.

    Primeiramente, precisamos de uma forma de armazenar os valores no caso da mudana de orientao do celular. L

    na classe FormularioDetalhes, vamos sobrescrever o mtodo onSaveInstanceState(), que armazenar os valores pra

    gente. Adicione a seguinte implementao ao final da classe:

    100 @Override

    101 public void onSaveInstanceState(Bundle outState) {

    102 super.onSaveInstanceState(outState);

    103

    104 outState.putString("nome", nome.getText().toString());

    105 outState.putString("endereco", endereco.getText().toString());

    106 outState.putString("anotacoes", anotacoes.getText().toString());

    107 outState.putInt("tipo", tipos.getCheckedRadioButtonId());

    108 }

    Pronto. J fizemos com que os valores do formulrio fossem salvos. Agora, vamos implementar o mtodo

    onRestoreInstanceState() que devolver os dados no formulrio.

    110 @Override

    111 public void onRestoreInstanceState(Bundle savedInstanceState) {

    112 super.onRestoreInstanceState(savedInstanceState);

    113

    114 nome.setText(savedInstanceState.getString("nome"));

    115 endereco.setText(savedInstanceState.getString("endereco"));

    116 anotacoes.setText(savedInstanceState.getString("anotacoes"));

    117 tipos.check(savedInstanceState.getInt("tipo"));

    118 }

    Por fim, vamos definir novamente o nosso layout em modo paisagem. Crie novamente a pasta (se voc a excluiu)

    res/layout-land e crie o arquivo form_detalhes.xml. Se voc ainda tem o arquivo main.xml l, exclua-o.

    1

    2

    6

    7

    8

    10

    11

    12

    13

    15

    16

    17

    18

    19

    21

  • 22 android:text="Fast Food"/>

    23

    25

    26

    27

    31

    40

    44

    45

    46

    E pronto! Quanto a tela de listagem, no precisamos alterar seu layout pois ele funciona bem tanto em modo retrato

    quanto paisagem.

  • Observao

    Aps a ltima atualizao do plugin ADT do Eclipse, ele acusou alguns warnings nos layouts

    XML. Por enquanto no se preocupem com isso!

  • Integrando Bibliotecas de Terceiros (Twitter) Veremos neste tutorial como integrar uma biblioteca externa ao nosso aplicativo em Android. Atravs dela, vamos

    vincular uma conta do Twitter ao restaurante e poderemos obter os ltimos tweets referentes quele restaurante.

    Para o acesso ao Twitter, utilizaremos a biblioteca twitter4j, que nos fornece acesso completo aos recursos da rede

    social. No tutorial vamos utilizar a verso 2.2.5 otimizada para Android (twitter4j-android-2.2.5), ou superior.

    O primeiro passo adicionar a conta do Twitter ao nosso modelo de dados. Isso implica em modificar a classe de

    persistncia GerenciadorRestaurantes. Comece alterando o mtodo onCreate() para abrigar o novo campo no banco

    de dados:

    18 @Override

    19 public void onCreate(SQLiteDatabase db) {

    20 db.execSQL("CREATE TABLE restaurantes (_id INTEGER PRIMARY KEY AUTOINCREMENT," +

    21 " nome TEXT, endereco TEXT, tipo TEXT, anotacoes TEXT, twitter TEXT);");

    22 }

    Alm disso, vamos alterar a verso do Schema do banco, para que ele seja atualizado em verses anteriores:

    12 private static final int VERSAO_SCHEMA = 2;

    Precisamos tambm atualizar o nosso mtodo onUpdate(), que antes no fazia nada. Ele ser executado se o usurio

    possuir a verso antiga do banco. Nesse caso, iremos adicionar a nova coluna twitter a tabela restaurantes.

    24 @Override

    25 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    26 db.execSQL("ALTER TABLE restaurantes ADD COLUMN twitter TEXT");

    27 }

    Para concluir as modificaes nesta classe, vamos atualizar os mtodo obterTodos(), obterPorId(), inserir() e

    atualizar(). Alm disso, tambm vamos adicionar o mtodo obterTwitter():

    29 public void inserir(String nome, String endereco, String tipo, String anotacoes, String twitter) {

    30 ContentValues valores = new ContentValues();

    31

    32 valores.put("nome", nome);

    33 valores.put("endereco", endereco);

    34 valores.put("tipo", tipo);

    35 valores.put("anotacoes", anotacoes);

    36 valores.put("twitter", twitter);

    37

    38 getWritableDatabase().insert("restaurantes", "nome", valores);

    39 }

    40

    41 public void atualizar(String id, String nome, String endereco, String tipo, String anotacoes, String twitter) {

    42 ContentValues valores = new ContentValues();

    43 String[] argumentos = {id};

    44

    45 valores.put("nome", nome);

    46 valores.put("endereco", endereco);

    47 valores.put("tipo", tipo);

  • 48 valores.put("anotacoes", anotacoes);

    49 valores.put("twitter", twitter);

    50

    51 getWritableDatabase().update("restaurantes", valores, "_id=?", argumentos);

    52 }

    53

    54 public Cursor obterTodos(String ordenacao) {

    55 return getReadableDatabase().rawQuery("select _id, nome, endereco, tipo, " +

    56 "anotacoes, twitter FROM restaurantes ORDER BY " + ordenacao, null);

    57 }

    58

    59 public String obterTwitter(Cursor c) {

    60 return c.getString(5);

    61 }

    62

    63 public Cursor obterPorId(String id) {

    64 String[] argumentos = {id};

    65

    66 return getReadableDatabase().rawQuery(

    67 "SELECT _id, nome, endereco, tipo, anotacoes, twitter " +

    68 "FROM restaurantes WHERE _id = ?", argumentos);

    69 }

    Pronto. Com relao aos dados do aplicativo, j estamos prontos. Vamos agora ajustar o formulrio de detalhes,

    adicionando o campo Twitter em ambos. Lembre-se que, como temos duas verses deste formulrio (res/layout e

    res/layout-land), precisaremos fazer a modificao em ambos. Primeiramente o formulrio para modo retrato

    (res/layout/form_detalhes.xml):

    1

    2

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    19

    21

    23

    24

    25

    33

    35

  • 37 android:layout_height="wrap_content"

    38 android:text="Salvar"/>

    39

    Basicamente, a nica modificao a adio do campo twitter e a remoo do TextView do campo anotaes,

    exibido agora como o atributo hint. A mesma coisa fazemos no formulrio do modo paisagem (res/layout-

    land/form_detalhes.xml):

    1

    2

    6

    7

    8

    10

    11

    12

    13

    15

    16

    17

    18

    19

    21

    23

    25

    26

    27

    31

    41

    45

    49

    50

    51

    Agora, iremos adicionar o atributo twitter na classe FormularioDetalhes.

  • 24 EditText twitter = null;

    Em seguida, no mtodo onCreate(), obtemos o valor do formulrio e o aplicamos ao atributo da classe:

    39 twitter = (EditText) findViewById(R.id.twitter);

    E no mtodo carregar(), configuramos o texto do EditText:

    130 twitter.setText(gerenciador.obterTwitter(c));

    Finalmente, vamos modificar as chamadas aos mtodos de persistncia l no onSave:

    58 private OnClickListener onSave = new OnClickListener() {

    59

    60 public void onClick(View arg0) {

    61 String tipo = null;

    62

    63 switch (tipos.getCheckedRadioButtonId()) {

    64 case R.id.rodizio:

    65 tipo = "rodizio";

    66 break;

    67 case R.id.fast_food:

    68 tipo = "fast_food";

    69 break;

    70 case R.id.a_domicilio:

    71 tipo = "a_domicilio";

    72 break;

    73 }

    74

    75 if (idRestaurante == null) {

    76 gerenciador.inserir(nome.getText().toString(),

    77 endereco.getText().toString(),

    78 tipo, anotacoes.getText().toString(),

    79 twitter.getText().toString());

    80 } else {

    81 gerenciador.atualizar(idRestaurante,

    82 nome.getText().toString(),

    83 endereco.getText().toString(),

    84 tipo, anotacoes.getText().toString(),

    85 twitter.getText().toString());

    86 }

    87

    88 finish();

    89 }

    90 };

    Acompanharam? O prximo passo adicionar a opo Twitter ao menu. Crie o novo arquivo opcao_detalhes.xml e o

    salve em res/menu. O cone tem pra download junto com o projeto l no final do tutorial.

    1

    2

    3

  • 5 android:icon="@drawable/twitter"/>

    6

    Em seguida, adicione o mtodo onCreateOptionsMenu() a classe FormularioDetalhes.

    92 @Override

    93 public boolean onCreateOptionsMenu(Menu menu) {

    94 new MenuInflater(this).inflate(R.menu.opcao_detalhes, menu);

    95

    96 return super.onCreateOptionsMenu(menu);

    97 };

    Como vamos utilizar a conexo de rede do celular com a Internet, precisamos verificar se essa conexo est

    disponvel. Vamos ento criar os mtodos redeDisponivel() e o mtodo onOptionsItemSelected() l na classe

    FormularioDetalhes:

    99 @Override

    100 public boolean onOptionsItemSelected(MenuItem item) {

    101 if (item.getItemId() == R.id.twitter) {

    102 if (redeDisponivel()) {

    103 Intent i = new Intent(this, TwitterActivity.class);

    104 i.putExtra(TwitterActivity.PERFIL, twitter.getText().toString());

    105 startActivity(i);

    106 } else {

    107 Toast.makeText(this, "Conexo com a Internet indisponvel", Toast.LENGTH_LONG).show();

    108 }

    109

    110 return true;

    111 }

    112

    113 return super.onOptionsItemSelected(item);

    114 }

    115

    116 private boolean redeDisponivel() {

    117 ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);

    118 NetworkInfo info = cm.getActiveNetworkInfo();

    119

    120 return (info != null);

    121 }

    Ao inserir estes dois mtodos, o Eclipse vai chiar pela ausncia da classe TwitterActivity. Calma! J j resolveremos

    isso. Tambm precisaremos adicionar ao AndroidManifest.xml que nosso aplicativo precisa de permisso para

    acessar a rede. Assim, adicione as duas linhas seguintes ao arquivo, antes do n application.

    9

    10

    Agora vamos comear a mexer com a obteno dos tweets propriamente ditos. Para adicionar a biblioteca (dentro

    do arquivo Zip baixado, vamos adicionar o arquivo twitter4j-core-android-2.2.5.jar (ou superior) que se encontra

    dentro da pasta lib), clique com o boto direito sobre o projeto, selecione Properties, clique em Java Build Path, aba

    Libraries e clique no boto Add External JARs. Localize o arquivo, e confirme.

  • Crie uma nova classe no pacote com.blogspot.flavioaf.restaurante chamada TwitterActivity estendendo ListActivity.

    Em seguida, adicione o mapeamento desta Activity no AndroidManifest.xml:

    28

    29

    Agora, crie uma classe interna a classe TwitterActivity chamada TarefaTwitter:

    21 private static class TarefaTwitter extends AsyncTask {

    22 private Twitter t = new TwitterFactory().getInstance();

    23 private Exception ex = null;

    24 private TwitterActivity activity = null;

    25

    26 TarefaTwitter(TwitterActivity activity) {

    27 anexar(activity);

    28 }

    29

    30 void anexar(TwitterActivity activity) {

    31 this.activity = activity;

    32 }

    33

    34 void desanexar() {

    35 activity = null;

    36 }

    37

    38 @Override

    39 protected List doInBackground(String... params) {

    40 List resultado = null;

    41

    42 try {

    43 resultado = t.getUserTimeline(params[0]);

    44 } catch (Exception ex) {

    45 this.ex = ex;

    46 }

    47

    48 return resultado;

    49 }

    50

    51 @Override

    52 public void onTutorialExecute(List result) {

    53 if (ex == null) {

    54 activity.atribuirTweets(result);

    55 } else {

    56 Log.e("ListaRestaurantes", "Erro manipulando timeline twitter", ex);

    57 activity.atirarErro(ex);

    58 }

    59 }

    60 }

    Esta classe a responsvel por carregar os tweets da conta selecionada e envi-los para a Activity (carregamento na

    linha 43 e atribuio para a Activity na linha 54). Sempre lembrando de corrigir os imports com o Ctrl + Shift + O

    Prosseguindo, vamos implementar os mtodos da classe TwitterActivity referenciados pela classe TarefaTwitter.

    Primeiramente, vamos com o atirarErro():

  • 21 private void atirarErro(Throwable t) {

    22 Builder builder = new Builder(this);

    23 builder.setTitle("Erro!").setMessage(t.toString()).setPositiveButton("OK", null).show();

    24 }

    Por fim, vamos fazer com que os tweets obtidos sejam exibidos. Dentro da TwitterActivity, vamos criar a classe

    AdaptadorTweets que ser responsvel por adaptar os nossos tweets para a exibio.

    58 private class AdaptadorTweets extends BaseAdapter {

    59 List status = null;

    60

    61 AdaptadorTweets(List status) {

    62 super();

    63 this.status = status;

    64 }

    65

    66 public int getCount() {

    67 return status.size();

    68 }

    69

    70 public Object getItem(int position) {

    71 return status.get(position);

    72 }

    73

    74 public long getItemId(int position) {

    75 return position;

    76 }

    77

    78 public View getView(int position, View convertView, ViewGroup parent) {

    79 View linha = convertView;

    80

    81 if (linha == null) {

    82 LayoutInflater inflater = getLayoutInflater();

    83 linha = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);

    84 }

    85

    86 Status item = (Status) getItem(position);

    87 ((TextView) linha).setText(item.getText());

    88

    89 return linha;

    90 }

    91 }

    Com este adaptador, vamos exibir os tweets em uma lista comum (android.R.layout.simple_list_item_1). Para

    gerenciar as instncias da TarefaTwitter e da lista de tweets, vamos criar uma classe interna StatusInstance:

    139 private static class StatusInstancia {

    140 List tweets = null;

    141 TarefaTwitter tarefa = null;

    142 }

    Em seguida adicionamos um objeto desta classe como atributo da classe TwitterActivity:

    22 private StatusInstancia status = null;

  • E implemente os mtodos onCreate(), onRetainNonConfigurationInstance() e atribuirTweets().

    24 @Override

    25 public void onCreate(Bundle savedInstanceState) {

    26 super.onCreate(savedInstanceState);

    27

    28 status = (StatusInstancia) getLastNonConfigurationInstance();

    29

    30 if (status == null) {

    31 status = new StatusInstancia();

    32 status.tarefa = new TarefaTwitter(this);

    33 status.tarefa.execute(getIntent().getStringExtra(PERFIL));

    34 } else {

    35 if (status.tarefa != null) {

    36 status.tarefa.anexar(this);

    37 }

    38

    39 if (status.tweets != null) {

    40 atribuirTweets(status.tweets);

    41 }

    42 }

    43 }

    44

    45 @Override

    46 public Object onRetainNonConfigurationInstance() {

    47 if (status.tarefa != null) {

    48 status.tarefa.desanexar();

    49 }

    50 return status;

    51 }

    52

    53 private void atribuirTweets(List tweets) {

    54 status.tweets = tweets;

    55 setListAdapter(new AdaptadorTweets(tweets));

    56 }

    E no final, vamos criar o atributo PERFIL na classe:

    21 public static final String PERFIL = "com.blogspot.flavioaf.PERFIL";

    E prontinho! Cadastre um restaurante e adicione uma conta de Twitter!

  • Utilizando um IntentService No tutorial anterior, utilizamos uma AsyncTask para recuperar o contedo do Twitter. Isso foi necessrio para que

    pudssemos obter comunicao com a rede fora da thread principal do aplicativo e, portanto, evitar lentido na

    interface. Outra forma de resolver esse problema usando um IntentService. Um IntentService um componente

    parte que aceita comandos vindos de uma Activity, executa os comandos em linhas em background e,

    opcionalmente, responde s atividades ou o usurio. Neste tutorial, vamos configurar um IntentService como um

    substituto para a AsyncTask.

    Primeiramente, crie uma nova classe no pacote com.blogspot.flavioaf.restaurante chamada TwitterService,

    estendendo IntentService:

    1 package com.blogspot.flavioaf.restaurante;

    2

    3 import android.app.IntentService;

    4 import android.content.Intent;

    5

    6 public class TwitterService extends IntentService {

    7

    8 public TwitterService() {

    9 super("TwitterService");

    10 }

    11

    12 @Override

    13 protected void onHandleIntent(Intent intent) {

    14

    15 }

    16 }

    Em seguida, vamos adicionar um novo n service l no arquivo AndroidManifest.xml logo aps os ns activity,

    dentro do n application.

    29

    30

    O mtodo onHandleIntent() da IntentService chamado sempre em background, razo principal de a utilizarmos.

    Vamos comear com uma implementao inicial deste mtodo l na nossa classe TwitterService, importando parte

    da lgica que tnhamos no mtodo doInBackground():

    18 @Override

    19 protected void onHandleIntent(Intent intent) {

    20 Twitter t = new TwitterFactory().getInstance();

    21

    22 try {

    23 List resultado = t.getUserTimeline(intent.getStringExtra(PERFIL_EXTRA));

    24 } catch (Exception ex) {

    25 Log.e("ListaRestaurantes", "Erro manipulando timeline twitter", ex);

    26 }

    27 }

    Adicione tambm o atributo da classe referenciado no mtodo, que servir para obter o perfil do Twitter que

    obteremos os tweets.

  • 14 public static final String PERFIL_EXTRA = "com.blogspot.flavioaf.PERFIL_EXTRA";

    Continuando, precisamos agora enviar os tweets para a Activity. Para realizar a comunicao, utilizaremos um

    Messenger, que servir para obtermos informaes do servio. Dessa forma, atualize a implementao do mtodo

    onHandleIntent():

    23 @Override

    24 protected void onHandleIntent(Intent intent) {

    25 Twitter t = new TwitterFactory().getInstance();

    26 Messenger messenger = (Messenger) intent.getExtras().get(MESSENGER_EXTRA);

    27 Message msg = Message.obtain();

    28

    29 try {

    30 List resultado = t.getUserTimeline(intent.getStringExtra(PERFIL_EXTRA));

    31

    32 msg.arg1 = Activity.RESULT_OK;

    33 msg.obj = resultado;

    34 } catch (Exception ex) {

    35 Log.e("ListaRestaurantes", "Erro manipulando timeline twitter", ex);

    36 msg.arg1 = Activity.RESULT_CANCELED;

    37 msg.obj = ex;

    38 }

    39

    40 try {

    41 messenger.send(msg);

    42 } catch (Exception ex) {

    43 Log.w("ListaRestaurantes", "Erro enviando dados para a Activity", ex);

    44 }

    45 }

    Para completar, s precisamos adicionar o atributo MESSENGER_EXTRA a nossa classe.

    18 public static final String MESSENGER_EXTRA = "com.blogspot.flavioaf.MESSENGER_EXTRA";

    Por fim, vamos fazer as modificaes na TwitterActivity para que ela trabalhe com o TwitterService em vez da

    TarefaTwitter.

    Primeiramente, vamos converter a nossa TarefaTwitter para HandlerTwitter, que estender Handler em vez de

    AsyncTask. Os mtodos anexar() e desanexar() sero mantidos para gerenciar as mudanas na configurao. J o

    mtodo doInBackground() ser removido, j que a lgica foi movida para o servio. O mtodo onTutorialExecute()

    vira handleMessage(), para pegar o objeto Message do TwitterService, chamando os mtodos atribuirTweets() ou

    atirarErro() dependendo do retorno do servio. O resultado ser esse:

    1 private static class HandlerTwitter extends Handler {

    2 private TwitterActivity activity = null;

    3

    4 HandlerTwitter(TwitterActivity activity) {

    5 anexar(activity);

    6 }

    7

    8 void anexar(TwitterActivity activity) {

    9 this.activity = activity;

  • 10 }

    11

    12 void desanexar() {

    13 activity = null;

    14 }

    15

    16 @Override

    17 public void handleMessage(Message msg) {

    18 if (msg.arg1 == RESULT_OK) {

    19 activity.atribuirTweets((List) msg.obj);

    20 } else {

    21 activity.atirarErro((Exception) msg.obj);

    22 }

    23 }

    Como no temos mais a TarefaTwitter, no precisamos mais dele no StatusInstancia. Porm, precisamos guardar

    nosso Handler como parte de nosso status, de forma que quando o usurio rotacionar a tela, nosso objeto

    Messenger ainda possa comunicar-se corretamente com a TwitterActivity. Assim, modifique a classe

    StatusInstancia:

    122 private static class StatusInstancia {

    123 List tweets = null;

    124 HandlerTwitter handler = null;

    125 }

    Assim, tambm precisaremos modificar o mtodo onRetainNonConfigurationInstance() para acomodar o Handler em

    vez da tarefa.

    44 @Override

    45 public Object onRetainNonConfigurationInstance() {

    46 if (status.handler != null) {

    47 status.handler.desanexar();

    48 }

    49 return status;

    50 }

    Por fim, vamo