guia aberto android ed.2

61
por Átila Camurça 2 a Edição 27 de outubro de 2012

Upload: atila-camurca

Post on 22-May-2015

6.549 views

Category:

Documents


56 download

TRANSCRIPT

Page 1: Guia Aberto Android ed.2

por Átila Camurça

2a Edição

27 de outubro de 2012

Page 2: Guia Aberto Android ed.2

ii

Page 3: Guia Aberto Android ed.2

Sumário

1 Preparando o Ambiente de Desenvolvimento 11.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Instalação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.2.1 Java JDK 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2.2 Android SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2.3 Android 2.2 API 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2.4 Android Virtual Device (AVD) . . . . . . . . . . . . . . . . . . . . . 41.2.5 Eclipse Juno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2.6 Plugin ADT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2.7 Sqlite3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.2.8 Sqliteman . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.2.9 Inkscape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2 Exemplo prático 92.1 Primeira aplicação - Contatos . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.1.1 AndroidManifest.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.1.2 Activity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.1.3 Formulários . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.1.4 Construindo o Model da aplicação . . . . . . . . . . . . . . . . . . . 142.1.5 Mostrando os dados na View . . . . . . . . . . . . . . . . . . . . . . 162.1.6 Editando dados existentes . . . . . . . . . . . . . . . . . . . . . . . . 20

3 Livro de Receitas 233.1 Mostrando Diálogos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3.1.1 Editar/Excluir ao clicar e segurar na ListView . . . . . . . . . . . . 233.1.2 Diálogo de confirmação . . . . . . . . . . . . . . . . . . . . . . . . . 253.1.3 Entrada de diferentes tipos de dados . . . . . . . . . . . . . . . . . . 273.1.4 Validação de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.1.5 Fazendo uma ligação . . . . . . . . . . . . . . . . . . . . . . . . . . . 293.1.6 Enviando e-mail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.2 Internacionalização (i18n) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323.2.1 Forçando região para teste . . . . . . . . . . . . . . . . . . . . . . . . 323.2.2 Forçando região pelo emulador . . . . . . . . . . . . . . . . . . . . . 33

3.3 Utilizando as Preferências do Android . . . . . . . . . . . . . . . . . . . . . 333.3.1 Atualizando colunas de uma tabela . . . . . . . . . . . . . . . . . . . 343.3.2 Array de Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353.3.3 Spinner, diálogo de seleção . . . . . . . . . . . . . . . . . . . . . . . 36

iii

Page 4: Guia Aberto Android ed.2

iv SUMÁRIO

3.3.4 A classe PreferenceActivity . . . . . . . . . . . . . . . . . . . . . . . 373.4 Grupo de Contatos usando Grid . . . . . . . . . . . . . . . . . . . . . . . . 41

3.4.1 Layout usando GridView . . . . . . . . . . . . . . . . . . . . . . . . 413.4.2 Activity para visualizar os Grupos . . . . . . . . . . . . . . . . . . . 423.4.3 Implementando o Adapter . . . . . . . . . . . . . . . . . . . . . . . . 453.4.4 Selecionando contatos de um determinado grupo . . . . . . . . . . . 46

A Sobre o Autor 49

Glossário 51

Page 5: Guia Aberto Android ed.2

Lista de Códigos-fonte

1 Exemplo de banco de dados [exemplo-bd.sql] . . . . . . . . . . . . . . . . . 72 Exemplo de query com subquery [exemplo-bd.sql] . . . . . . . . . . . . . . . 73 Projeto inicial [AndroidManifest.xml] . . . . . . . . . . . . . . . . . . . . . . 94 Layout principal [res/layout/main.xml] . . . . . . . . . . . . . . . . . . . . . 105 Menu principal [res/menu/main

¯menu.xml] . . . . . . . . . . . . . . . . . . 10

6 Definir layout [MainActivity.java] . . . . . . . . . . . . . . . . . . . . . . . . 117 Criando o menu [MainActivity.java] . . . . . . . . . . . . . . . . . . . . . . . 128 Formulário principal [res/layout/salvar.xml] . . . . . . . . . . . . . . . . . . 139 Mudando de Activity [MainActivity.java] . . . . . . . . . . . . . . . . . . . . 1410 Utilizando EditText’s [SalvarActivity.java] . . . . . . . . . . . . . . . . . . . 1411 Mapear SalvarActivity [AndroidManifest.xml] . . . . . . . . . . . . . . . . . 1412 Helper da aplicação [ContatoHelper.java] . . . . . . . . . . . . . . . . . . . . 1513 Criar novo contato [ContatoHelper.java] . . . . . . . . . . . . . . . . . . . . 1514 Fim da iteração criar contato [SalvarActivity.java] . . . . . . . . . . . . . . 1615 Layout para cada linha da lista [res/layout/linha.xml] . . . . . . . . . . . . 1716 Listar contatos existentes [ContatoHelper.java] . . . . . . . . . . . . . . . . 1817 Classe Holder [MainActivity.java] . . . . . . . . . . . . . . . . . . . . . . . . 1818 Classe Adapter [MainActivity.java] . . . . . . . . . . . . . . . . . . . . . . . 1919 Popular ListView [MainActivity.java] . . . . . . . . . . . . . . . . . . . . . . 2020 Passagem de parâmetros [MainActivity.java] . . . . . . . . . . . . . . . . . . 2121 Ler e atualizar dados existentes [ContatoHelper.java] . . . . . . . . . . . . . 2122 Usando Activity para criar ou atualizar [SalvarActivity.java] . . . . . . . . . 2223 Deletar dados existentes [ContatoHelper.java] . . . . . . . . . . . . . . . . . 2324 Adicionar Listener para click longo [MainActivity.java] . . . . . . . . . . . . 2425 Diálogo de confirmação ao deletar contato [MainActivity.java] . . . . . . . . 2626 Distinção de dados [res/layout/salvar.xml] . . . . . . . . . . . . . . . . . . . 2827 Validação dos dados [SalvarActivity.java] . . . . . . . . . . . . . . . . . . . . 2928 Permissão de realizar chamadas [AndroidManifest.xml] . . . . . . . . . . . . 3029 Item chamar no diálogo [MainActivity.java] . . . . . . . . . . . . . . . . . . 3130 Item enviar e-mail no diálogo [MainActivity.java] . . . . . . . . . . . . . . . 3231 Forçando região [SalvarActivity.java] . . . . . . . . . . . . . . . . . . . . . . 3332 Nova coluna grupo na base de dados [ContatoHelper.java] . . . . . . . . . . 3433 Modificação nas queries [ContatoHelper.java] . . . . . . . . . . . . . . . . . 3534 Array de Strings [strings.xml] . . . . . . . . . . . . . . . . . . . . . . . . . . 3635 Adicionando elemento Spinner [res/layout/salvar.xml] . . . . . . . . . . . . 3636 Utilização de Spinner [SalvarActivity.java] . . . . . . . . . . . . . . . . . . . 3737 XML descrevendo layout de preferências [res/xml/preferencias.xml] . . . . . 38

v

Page 6: Guia Aberto Android ed.2

vi LISTA DE CÓDIGOS-FONTE

38 Activity para mostrar preferências [EditarPreferencias.java] . . . . . . . . . 3839 Mapeando Activity EditarPreferencias [AndroidManifest.xml] . . . . . . . . 3840 Adicionar item Preferências ao menu principal [res/menu/main

¯menu.xml] . 39

41 Ir para Preferências pelo menu principal [MainActivity.java] . . . . . . . . . 3942 Mudança em método irParaSalvar [MainActivity.java] . . . . . . . . . . . . 4043 Obtem o valor padrão definido nas Preferências [SalvarActivity.java] . . . . 4044 Item do Layout de Grupos [res/layout/grupos

¯item.xml] . . . . . . . . . . . 41

45 Layout de Grupos [res/layout/grupos.xml] . . . . . . . . . . . . . . . . . . . 4246 Activity para visualizar Grupos [GruposActivity.java] . . . . . . . . . . . . . 4247 Adapter responsável por cada item do Grid [GruposActivity.java] . . . . . . 4348 implementação do Adapter [GruposActivity.java] . . . . . . . . . . . . . . . 4549 Método listar com parâmetro grupo [ContatoHelper.java] . . . . . . . . . . 4650 Evento de clique em um item do grid [GruposActivity.java] . . . . . . . . . 4751 Captura de parâmetro vindo de GruposActivity [MainActivity.java] . . . . 47

Page 7: Guia Aberto Android ed.2

Lista de Tabelas

1.1 Tipos de dados do Sqlite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.1 Convenção para nome dos ícones . . . . . . . . . . . . . . . . . . . . . . . . 11

3.1 Paleta de cores do Android . . . . . . . . . . . . . . . . . . . . . . . . . . . 443.2 Localização e tamanho dos ícones . . . . . . . . . . . . . . . . . . . . . . . . 44

vii

Page 8: Guia Aberto Android ed.2

viii LISTA DE TABELAS

Page 9: Guia Aberto Android ed.2

Lista de Figuras

2.1 Layout linha da Lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3.1 Tela de Grupos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

ix

Page 10: Guia Aberto Android ed.2

x LISTA DE FIGURAS

Page 11: Guia Aberto Android ed.2

Capítulo 1

Preparando o Ambiente deDesenvolvimento

1.1 Introdução

O desenvolvimento de aplicativos para a plataforma Android é feito na linguagem Java.Para esta apostila serão utilizados os seguintes aplicativos e bibliotecas:

I Ubuntu 10.04 ou 12.04

I Java JDK 6 ou 7

I Android SDK

I Android 2.2 API 8

I Eclipse Juno

I ADT Plugin

I Sqlite3

I Sqliteman

I Inkscape

Você pode estar se perguntando: ”Por que utilizar essa configuração?”. Bom, paracomeçar um ambiente de desenvolvimento precisa ser estável, e para isso nada melhor queo http://releases.ubuntu.com/lucid/ (Ubuntu 10.04) ou ainda o http://releases.ubuntu.com/precise/ (Ubuntu 12.04) por serem LTS.

A IDE Eclipse funciona independente do sistema operacional, então podemos utilizara versão mais recente. O mesmo para o plugin ADT.

Usaremos especificamente para os exemplos a seguir a versão 2.2 do Android. EssaAPI é uma ótima escolha inicial, pois é a mais utilizada pelos aparelhos mais simples querodam Android. É claro que você poderá instalar outras versões e compilar seus aplicativospara tablets, etc.

1

Page 12: Guia Aberto Android ed.2

2 CAPÍTULO 1. PREPARANDO O AMBIENTE DE DESENVOLVIMENTO

1.2 InstalaçãoA instalação do Java JDK 6 no Ubuntu 10.04 não é a mesma que no Ubuntu 12.04. Issoporque na época de lançamento do lucid, em 2010, a empresa que desenvolvia o Javaera a Sun Microsystems, que tinha um canal nos repositórios do Ubuntu como parceira(partner). Ainda em 2010 a empresa Oracle comprou a Sun junto com seu software ehardware. Nesse ponto o canal de parceria foi desligado.

Discussões a parte, vamos ver as duas maneiras de instalar o Java.

1.2.1 Java JDK 6

A instalação do Java no Ubuntu 10.04 é bastante simples. Você apenas irá precisar habili-tar repositório de terceiros, ou Partner. Isso pode ser feito através do aplicativo Synaptic.No menu principal do Ubuntu clique em Sistema → Administração → Gerenciadorde pacotes Synaptic.

No menu do Synaptic clique em Configuração → Repositórios. Na aba OutroSoftware temos vários itens que representam repositórios. Marque os dois repositórios queterminam com partner. Feche e depois clique em Editar → Recarregar informaçõesdos pacotes ou simplesmente Ctrl + R.

Após a atualização dos pacotes existentes nos repositórios já é possível encontrar oJava JDK 6. No campo de Pesquisa rápida digite: sun-java6. Clique com botãodireito no pacote sun-java6-jdk e selecione a opção Marcar para instalação. Depoisbasta Aplicar as mudanças. Para isso clique em Editar → Aplicar as alteraçõesmarcadas ou Ctrl + P.

Para a instalação no Ubuntu 12.04 temos que habilitar um repositório de terceiros,também conhecido como PPA (Personal Package Archives). Abra um terminal e executeos passos a seguir para adicionar um repositório e instalar o Java:

$ sudo su# apt-add-repository ppa:flexiondotorg/java# apt-get update# apt-get install sun-java6-jdk

Um pouco de Linux

Para quem não está familiarizado com o ambiente Linux vamos a uma pequena explica-ção. Nos comandos acima aparecem dois caracteres que não devem ser escritos mas querepresentam algo importante no âmbito dos comandos, são eles $ e #. Estes caracteresindicam qual o nível do usuário; $ significa usuário comum, # representa super usuário(root). No comando sudo su é onde trocamos de usuário comum para super usuário.Neste momento você terá que entrar com sua senha de login.

Java JDK 7

Segundo a página de Requerimentos do Sistema (http://developer.android.com/sdk/requirements.html) do site oficial do Android, é necessário uso do Java 6. Caso vocêqueira utilizar o Java 7, você terá que configurar seu projeto Android para ser compiladocom suporte a versão 6.

Page 13: Guia Aberto Android ed.2

1.2. INSTALAÇÃO 3

A instalação do Java 7 no Ubuntu 12.04 pode ser feita da seguinte maneira:

$ sudo su# add-apt-repository ppa:webupd8team/java# apt-get update# apt-get install oracle-jdk7-installer

Após criar o projeto clique com botão direito do mouse em seu projeto e selecioneProperties. Na lista de itens do lado esquerdo selecione Java Compiler. Daí basta clicarem Enable project specific settings e logo abaixo escolher o nível de compilação emCompiler compliance level, escolha 1.6.

1.2.2 Android SDK

Para o Android SDK comece pelo download http://developer.android.com/sdk/index.html.

A instalação é feita apenas colocando o SDK em um diretório do sistema. Existem 2bons locais para abrigar bibliotecas no Linux, são elas: /opt e /usr/local/lib. Nesseexemplo vamos utilizar este último. Abra um terminal e vamos aos comandos.

Se você baixou o SDK para seu diretório Downloads, proceda da seguinte maneira:

$ cd /home/usuario/Downloads$ tar -xf android-sdk

¯r18-linux.tgz

$ sudo su# mv android-sdk-linux /usr/local/lib# cd /usr/local/lib# ln -s android-sdk-linux android-sdk# cd android-sdk/tools# ln -s android /usr/local/bin/android

Obs.: troque usuario na primeira linha pelo seu login do sistema.

O poder do Linux

Dê atenção ao uso do comando ln. Ele é responsável por criar links simbólicos. Isso émuito útil quando se instala um aplicativo ou biblioteca, pois proporciona atualização semque outros ajustes sejam feitos. Neste caso basta linkar outra vez e pronto.

Note que no último comando temos um link simbólico para o diretório /usr/local/bin.É nele que colocamos os executáveis globais, ou seja, que são vistos a partir de qualqueroutro diretório. Agora saindo do modo root e usando seu próprio usuário instalaremos aAPI.

1.2.3 Android 2.2 API 8

Ainda no terminal, agora como usuário comum, vamos abrir o aplicativo que instala qual-quer uma das API disponibilizadas pelo Android.

$ android

Page 14: Guia Aberto Android ed.2

4 CAPÍTULO 1. PREPARANDO O AMBIENTE DE DESENVOLVIMENTO

O aplicativo Android SDK and AVD Manager irá aparecer. Clique em Avaliablepackages e procure pela versão 2.2 API 8 do Android. Selecione e clique em InstallSelected. Após o download você pode verificar a versão instalada em Installed packages,um dos itens é algo como SDK Plataform Android 2.2, API 8, revision 2.

Se você quiser aproveite para baixar outras versões para utilizar em projetos futuros.

1.2.4 Android Virtual Device (AVD)

Vamos aproveitar e criar nosso AVD para testar pela primeira vez nosso emulador. Aindano Android SDK and AVD Manager clique em Virtual devices, depois em New...

Dê um nome. Você pode usar qualquer nomenclatura, mas é interessante que tenhaalgo haver com a versão. Assim, caso você tenha que testar seu código em outras versõesvocê poderá saber qual emulador utilizar. Por exemplo use android-2.2. Em Targetescolha a versão, neste caso Android 2.2 - API Level 8. Pronto, apenas clique emCreate AVD.

Dicas

A opção Skin indica qual a resolução da tela do aparelho. Como não é possível redimen-sionar a janela, em alguns monitores a janela fica maior que a tela do seu monitor.

A opção Snapshot quando habilitada, serve para salvar o estado do emulador. Isso fazcom que da segunda inicialização em diante se torne mais rápida.

A opção SD Card é ideal caso sua aplicação necessite guardar dados como fotos, arqui-vos. O AVD irá reservar um espaço em seu HD permitindo assim o acesso a dados peloemulador.

1.2.5 Eclipse Juno

O IDE Eclipse pode ser encontrada em http://www.eclipse.org/downloads/. Para o de-senvolvimento de aplicativos para o Android a versão Eclipse IDE for Java Developersé ideal. Mas se você tiver interesse em aplicativos Java para Web a opção é baixar a versãoEclipse IDE for Java EE Developers.

Em todo caso as duas vão servir para o desenvolvimento, pois ambas vem com suportea Java.

O Eclipse não possui instalador, no caso ele já vem pré-compilado. Basta apenasdescompactar e executar o arquivo eclipse.

Para sua comodidade você pode adicionar o Eclipse no menu do Ubuntu. Isso podeser feito apenas clicando com o botão direiro do mouse no menu principal e escolhendo aopção Editar menus. Ou você pode usar a dica do blog MAD3 Linux(http://www.mad3linux.org) - http://va.mu/VSgR. Essa dica irá lhe mostrar comoadicionar um item ao menu visível a todos os usuários.

1.2.6 Plugin ADT

Para a instalação do plugin ADT vamos abrir o Eclipse, e em seu menu selecione Help →Eclipse Marketplace...

Busque por adt e escolha o Android Development Tools for Eclipse da Google,Inc., Apache 2.0 e clique em Install. O Eclipse irá pedir confirmação sobre os itens

Page 15: Guia Aberto Android ed.2

1.2. INSTALAÇÃO 5

a serem instalados, clique em Next. Agora basta aceitar os termos de uso e clicar emFinish. Após o download e a instalação, reinicie o Eclipse.

No Eclipse Marketplace você pode encontrar outras ferramentas bastante úteis paraum bom desenvolvimento. Clique na aba Popular e veja as ferramentas mais baixadas,talvez exista uma que você não conheça mas que sempre precisou.

Configurando o ADT

Agora que o plugin foi instalado temos que dizer ao Eclipse onde nós instalamos o AndroidSDK. Isso pode ser feito clicando no menu Window → Preferences. Selecione Androidno painel lateral esquerdo. Em SDK Location clique em Browse... e indique o diretóriodo SDK, caso não lembre, ele está em /usr/local/lib/android-sdk. Clique em Applyna parte inferior direita para atualizar a lista de API’s disponíveis.

Caso você tenha mais dúvidas dê uma olhada na página oficial de instalação do pluginADT localizada em http://developer.android.com/sdk/eclipse-adt.html.

Testando o ADT

Para testar o Android Development Tools ou ADT crie um projeto Android. No menudo Eclipse selecione File → New → Project...

Selecione Android Application Project e clique em Next. Dê um nome qualquerao seu aplicativo, por exemplo hello.android. Note que o ADT tenta dar um nomeao seu pacote e ao diretório de arquivos a partir do nome que você digitou. Deixe comoestá. Em Build SDK é preciso escolher qual API vamos utilizar, em nosso caso escolhaa Android 2.2 (API 8). Em Minimum Required SDK escolha a API 8: Android 2.2(Froyo) indicando que a versão mínima é a API 8. Clique em Next.

Na versão do ADT para o Eclipse Juno, uma novidade apareceu. É possível criar oícone lançador logo ao criar o aplicativo. Selecione da maneira que achar melhor e cliqueem Next. Depois clique em Finish.

Após isso clique com botão direito do mouse no projeto recém criado, e Run As →Android Application. Se tudo tiver dado certo é possível ver no emulador sua primeiraaplicação rodando.

Dicas

Uma vez que você abriu o emulador não o feche. Você irá notar que ao abrir pela primeiravez ele leva um tempo para isso. Neste caso ao atualizar o código-fonte apenas rodeo aplicativo novamente. O plugin ADT fará com que o aplicativo seja reinstalado noemulador.

Faça o teste com alguns atalhos básicos:

Alt + Enter Maximiza o emulador. Ideal para demostrações.

Ctrl + F11 Muda a orientação do emulador, retrato ou paisagem.

F8 Liga/desliga a rede.

Outro elemento essencial é o LogCat. Ele faz parte do ADT e é responsável por mostraras mensagens de log do emulador. Caso você encontre problemas com seu código o LogCatserá seu melhor aliado. Para acessá-lo no Eclipse clique no menu Window → Show View→ Other..., clique em Android → LogCat.

Page 16: Guia Aberto Android ed.2

6 CAPÍTULO 1. PREPARANDO O AMBIENTE DE DESENVOLVIMENTO

1.2.7 Sqlite3

Sendo o Sqlite o banco de dados embutido na plataforma Android, nada melhor do queaprendermos um pouco sobre ele.

O Sqlite é um banco de dados relacional bastante utilizado por dispositivos e sistemasembarcados por ser leve, robusto, de fácil configuração e, acima de tudo, livre. Para ainstalação, abra um terminal como root e:

$ sudo su# apt-get install sqlite3

Após a instalação é possível utilizar o Sqlite via linha de comando. Faça logoff dousuário root e faça os seguintes testes:

# exit$ sqliteSQLite version 2.8.17Enter ".help"for instructionssqlite>

Você deverá ver algo parecido. Para sair utilize o comando .exit. Veja outros detalhesna página oficial do projeto: http://www.sqlite.org/.

Tipos de dados

Utilize a tabela abaixo para criar suas tabelas futuramente.

Nome Descrição

INTEGER valores inteiros, positivos ou negativos. Podem variar de 1 a 8 bytes.

REAL valores reais ou decimais.

TEXT usado para armazenar valores, não-limitado. Suporta várias codifica-ções, por exemplo UTF-8.

BLOB objetos binários tais como imagens, arquivos de texto, etc. Tambémpossui tamanho não-limitado.

NULL representa falta de informação.

Tabela 1.1: Tipos de dados do Sqlite

1.2.8 Sqliteman

Para uma gerência mais produtiva usaremos o Sqliteman para acessar e modificar bancosde dados. A instalação é feita via linha de comando. Abra um terminal e:

$ sudo su# apt-get install sqliteman

Page 17: Guia Aberto Android ed.2

1.2. INSTALAÇÃO 7

Depois de instalado, acesse o aplicativo do menu principal do Ubuntu em Aplicativos→ Escritório → Sqliteman. Faça alguns testes criando bancos de dados, depois criealgumas tabelas. Ele possui assistentes que irão auxiliar nos primeiros momentos.

Por exemplo, crie uma base de dados e depois clique com o botão direito do mouse emTables. Utilize o assistente e veja como é simples criar tabelas no sqlite.

1 -- Distribuições Linux2

3 CREATE TABLE distros (4 _id INTEGER PRIMARY KEY,5 nome TEXT NOT NULL,6 interface TEXT NOT NULL DEFAULT ’Gnome3’ ,7 deriva_de INTEGER REFERENCES distros(_id)8 );9

10 INSERT INTO distros VALUES (1, ’Debian’ , ’Gnome3’ , NULL);11 INSERT INTO distros VALUES (2, ’Ubuntu’ , ’Unity’ , 1);12 INSERT INTO distros VALUES (3, ’Linux Mint’ , ’Mate’ , 2);13 INSERT INTO distros VALUES (4, ’Fedora’ , ’KDE’ , NULL);14 INSERT INTO distros VALUES (5, ’Slackware’ , ’KDE’ , NULL);15 INSERT INTO distros VALUES (6, ’Slax’ , ’KDE’ , 5);16 INSERT INTO distros VALUES (7, ’Ubuntu Studio’ , ’XFCE’ , 2);17 INSERT INTO distros VALUES (8, ’kUbuntu’ , ’KDE’ , 2);18 INSERT INTO distros VALUES (9, ’xUbuntu’ , ’XFCE’ , 2);

Código-fonte 1: Exemplo de banco de dados [exemplo-bd.sql]

Observe que podemos fazer auto-relacionamento na tabela. Assim somos capazes deexecutar a seguinte SQL, contando o número de distros que derivam de uma outra original.Veja:

1 SELECT d._id, d.nome, d.interface,2 (3 SELECT SUM( CASE WHEN aux.deriva_de = d._id THEN 1 ELSE 0 END )4 FROM distros aux5 ) AS num_derivadas6 FROM distros d

Código-fonte 2: Exemplo de query com subquery [exemplo-bd.sql]

Mais informações em: http://sqliteman.com/

1.2.9 Inkscape

Uma ótima ferramenta de desenho vetorial é o Inkscape. Ela será bastante útil pois odesenvolvimento de aplicativos hoje em dia é baseado muito em figuras para facilitar anavegação, identidade visual, entre outras coisas.

Page 18: Guia Aberto Android ed.2

8 CAPÍTULO 1. PREPARANDO O AMBIENTE DE DESENVOLVIMENTO

A instalação é feita de forma simples. Num terminal:

$ sudo su# apt-get install inkscape

Para dicas de como criar ícones para os diversos elementos do Android veja a páginahttp://developer.android.com/design/style/iconography.html.

Page 19: Guia Aberto Android ed.2

Capítulo 2

Exemplo prático

2.1 Primeira aplicação - Contatos

Baseado em 1.2.6 Testando o ADT, crie um novo aplicativo chamado Contatos. Usecontatos.app como o nome do pacote. Crie uma Activity inicial chamada MainActivitye um layout inicial chamado main. Depois clique em Finish.

Este exemplo é bastante útil para aprendermos como funciona o Android. Você sópoderá criar algo se você souber utilizar bem as ferramentas.

2.1.1 AndroidManifest.xml

Este é o arquivo que define nossa aplicação, mapeia as Activity’s, entre outras configura-ções. Ao finalizar a criação do projeto, inicialmente este arquivo deverá conter o seguinteconteúdo:

1 <?xml version="1.0" encoding="UTF-8"?>2 <manifest xmlns:android= "http://schemas.android.com/apk/res/android"3 package= "contatos.app"4 android:versionCode= "1"5 android:versionName= "1.0" >6 <uses-sdk android:minSdkVersion= "8" android:targetSdkVersion= "8" />7 <application android:icon= "@drawable/icon" android:label= "@string/app_name" >

8 <activity android:name= ".MainActivity" android:label= "@string/app_name" >9 <intent-filter>

10 <action android:name= "android.intent.action.MAIN" />11 <category android:name= "android.intent.category.LAUNCHER" />12 </intent-filter>13 </activity>14 </application>15 </manifest>

Código-fonte 3: Projeto inicial [AndroidManifest.xml]

9

Page 20: Guia Aberto Android ed.2

10 CAPÍTULO 2. EXEMPLO PRÁTICO

2.1.2 Activity

Não existe método main visível ao programador no Android. Ao invés disso temosActivity’s. Para que o Android saiba qual ele deve iniciar primeiro utilizamos umintent-filter como visto no trecho de código acima da linha 09 a 12 . Para nossaprimeira Activity criaremos uma lista de contatos e um menu para criação de um novocontato.

Para construir o layout inicial de nossa aplicação precisamos editar o arquivo main.xmllocalizado em res/layout.

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 <ListView7 android:id= "@+id/lv_contatos"8 android:layout_width= "fill_parent"9 android:layout_height= "wrap_content" />

10 </LinearLayout>

Código-fonte 4: Layout principal [res/layout/main.xml]

Deste momento em diante tenha em mente que os arquivos xml aqui descritos sãoapenas para você poder comparar e ver se não esqueceu de nada. Todos os layout’s devemser criados usando a ferramenta ADT. Você irá notar que ao abrir o xml uma janela delayout aparecerá. Para visualizar o xml ou o layout gráfico basta utilizar a aba inferioresquerda.

Por fim, temos o menu. Clique com o botão direito do mouse em seu projeto e New →Other... ou Ctrl + N. Procure por Android XML File. Em Resource Type escolha aopção Menu. Chame-o de main

¯menu.xml.

1 <?xml version="1.0" encoding="UTF-8"?>2 <menu xmlns:android= "http://schemas.android.com/apk/res/android" >3 <item4 android:id= "@+id/menu_add"5 android:title= "Novo"6 android:icon= "@android:drawable/ic_menu_add" />7 </menu>

Código-fonte 5: Menu principal [res/menu/main¯menu.xml]

Pronto, já temos nosso layout. Compile o projeto e vamos a próxima iteração.

Page 21: Guia Aberto Android ed.2

2.1. PRIMEIRA APLICAÇÃO - CONTATOS 11

Convenção de nomes para ícones

Observe que o ícone utilizado no menu vem junto com o SDK do Android. Você podevisualizar os ícones em SDK

¯INSTALL/plataforms/android-8/data/res/drawable-hdpi

(substitua SDK¯INSTALL pelo diretório de instalação do SDK do Android, no nosso caso

usr/local/lib/android-sdk, 1.2.2). Note que há namespaces ou prefixos em cada umdos ícones. O Android recomenda a seguinte convenção:

Tipo de Recurso Prefixo Exemplo

Ícones ic¯

ic¯adicionar.png

Launcher icons ic¯launcher

¯ic¯launcher

¯calendario.png

Menu e Action Bar ic¯menu

¯ic¯menu

¯ajuda.png

Status bar icons ic¯stat

¯notify

¯ic¯stat

¯notify

¯msg.png

Tab icons ic¯tab

¯ic¯tab

¯recente.png

Dialog icons ic¯dialog

¯ic¯dialog

¯info.png

Tabela 2.1: Convenção para nome dos ícones

Note que você não é obrigado a utilizar os prefixos citados acima, isto é apenas umaconvenção. Veja mais detalhes em http://developer.android.com/guide/practices/ui_guidelines/icon_design.html.

Abra o arquivo MainActivity.java e vá ao método onCreate. Defina o layout comosendo nosso main.xml. Para isso adicione o layout main ao final do método:

1 @Override2 public void onCreate(Bundle icicle) {3 super.onCreate(icicle);4 setContentView(R.layout.main);5 }

Código-fonte 6: Definir layout [MainActivity.java]

Cuidado: no ambiente Android temos uma classe chamada R. Ela existe tanto na biblio-teca do Android como em cada projeto. Nesse caso faça o import da classe contatos.app.R.A classe android.R é utilizada em outras situações, onde códigos pré-prontos foram dis-ponibilizados pela equipe do Android.

Agora precisamos sobrescrever os métodos onCreateOptionsMenu e onOptionsItemSelected.Eles irão criar o menu a partir de nosso layout e notificar quando os itens do menu forempressionados, respectivamente. Vamos ao código:

Page 22: Guia Aberto Android ed.2

12 CAPÍTULO 2. EXEMPLO PRÁTICO

1 @Override2 public boolean onCreateOptionsMenu(Menu menu) {3 new MenuInflater(this).inflate(R.menu.main_menu, menu);4 return super.onCreateOptionsMenu(menu);5 }6

7 @Override8 public boolean onOptionsItemSelected(MenuItem item) {9 if (item.getItemId() == R.id.menu_add) {

10 irParaSalvar();11 return true;12 }13 return super.onOptionsItemSelected(item);14 }15

16 private void irParaSalvar() {17 // não implementado ainda ...18 }

Código-fonte 7: Criando o menu [MainActivity.java]

2.1.3 Formulários

Agora vamos criar nosso formulário para criação e edição de contatos. Começaremos pelolayout. Crie um arquivo xml em res/layout chamado salvar.xml.

Existem alguns pontos importantes para este trecho de código. Começando pelo layoutinicial, onde usaremos TableLayout. Esse layout é ideal para telas com estilo tabela.

Um detalhe importante para observarmos neste layout é que ele possui o atributostretchColumns com valor 1. Isso quer dizer que a coluna 1 da tabela terá o maiortamanho possível, respeitando o tamanho mínimo das outras células. Para visualizar asmudanças você pode tentar usar outros valores como 0 tornando a primeira coluna maiorque as demais, ou ainda * que fará com que todas as células tenham o mesmo tamanho.

Page 23: Guia Aberto Android ed.2

2.1. PRIMEIRA APLICAÇÃO - CONTATOS 13

1 <?xml version="1.0" encoding="UTF-8"?>2 <RelativeLayout3 android:id= "@+id/widget31"4 android:layout_width= "fill_parent"5 android:layout_height= "fill_parent"

6 xmlns:android= "http://schemas.android.com/apk/res/android" >7 <TableLayout8 android:id= "@+id/widget32"9 android:layout_width= "fill_parent"

10 android:layout_height= "wrap_content"11 android:orientation= "vertical"12 android:stretchColumns= "1" >13 <TableRow14 android:id= "@+id/widget33"15 android:layout_width= "fill_parent"16 android:layout_height= "wrap_content"17 android:orientation= "horizontal" >18 <TextView19 android:id= "@+id/textView1"20 android:layout_width= "wrap_content"21 android:layout_height= "wrap_content"22 android:text= "Nome" ></TextView>23 <EditText24 android:id= "@+id/et_nome"25 android:layout_width= "wrap_content"26 android:layout_height= "wrap_content" ></EditText>27 </TableRow>28 <!-- faça mais duas TableRow’s contendo o Telefone e E-mail -->29 <Button30 android:id= "@+id/bt_salvar"31 android:text= "Salvar"32 android:layout_height= "wrap_content"33 android:layout_width= "fill_parent" ></Button>34 </TableLayout>35 </RelativeLayout>

Código-fonte 8: Formulário principal [res/layout/salvar.xml]

Crie uma nova Activity chamada SalvarActivity dentro de contatos.app.view.Para irmos de uma Activity para outra precisamos de um Intent. Um de seus constru-tores recebe como parâmetros a instância da classe em que estamos, sendo que ela deveimplementar a interface Context e o nome da classe a qual deve ser mostrada. Veja comoimplementar o método irParaSalvar da classe MainActivity:

Page 24: Guia Aberto Android ed.2

14 CAPÍTULO 2. EXEMPLO PRÁTICO

1 private void irParaSalvar() {2 Intent intent = new Intent(MainActivity.this, SaveActivity.class);3 startActivity(intent);4 }

Código-fonte 9: Mudando de Activity [MainActivity.java]

Veremos agora como manipular EditText’s, que representam os campos de entradade dados. Abra o SalvarActivity e adicione o método carregar e crie atributos paraguardar os EditText’s:

1 private EditText etNome, etFone, etEmail;2 /* ... */3

4 @Override5 public void onCreate(Bundle icicle) {6 super.onCreate(icicle);7 setContentView(R.layout.salvar);8 carregar();9 }

10

11 private void carregar() {12 etNome = (EditText) findViewById(R.id.et_nome);13 etTefone = (EditText) findViewById(R.id.et_telefone);14 etEmail = (EditText) findViewById(R.id.et_email);15 }

Código-fonte 10: Utilizando EditText’s [SalvarActivity.java]

Para que a Activity funcione precisamos mapeá-la no arquivo AndroidManifest.xml.Adicione o conteúdo abaixo entre as tags application:

1 <activity android:name= ".view.SalvarActivity" ></activity>

Código-fonte 11: Mapear SalvarActivity [AndroidManifest.xml]

Utilize sempre o ADT e apenas confira se o arquivo está da maneira correta.

2.1.4 Construindo o Model da aplicação

Precisamos de um helper para fazer acesso ao banco de dados. O Android provê suporte abancos de dados Sqlite por padrão. Qualquer banco de dados que você criar será acessívelpelo nome por qualquer classe na sua aplicação, mas não fora dela.

Crie uma classe chamada ContatoHelper em contatos.app.model que extende deSQLiteOpenHelper. Essa classe será capaz de ler e escrever no banco de dados graças aosmétodos getReadableDatabase() e getWritableDatabase(), respectivamente.

Page 25: Guia Aberto Android ed.2

2.1. PRIMEIRA APLICAÇÃO - CONTATOS 15

A princípio temos que criar um construtor passando como parâmetros o nome do bancode dados e a versão da DDL (Data Definition Language). Logo em seguida precisamosimplementar os métodos onCreate, no qual iremos criar as tabelas e onUpdate, casotenhamos que alterar alguma tabela.

1 package contatos.app.model;2

3 import android.content.Context;4 import android.database.sqlite.SQLiteDatabase;5 import android.database.sqlite.SQLiteOpenHelper;6

7 public class ContatoHelper extends SQLiteOpenHelper {8

9 private static final String DATABASE_NAME = "contatos.db" ;10 private static final int VERSION = 1;11

12 public ContatoHelper(Context context) {13 super(context, DATABASE_NAME, null, VERSION);14 }15

16 @Override17 public void onCreate(SQLiteDatabase db) {18 db.execSQL( "CREATE TABLE contato (_id INTEGER PRIMARY KEY AUTOINCREMENT,"

19 + " nome TEXT, fone TEXT, email TEXT);" );20 }21

22 @Override23 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {24 // nada a fazer por enquanto ...25 }26 }

Código-fonte 12: Helper da aplicação [ContatoHelper.java]

Para a iteração de criação de um novo contato, ainda em ContatoHelper vamos adi-cionar um método criar. Faça:

1 public void criar(ContentValues values) {2 getWritableDatabase().insert( "contato" , "telefone" , values);3 }

Código-fonte 13: Criar novo contato [ContatoHelper.java]

Agora temos que fazer a chamada do método criar da classe ContatoHelper emSalvarActivity. Para isso temos que criar uma instância de ContatoHelper, adicionaro botão salvar e adicionar um Listener de click (faça o import da classeandroid.view.View.OnClickListener). Vamos ao código:

Page 26: Guia Aberto Android ed.2

16 CAPÍTULO 2. EXEMPLO PRÁTICO

1 /* ... */2 private ContatoHelper helper;3 private Button btSalvar;4

5 @Override6 public void onCreate(Bundle icicle) {7 /* ... */8 helper = new ContatoHelper(this);9 carregar();

10 ir();11 /* ... */12 }13

14 private void carregar() {15 /* ... */16 btSalvar = (Button) findViewById(R.id.bt_salvar);17 }18

19 private void ir() {20 btSalvar.setOnClickListener(new OnClickListener() {21

22 public void onClick(View view) {23 ContentValues values = new ContentValues();24 values.put( "nome" , etNome.getText().toString());25 values.put( "telefone" , etTefone.getText().toString());26 values.put( "email" , etEmail.getText().toString());27 helper.criar(values);28 finish();29 }30 });31 }32

33 @Override34 protected void onDestroy() {35 super.onDestroy();36 helper.close();37 }

Código-fonte 14: Fim da iteração criar contato [SalvarActivity.java]

Com essa implementação já é possível salvar contatos na base de dados.

2.1.5 Mostrando os dados na View

Após salvar os dados no banco, devemos ser capazes de obter tais informações e colocá-las em forma de Lista. Para isso criaremos um novo layout que será responsável porrepresentar uma linha de nossa Lista. Essa linha deve ser semelhante a figura abaixo:

Page 27: Guia Aberto Android ed.2

2.1. PRIMEIRA APLICAÇÃO - CONTATOS 17

Figura 2.1: Layout linha da Lista

Para isso crie um arquivo chamado linha.xml em res/layout com o seguinte con-teúdo.

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" android:layout_height= "wrap_content"4 android:orientation= "horizontal" >5 <ImageView6 android:id= "@+id/linha_icone" android:layout_width= "wrap_content"

7 android:layout_height= "fill_parent" android:src= "@drawable/ic_launcher" >8 </ImageView>9 <LinearLayout

10 android:layout_width= "fill_parent" android:layout_height= "wrap_content"11 android:orientation= "vertical" >12 <TextView13 android:id= "@+id/linha_nome" android:layout_width= "fill_parent"14 android:layout_height= "wrap_content" android:textStyle= "bold"15 android:ellipsize= "end" ></TextView>16 <TextView17 android:id= "@+id/linha_fone" android:layout_width= "fill_parent"18 android:layout_height= "wrap_content" ></TextView>19 <TextView20 android:id= "@+id/linha_email" android:layout_width= "fill_parent"21 android:layout_height= "wrap_content" ></TextView>22 </LinearLayout>23 </LinearLayout>

Código-fonte 15: Layout para cada linha da lista [res/layout/linha.xml]

Note a possibilidade de aninhar o LinearLayout. Fazendo isso é possível criar olayout desejado fazendo com que alguns elementos sejam inseridos na horizontal, outrosna vertical.

Outro ponto interessante é o uso de negrito no TextView correspondente ao nome, na li-nha 14 , e o uso de reticências caso o nome seja maior que a tela usando android:ellipsize="end"na linha 15 .

Page 28: Guia Aberto Android ed.2

18 CAPÍTULO 2. EXEMPLO PRÁTICO

Agora vamos até ContatoHelper e adicionar o método listar. E também adiciona-remos métodos para facilitar a obtenção dos valores de cada atributo.

1 public Cursor listar() {2 return getReadableDatabase()3 .rawQuery( "SELECT _id, nome, fone, email FROM contato ORDER BY nome" ,4 null);5 }6

7 public String getNome(Cursor c) {8 return c.getString(1);9 }

10

11 public String getFone(Cursor c) {12 return c.getString(2);13 }14

15 public String getEmail(Cursor c) {16 return c.getString(3);17 }

Código-fonte 16: Listar contatos existentes [ContatoHelper.java]

Os elementos de um Cursor são numerados iniciando de 0 (zero). Neste caso o 0 é acoluna

¯id. Note que ela não será usada pelo programador e sim pelo Android. Isto será

visto com mais detalhes em 2.1.6 Editando dados existentes.Para popular cada linha de nossa Lista vamos criar uma classe interna (inner class)

em MainActivity. Assim podemos fazer cache dos objetos aumentando a performance.Use o sufixo Holder para esse tipo de classe.

1 private static class ContatoHolder {2 private TextView nome, fone, email = null;3

4 public ContatoHolder(View linha) {5 nome = (TextView) linha.findViewById(R.id.linha_nome);6 fone = (TextView) linha.findViewById(R.id.linha_fone);7 email = (TextView) linha.findViewById(R.id.linha_email);8 }9

10 public void popularForm(Cursor c, ContatoHelper helper) {11 nome.setText(helper.getNome(c));12 fone.setText(helper.getFone(c));13 email.setText(helper.getEmail(c));14 }15 }

Código-fonte 17: Classe Holder [MainActivity.java]

Page 29: Guia Aberto Android ed.2

2.1. PRIMEIRA APLICAÇÃO - CONTATOS 19

Levando em conta que estamos usando a interface Cursor em nosso Helper temosque criar uma classe que extenda de CursorAdapter que será responsável por definir olayout de cada linha da Lista. Crie uma classe interna chamada ContatoAdapter. Iremossobrescrever dois métodos, newView() e bindView(), que são responsáveis por inflar(inflate) uma nova linha e reciclar uma linha existente, respectivamente.

1 private ContatoHelper helper;2 /* ... */3

4 private class ContatoAdapter extends CursorAdapter {5

6 public ContatoAdapter(Cursor c) {7 super(MainActivity.this, c);8 }9

10 @Override11 public View newView(Context cntxt, Cursor cursor, ViewGroup vg) {12 LayoutInflater inflater = getLayoutInflater();13 View linha = inflater.inflate(R.layout.linha, vg, false);14 ContatoHolder holder = new ContatoHolder(linha);15 linha.setTag(holder);16 return linha;17 }18

19 @Override20 public void bindView(View view, Context cntxt, Cursor cursor) {21 ContatoHolder holder = (ContatoHolder) view.getTag();22 holder.popularForm(cursor, helper);23 }24 }

Código-fonte 18: Classe Adapter [MainActivity.java]

Com a introdução do Helper teremos que criar uma instância da classe Cursor parapopular nossa ListView. Vamos ao código-fonte:

Page 30: Guia Aberto Android ed.2

20 CAPÍTULO 2. EXEMPLO PRÁTICO

1 /* ... */2 private Cursor model = null;3 private ContatoAdapter adapter = null;4 private ListView listView = null;5

6 @Override7 public void onCreate(Bundle icicle) {8 /* ... */9 helper = new ContatoHelper(this);

10 carregar();11 }12

13 private void carregar() {14 listView = (ListView) findViewById(R.id.lv_contatos);15 model = helper.listar();16 startManagingCursor(model);17 adapter = new ContatoAdapter(model);18 listView.setAdapter(adapter);19 }20

21 @Override22 protected void onDestroy() {23 super.onDestroy();24 model.close();25 helper.close();26 }

Código-fonte 19: Popular ListView [MainActivity.java]

Nunca esquecendo de fechar o helper ao sair, pois assim garantimos que a conexãocom o banco será fechada.

2.1.6 Editando dados existentes

Para a edição de informações usaremos o mesmo Activity do criar, ou seja, SalvarActivity.Para isso precisamos passar um parâmetro para o Activity. Usaremos então um métododo Intent que é responsável por isso, putExtra(chave, valor).

Para uma passagem de parâmetros segura devemos usar um namespace para que nãocolida com nenhum nome já utilizado pelo Android. Assim, vamos criar uma variávelestática do tipo String. Isso acontecerá quando o usuário pressionar a linha que eledeseja editar. Podemos fazer isso utilizando a interface OnItemClickListener.

Vamos incrementar também o método irParaSalvar passando o parâmetro caso hajaum. Vamos ao código:

Page 31: Guia Aberto Android ed.2

2.1. PRIMEIRA APLICAÇÃO - CONTATOS 21

1 /* ... */2 public static final String _ID = "contatos.app._ID" ;3

4 @Override5 public void onCreate(Bundle icicle) {6 /* ... */7 configurar();8 }9

10 private void irParaSalvar() {11 irParaSalvar(null);12 }13

14 private void irParaSalvar(String id) {15 Intent intent = new Intent(MainActivity.this, SalvarActivity.class);16 if (id != null) {17 intent.putExtra(_ID, id);18 }19 startActivity(intent);20 }21

22 private void configurar() {23 listView.setOnItemClickListener(new OnItemClickListener() {24 public void onItemClick(AdapterView<?> parent, View view,25 int position, long id) {26 irParaSalvar(String.valueOf(id));27 }28 });29 }

Código-fonte 20: Passagem de parâmetros [MainActivity.java]

Agora é hora de tratar nosso parâmetro no SalvarActivity. Caso haja um parâmetroprecisamos obter os dados existentes no banco de dados para então editá-lo. Neste casoprecisaremos de mais dois métodos em ContatoHelper, que são ler e atualizar.

1 public Cursor ler(String id) {2 return getReadableDatabase().rawQuery( "SELECT _id, nome, telefone, " +3 "email FROM contato WHERE _id = ?" , new String[]{id});4 }5

6 public void atualizar(String id, ContentValues values) {7 getWritableDatabase().update( "contato" , values, "_id = ?" , new String[]{id});8 }

Código-fonte 21: Ler e atualizar dados existentes [ContatoHelper.java]

Page 32: Guia Aberto Android ed.2

22 CAPÍTULO 2. EXEMPLO PRÁTICO

O próximo passo é tratar no SalvarActivity caso o parâmetro tenha sido enviadoou não. Caso positivo devemos carregar os dados existentes no banco de dados e depoisatualizá-los.

1 /* ... */2 private String contatoId = null;3

4 private void carregar() {5 /* ... */6 contatoId = getIntent().getStringExtra(MainActivity._ID);7 if (contatoId != null) {8 carregarContato();9 }

10 }11

12 private void carregarContato() {13 Cursor cursor = helper.ler(contatoId);14 cursor.moveToFirst();15 etNome.setText(helper.getNome(cursor));16 etFone.setText(helper.getFone(cursor));17 etEmail.setText(helper.getEmail(cursor));18 cursor.close();19 }20

21 private void ir() {22 btSalvar.setOnClickListener(new OnClickListener() {23 public void onClick(View view) {24 ContentValues values = new ContentValues();25 values.put( "nome" , etNome.getText().toString());26 values.put( "telefone" , etTefone.getText().toString());27 values.put( "email" , etEmail.getText().toString());28 if (contatoId == null) {29 helper.criar(values);30 } else {31 helper.atualizar(contatoId, values);32 }33 finish();34 }35 });36 }

Código-fonte 22: Usando Activity para criar ou atualizar [SalvarActivity.java]

Com isso encerramos um CRUD básico, mas completo. A seguir temos implementa-ções mais específicas que irão tornar nossa aplicação mais profissional.

Page 33: Guia Aberto Android ed.2

Capítulo 3

Livro de Receitas

3.1 Mostrando Diálogos

No Android, podemos criar diálogos no Activity mostrando opções ao usuário, como porexemplo, escolher itens de uma lista, ou responder sim ou não a uma ação, etc.

Vamos incrementar algumas partes de nosso código e tentar encaixar algumas funcio-nalidades relacionadas.

3.1.1 Editar/Excluir ao clicar e segurar na ListView

Vamos implementar uma ação comum no mundo Android, que é a seguinte: ao clicar esegurar num item da ListView, ele mostra opções editar e excluir, por exemplo. Isto podeser feito facilmente usando AlertDialog.Builder, uma classe com métodos pré-prontospara serem usados por você.

Neste exemplo, precisaremos editar ContatoHelper e adicionar um método para de-letar um contato, editar nosso MainActivity no método configurar e adicionar umListener que ao clicar e segurar num item da ListView um método é acionado. Vamos aimplementação:

1 public int deletar(String id) {2 String whereClause = "_id = ?" ;3 String[] whereArgs = {id};4 return getWritableDatabase().delete( "contato" , whereClause, whereArgs);5 }

Código-fonte 23: Deletar dados existentes [ContatoHelper.java]

23

Page 34: Guia Aberto Android ed.2

24 CAPÍTULO 3. LIVRO DE RECEITAS

1 /* ... */2 private void configurar() {3 /* ... */4 listView.setOnItemLongClickListener(new OnItemLongClickListener() {5 public boolean onItemLongClick(AdapterView<?> parent, View view,6 int position, final long id) {7 final String[] itens = { "Editar" , "Deletar" };8 AlertDialog.Builder dialogo =9 new AlertDialog.Builder(MainActivity.this);

10 dialogo.setTitle( "Opções" );11 dialogo.setItems(itens, new OnClickListener() {12 public void onClick(DialogInterface dialog, int which) {13 switch (which) {14 case 0: // editar15 irParaSalvar(String.valueOf(id));16 break;17 case 1: // deletar18 int linhasAfetadas = helper.deletar(String.valueOf(id));19 if (linhasAfetadas > 0) {20 exibirMensagem( "Contatos deletado com sucesso." );21 carregar();22 } else {23 exibirMensagem( "Falha ao deletar contato." );24 }25 break;26 }27 }28 });29 dialogo.show();30 return true;31 }32 });33 }34

35 private void exibirMensagem(String mensagem) {36 Toast.makeText(this, mensagem, Toast.LENGTH_LONG).show();37 }

Código-fonte 24: Adicionar Listener para click longo [MainActivity.java]

Note a necessidade de um novo método em MainActivity, o exibirMensagem. Ele ébastante útil quando se quer exibir uma mensagem rapidamente e depois ela suma. Paraisso usamos a classe Toast.

Page 35: Guia Aberto Android ed.2

3.1. MOSTRANDO DIÁLOGOS 25

Interface como parâmetro de um método

Você já deve ter notado o uso de interface’s como parâmetro dos métodos, por exemplona linha 4 e 11 do código acima. Essa prática obriga ao programador implementar aclasse na passagem dos parâmetros.

Essa ideia vem de algumas linguagens de programação que possuem funções comoparâmetros para outras funções. Como o Java não suporta essa característica, a soluçãoveio em forma de uma interface, a qual o programador é obrigado a implementar seusmétodos. Com isso o método que recebe a interface como parâmetro sabe exatamente oque ela tem disponível.

A partir dessa observação, podemos justificar o uso da palavra reservada final emalguns parâmetros dos métodos acima. Isso acontece porque alguns parâmetros são utili-zados dentro da implementação das interface’s.

Caso haja a necessidade de utilizar uma implementação em outra classe você pode criaruma classe que implementa uma interface, por exemplo a interface OnItemLongClickListener.Daí para a passagem do parâmetro apenas crie uma instância da classe. Por exemplo, supo-nha que você tenha uma classe chamada OpcoesContato que implementa OnItemLongClickListener,nesse caso a linha 4 se tornaria:

listView.setOnItemLongClickListener(new OpcoesContato());

3.1.2 Diálogo de confirmação

Deletar dados é uma ação que deve ser feita com cuidado, então sempre é bom confirmarcom o usuário se ele deseja realmente deletar, no nosso caso, um contato. Para issousaremos o AlertDialog.Builder mais uma vez, agora apenas com uma mensagem e osbotões Sim ou Não.

Ainda em MainActivity criaremos um outro AlertDialog.Builder no momento queo usuário clicar em Deletar. Segue o trecho:

Page 36: Guia Aberto Android ed.2

26 CAPÍTULO 3. LIVRO DE RECEITAS

1 /* ... */2 private void configurar() {3 /* ... */4 listView.setOnItemLongClickListener(new OnItemLongClickListener() {5 public boolean onItemLongClick(AdapterView<?> parent, View view,6 int position, final long id) {7 /* ... */8 dialogo.setItems(itens, new OnClickListener() {9 public void onClick(DialogInterface dialog, int which) {

10 switch (which) {11 case 0: // editar12 irParaSalvar(String.valueOf(id));13 break;14 case 1: // deletar15 AlertDialog.Builder confirmacao =16 new AlertDialog.Builder(MainActivity.this);17 confirmacao.setTitle( "Deletar" );18 confirmacao.setMessage( "Deseja realmente deletar este contato?" );19 confirmacao.setPositiveButton( "Sim" , new OnClickListener() {20 public void onClick(DialogInterface dialog, int which) {21 int linhasAfetadas = helper.deletar(String.valueOf(id));22 if (linhasAfetadas > 0) {23 exibirMensagem( "Contatos deletado com sucesso." );24 carregar();25 } else {26 exibirMensagem( "Falha ao deletar contato." );27 }28 }29 });30 confirmacao.setNegativeButton( "Não" , null);31 confirmacao.show();32 break;33 }34 }35 });36 dialogo.show();37 return true;38 }39 });40 }

Código-fonte 25: Diálogo de confirmação ao deletar contato [MainActivity.java]

Pronto, agora o trecho que deleta o contato foi movido para dentro do Listener dobotão Sim. No botão Não passamos null no Listener, pois caso seja a opção escolhidaapenas fazemos nada. Você pode se quiser criar um Listener e mostrar uma mensagemdo tipo, Cancelado pelo usuário, para isso usando o método exibirMensagem.

Page 37: Guia Aberto Android ed.2

3.1. MOSTRANDO DIÁLOGOS 27

3.1.3 Entrada de diferentes tipos de dados

O Android foi desenvolvido com muitos recursos pré-prontos para facilitar o desenvolvi-mento de aplicações. Um recurso bastante útil é a distinção dos dados que irão ser inseridosnos TextView’s. Com isso o teclado virtual do cliente se adapta ao tipo de dado que seráinserido. No nosso caso faremos distinção do campo telefone, onde apenas números ehífens (-) podem ser inseridos, e o campo e-mail onde a presença do arroba (@) e pontos(.) são elementos essenciais.

Vejamos alguns valores aceitos pelo inputType:

I Para textos:

. text

. textCapCharacters

. textMultiLine

. textUri

. textEmailAddress

. textPersonName

. textPassword

. textVisiblePassword

I Para números:

. number

. numberSigned

. numberDecimal

. phone

. datetime

. date

. time

Precisaremos alterar apenas o salvar.xml localizado em res/layout. Localize oatributo inputType dos campos telefone e e-mail e altere os valores da seguinte maneira:

Page 38: Guia Aberto Android ed.2

28 CAPÍTULO 3. LIVRO DE RECEITAS

1 <!-- ... -->2 <TableRow android:id= "@+id/tableRow2"3 android:layout_width= "wrap_content"4 android:layout_height= "wrap_content" >

5 <TextView android:id= "@+id/textView2"6 android:layout_width= "wrap_content"7 android:layout_height= "wrap_content"8 android:text= "Telefone:" ></TextView>9 <EditText android:layout_width= "wrap_content"

10 android:layout_height= "wrap_content"

11 android:id= "@+id/et_telefone"12 android:inputType= "phone" ></EditText>13 </TableRow>14 <TableRow android:id= "@+id/tableRow3"15 android:layout_width= "wrap_content"16 android:layout_height= "wrap_content" >

17 <TextView android:id= "@+id/textView3"18 android:layout_width= "wrap_content"19 android:layout_height= "wrap_content"20 android:text= "E-mail:" ></TextView>21 <EditText android:layout_width= "wrap_content"22 android:layout_height= "wrap_content"

23 android:id= "@+id/et_email"24 android:inputType= "textEmailAddress" ></EditText>25 </TableRow>26 <!-- ... -->

Código-fonte 26: Distinção de dados [res/layout/salvar.xml]

3.1.4 Validação de dados

Mesmo configurando um inputType para seu TextView pode não ser o bastante paraque os dados inseridos estejam corretos. Para isso usaremos a classe Patterns do pacoteandroid.util. Nela podemos encontrar alguns objetos bastante úteis na hora de validardados. Entre eles estão os objetos Patterns.EMAIL

¯ADDRESS e Patterns.PHONE. Com

eles podemos validar de forma simples os dados inseridos em nosso formulário.Em nosso SalvarActivity adicionaremos um método validar passando como pa-

râmetro um ContentValues. Copie o método exibirMensagem da classe MainActivitypara mostrar uma mensagem caso alguma validação seja falsa.

OBS: Para ummelhor reuso crie uma classe abstrata que implementa o método exibirMensageme que extenda de Activity e faça com que seus Activity’s herdem dela. É uma boa prá-tica.

Vamos ao trecho de código:

Page 39: Guia Aberto Android ed.2

3.1. MOSTRANDO DIÁLOGOS 29

1 /* ... */2 private void ir() {3 btSalvar.setOnClickListener(new OnClickListener() {4

5 public void onClick(View view) {6 ContentValues values = new ContentValues();7 values.put( "nome" , etNome.getText().toString());8 values.put( "telefone" , etTefone.getText().toString());9 values.put( "email" , etEmail.getText().toString());

10 if (validar(values)) {11 if (contatoId == null) {12 helper.criar(values);13 } else {14 helper.atualizar(contatoId, values);15 }16 finish();17 }18 }19 });20 }21

22 private boolean validar(ContentValues values) {23 if (!Patterns.PHONE.matcher(values.getAsString( "telefone" )).matches()) {24 exibirMensagem( "Telefone não é válido." );25 return false;26 }27

28 if (!Patterns.EMAIL_ADDRESS.matcher(values.getAsString( "email" )).matches()) {29 exibirMensagem( "E-mail não é válido." );30 return false;31 }32 return true;33 }34

35 private void exibirMensagem(String mensagem) {36 Toast.makeText(this, mensagem, Toast.LENGTH_LONG).show();37 }38 /* ... */

Código-fonte 27: Validação dos dados [SalvarActivity.java]

3.1.5 Fazendo uma ligação

Já que estamos fazendo uma lista de contatos nada melhor que usar o número do telefonedos contatos inseridos para realizar chamadas. Para isso vamos aprender um pouco sobrePermissões.

Permissões no Android são definidas no AndroidManifest.xml. Ao instalar seu aplica-

Page 40: Guia Aberto Android ed.2

30 CAPÍTULO 3. LIVRO DE RECEITAS

tivo, o usuário saberá quais as permissões que o seu aplicativo necessita para ser executado.Por padrão, o Android traz uma série de permissões que auxiliam seu aplicativo a se

comunicar com o aparelho. Abaixo alguns exemplos:

I Verificação

. ACCESS¯NETWORK

¯STATE

. ACCESS¯WIFI

¯STATE

. BATTERY¯STATS

I Comunicação

. BLUETOOTH

. CALL¯PHONE

. INTERNET

. SEND¯SMS

A lista completa pode ser vista em http://developer.android.com/reference/android/Manifest.permission.html.

Edite o AndroidManifest.xml e adicione a permissao CALL¯PHONE.

1 <?xml version="1.0" encoding="UTF-8"?>2 <manifest xmlns:android= "http://schemas.android.com/apk/res/android"3 package= "contatos.app"4 android:versionCode= "1"5 android:versionName= "1.0" >6 <uses-permission android:name= "android.permission.CALL_PHONE" >7 </uses-permission>8 <!-- ... -->9 </manifest>

Código-fonte 28: Permissão de realizar chamadas [AndroidManifest.xml]

Agora vamos adicionar um item ao diálogo que aparece ao clicar e segurar um itemda ListView. Ele servirá para implementarmos o trecho que realiza a chamada. Vamos aele:

Page 41: Guia Aberto Android ed.2

3.1. MOSTRANDO DIÁLOGOS 31

1 /* ... */2 private void configurar() {3 listView.setOnItemLongClickListener(new OnItemLongClickListener() {4 public boolean onItemLongClick(AdapterView<?> parent, View view,5 final int position, final long id) {6 final String[] itens = { "Editar" , "Deletar" , "Chamar" };7 /* ... */8 dialogo.setItems(itens, new OnClickListener() {9 public void onClick(DialogInterface dialog, int which) {

10 switch (which) {11 /* ... */12 case 2: // chamar13 model.moveToPosition(position);14 startActivity(new Intent(Intent.ACTION_CALL,15 Uri.parse( "tel:" + helper.getTelefone(model))16 )17 );18 break;19 }20 }21 });22 dialogo.show();23 return true;24 }25 });26 }

Código-fonte 29: Item chamar no diálogo [MainActivity.java]

Nesse trecho de código podemos ver o uso de Intent’s do prórpio Android, nessecaso o Intent.ACTION

¯CALL (veja linha 14 ). Ele serve para chamar uma Activity

que realize ligações. Atente apenas para um detalhe - esse Intent faz a chamada semconfirmação. Caso você queira que o usuário possa visualizar o número no discador use oIntent Intent.ACTION

¯DIAL. Faça esse teste e veja a diferença entre os Intent’s.

Veja mais detalhes em http://developer.android.com/reference/android/content/Intent.html.

Page 42: Guia Aberto Android ed.2

32 CAPÍTULO 3. LIVRO DE RECEITAS

3.1.6 Enviando e-mail

Para envio de e-mail você pode simplesmente usar a aplicação de e-mail padrão do apare-lho. Seguindo o mesmo princípio do exemplo anterior vamos apenas inserir um trecho decódigo no método configurar da classe MainActivity:

1 /* ... */2 private void configurar() {3 listView.setOnItemLongClickListener(new OnItemLongClickListener() {4 public boolean onItemLongClick(AdapterView<?> parent, View view,5 final int position, final long id) {6 final String[] itens = { "Editar" , "Deletar" , "Chamar" ,7 "Enviar e-mail" };8 /* ... */9 dialogo.setItems(itens, new OnClickListener() {

10 public void onClick(DialogInterface dialog, int which) {11 switch (which) {12 /* ... */13 case 3: // enviar e-mail14 model.moveToPosition(position);15 Intent email = new Intent(Intent.ACTION_SEND);16 email.setType( "plain/text" );17 email.putExtra(Intent.EXTRA_EMAIL,18 new String[]{ helper.getEmail(model) });19 startActivity(Intent.createChooser(email,20 "Enviar e-mail..." ));21 break;22 }23 }24 });25 dialogo.show();26 return true;27 }28 });29 }

Código-fonte 30: Item enviar e-mail no diálogo [MainActivity.java]

Ao testar no emulador você receberá a mensagem: No applications can performthis action. Traduzindo quer dizer que: Nenhuma aplicação pode executar esta ação.Em outras palavras, nenhum cliente de e-mail foi encontrado.

3.2 Internacionalização (i18n)

3.2.1 Forçando região para teste

Para podermos testar as strings de i18n podemos forçar o Activity a utilizar umadeterminada linguagem. Isso se dá por meio da classe Locale. Façamos um teste com o

Page 43: Guia Aberto Android ed.2

3.3. UTILIZANDO AS PREFERÊNCIAS DO ANDROID 33

SalvarActivity inserindo o trecho de código abaixo no método onCreate. Vamos a ele:

1 /* ... */2 @Override3 protected void onCreate(Bundle savedInstanceState) {4 /* ... */5 forceLocale( "pt" , "BR" );6 carregar();7 ir();8 }9

10 private void forceLocale(String language, String country) {11 Locale locale = new Locale(language, country);12 Locale.setDefault(locale);13 Configuration configuration = new Configuration();14 configuration.locale = locale;15 getBaseContext().getResources()16 .updateConfiguration(configuration,17 getBaseContext().getResources().getDisplayMetrics());18 }

Código-fonte 31: Forçando região [SalvarActivity.java]

Para visualizar a mudança crie strings no seu arquivo strings.xml. Substitua asstrings Nome, Telefone, E-mail e Salvar pelos respectivos valores em inglês Name, Phone,E-mail e Save. Agora crie outro arquivo strings.xml dentro do diretório /res/values-pt-rBRe insira as mesmas strings citadas anteriormente, traduzindo cada valor.

Faça testes comentando a chamada para a função forceLocale e veja as mudanças.

3.2.2 Forçando região pelo emulador

A maneira mais rápida e prática de forçar a região é pelo próprio emulador. Vá até alista de aplicativos e procure por Custom Locale. Depois pesquise por pt

¯BR e caso não

encontre clique em Add New Locale. Digite pt¯BR e clique em Add and Select.

3.3 Utilizando as Preferências do Android

O Android já disponibiliza uma maneira de criar preferências de forma fácil. Para demons-trar implementaremos um exemplo bem amplo, que irá nos ajudar a entender ainda maisde Android. Para começar adicionaremos um nova coluna a nossa tabela contato cha-mada grupo. Depois adicionaremos um array de string’s ao nosso arquivo strings.xmle ainda vamos aprender a utilizar um Spinner, também conhecido como combo box. Porúltimo, e não menos importante, usaremos as preferências para tornar padrão um valorde nosso Spinner.

Page 44: Guia Aberto Android ed.2

34 CAPÍTULO 3. LIVRO DE RECEITAS

3.3.1 Atualizando colunas de uma tabela

Como visto em 2.1.4, a classe SQLiteOpenHelper obriga-nos a implementar os métodosonCreate e onUpgrade. Neste ponto será necessário o uso do método onUpgrade. Eleserve, como o nome sugere, para atualizar a DDL do banco de dados. Isso é útil quandoseu cliente já possui uma versão do seu aplicativo instalada e ele quer apenas atualizarpara uma nova versão. Também será necessário adicionar a coluna grupo nas queries.Abra a classe ContatoHelper em contatos.app.model e faça as modificações:

1 public class ContatoHelper extends SQLiteOpenHelper {2 /* ... */3 private static final int VERSION = 2;4 private static final String TAG = "ContatoHelper" ;5

6 @Override7 public void onCreate(SQLiteDatabase db) {8 db.execSQL( "CREATE TABLE contato ( _id INTEGER PRIMARY KEY AUTOINCREMENT," +9 "nome TEXT, telefone TEXT, email TEXT," +

10 // versao 211 "grupo INTEGER NOT NULL DEFAULT 0 );" );12 }13

14 @Override15 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {16 Log.w(TAG, "Atualizando banco de dados da versão "17 + oldVersion + " para " + newVersion + "." );18 if (newVersion > oldVersion) {19 switch (oldVersion) {20 case 2:21 try {22 db.execSQL( "ALTER TABLE contato " +23 "ADD COLUMN grupo INTEGER NOT NULL DEFAULT 0" );24 } catch (SQLException e) {25 Log.e(TAG, "Erro ao executar SQL: " , e);26 }27 default:28 Log.w(TAG, "Versão desconhecida: " + oldVersion +29 ". Criando novo banco de dados." );30 db.execSQL( "DROP TABLE IF EXISTS contato" );31 onCreate(db);32 }33 }34 }35 }

Código-fonte 32: Nova coluna grupo na base de dados [ContatoHelper.java]

Page 45: Guia Aberto Android ed.2

3.3. UTILIZANDO AS PREFERÊNCIAS DO ANDROID 35

Vemos neste exemplo o uso da classe Log do pacote android.util. Ela possui apenasmétodos estáticos, assim não precisamos instanciar, apenas faça a chamada dos métodos.Temos:

Log.w() para mostrar warning’s, ou seja, avisos.

Log.e() para mensagens de erro.

Log.d() para mensagens debug.

Log.i() para mensagens informativas.

Log.v() para outras mensagens.

1 public class ContatoHelper extends SQLiteOpenHelper {2 /* ... */3 public Cursor listar() {4 return getReadableDatabase()5 .rawQuery( "SELECT _id, nome, telefone, email, grupo " +6 "FROM contato ORDER BY nome" , null);7 }8

9 public int getGrupo(Cursor c) {10 return c.getInt(4);11 }12

13 public Cursor ler(String id) {14 String[] params = {id};15 return getReadableDatabase()16 .rawQuery( "SELECT _id, nome, telefone, email, grupo " +17 "FROM contato WHERE _id = ?" , params);18 }19 }

Código-fonte 33: Modificação nas queries [ContatoHelper.java]

3.3.2 Array de Strings

No arquivo de string’s do Android é possível criar vários recursos. Dentre eles temosCor, Dimensão, Estilo/Tema. Usando a ferramenta ADT, crie um String Array emstrings.xml dentro de res/values e adicione alguns itens para representar os valores dacoluna grupo, e outro String Array para representar os índices:

Dica: você pode tentar implementar o trecho usando uma tabela do banco de dados. Aideia é a mesma, neste caso não seria necessário o uso de String Array’s.

Page 46: Guia Aberto Android ed.2

36 CAPÍTULO 3. LIVRO DE RECEITAS

1 <?xml version="1.0" encoding="utf-8"?>2 <resources>3 <!-- ... -->4 <string-array name= "array_grupos" >5 <item>amigos</item>6 <item>trabalho</item>7 <item>conhecidos</item>8 <item>família</item>9 </string-array>

10 <string-array name= "index_array_grupos" >11 <item>0</item><item>1</item>12 <item>2</item><item>3</item>13 </string-array>14 </resources>

Código-fonte 34: Array de Strings [strings.xml]

3.3.3 Spinner, diálogo de seleção

O Spinner é ideal quando temos que escolher entre valores fixos, sejam eles estáticosou dinâmicos. Nosso exemplo irá utilizar valores estáticos para popular o mesmo. Paraisso utilizaremos o array

¯grupos que criamos em res/values/strings.xml. Também

veremos um exemplo de uso da classe android.R como visto em 2.1.2 em que é explicadoa diferença entre as classes de recursos. Mas antes temos que atualizar nosso layoutsalvar.xml. Adicione o Spinner logo abaixo do e-mail, como mostra o trecho abaixo:

1 <!-- ... -->2 <TableRow3 android:id= "@+id/tableRow4"4 android:layout_width= "wrap_content"5 android:layout_height= "wrap_content" >6

7 <TextView8 android:id= "@+id/textView4"9 android:layout_width= "wrap_content"

10 android:layout_height= "wrap_content"11 android:text= "Grupo:" />12

13 <Spinner14 android:id= "@+id/sp_grupo"15 android:layout_width= "wrap_content"16 android:layout_height= "wrap_content" />17 </TableRow>18 <!-- ... -->

Código-fonte 35: Adicionando elemento Spinner [res/layout/salvar.xml]

Page 47: Guia Aberto Android ed.2

3.3. UTILIZANDO AS PREFERÊNCIAS DO ANDROID 37

Agora já podemos carregar e popular o Spinner na classe SalvarActivity.

1 public class SalvarActivity extends Activity {2 /* ... */3 private Spinner spGrupo = null;4

5 private void carregar() {6 /* ... */7 spGrupo = (Spinner) findViewById(R.id.sp_grupo);8 ArrayAdapter<CharSequence> adapter =9 ArrayAdapter.createFromResource(this,

10 R.array.array_grupos, android.R.layout.simple_spinner_item);11 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);12 spGrupo.setAdapter(adapter);13 /* antes de verificar o parâmetro contatoId */14 }15

16 private void carregarContato() {17 spGrupo.setSelection(helper.getGrupo(c));18 c.close();19 }20

21 private void ir() {22 btSalvar.setOnClickListener(new View.OnClickListener() {23 /* ... */24 contato.setGrupo(spGrupo.getSelectedItemPosition());25 /* antes de validar e salvar */26 }27 }28 }

Código-fonte 36: Utilização de Spinner [SalvarActivity.java]

Note a utilização da classe android.R nas linhas 10 e 11 . Eles servem para definiro layout do Spinner. Isso quer dizer que você pode implementar como seu Spinner iráaparecer na tela da mesma maneira que implementamos a linha da ListView em 2.1.5.

3.3.4 A classe PreferenceActivity

Afinal vamos utilizar as preferências do Android. Neste exemplo a usaremos para decidirqual grupo do array

¯grupos aparecerá selecionado por padrão. A princípio é um exemplo

bem simples, mas que pode ser ajustado para outras finalidades, o que importa realmenteé a ideia.

Para começar criaremos um layout em res/layout chamado preferencias.xml. Noprojeto clique com botão direito do mouse e selecione New → Other..., pesquise porAndroid XML File e Next. Em Resource Type escolha Preference e escreva preferenciasem File. Logo abaixo em Root Element escolha a opção PreferenceScreen, então

Page 48: Guia Aberto Android ed.2

38 CAPÍTULO 3. LIVRO DE RECEITAS

Finish.Utilizando a ferramenta ADT adicione um elemento ListPreference a PreferenceScreen.

Defina os parâmetros necessários como mostra o código abaixo:

1 <?xml version="1.0" encoding="utf-8"?>2 <PreferenceScreen xmlns:android= "http://schemas.android.com/apk/res/android" >3 <ListPreference4 android:summary= "Selecione o grupo padrão"5 android:dialogTitle= "Escolha um Grupo"

6 android:entries= "@array/array_grupos"

7 android:entryValues= "@array/index_array_grupos"8 android:key= "lista_grupos"9 android:title= "Grupos" />

10 </PreferenceScreen>

Código-fonte 37: XML descrevendo layout de preferências [res/xml/preferencias.xml]

Crie uma nova classe chamada EditarPreferencias em contatos.app.view her-dando de PreferenceActivity. Agora de uma maneira bem simples implementaremosessa classe. Veja:

1 package app.contatos.view;2

3 import android.os.Bundle;4 import android.preference.PreferenceActivity;5 import app.contatos.R;6

7 public class EditarPreferencias extends PreferenceActivity {8

9 @Override10 protected void onCreate(Bundle savedInstanceState) {11 super.onCreate(savedInstanceState);12 addPreferencesFromResource(R.xml.preferencias);13 }14 }

Código-fonte 38: Activity para mostrar preferências [EditarPreferencias.java]

Para chamar a nova Activity temos ainda que mapeá-la no AndroidManifest e criarum item no menu.

1 <activity android:name= ".view.EditarPreferencias" ></activity>

Código-fonte 39: Mapeando Activity EditarPreferencias [AndroidManifest.xml]

Page 49: Guia Aberto Android ed.2

3.3. UTILIZANDO AS PREFERÊNCIAS DO ANDROID 39

1 <?xml version="1.0" encoding="utf-8"?>2 <menu xmlns:android= "http://schemas.android.com/apk/res/android" >3 <!-- ... -->4 <item5 android:id= "@+id/menu_pref"

6 android:icon= "@android:drawable/ic_menu_preferences"7 android:title= "Preferências" >8 </item>9 </menu>

Código-fonte 40: Adicionar item Preferências ao menu principal[res/menu/main

¯menu.xml]

Agora que adicionamos um item ao menu, temos que capturar o evento quando ousuário o selecionar e direcioná-lo às Preferências. Isso deve ser feito em MainActivity.

1 /* ... */2 @Override3 public boolean onOptionsItemSelected(MenuItem item) {4 if (item.getItemId() == R.id.menu_add) {5 irPara(SalvarActivity.class);6 return true;7 } else if (item.getItemId() == R.id.menu_pref) {8 irPara(EditarPreferencias.class);9 return true;

10 }11 return super.onOptionsItemSelected(item);12 }13

14 private void irPara(Class<?> clazz) {15 irPara(clazz, null);16 }17

18 private void irPara(Class<?> clazz, String id) {19 Intent intent = new Intent(MainActivity.this, clazz);20 if (id != null) {21 intent.putExtra(_ID, id);22 }23 startActivity(intent);24 }

Código-fonte 41: Ir para Preferências pelo menu principal [MainActivity.java]

Note que para ter um código mais eficiente e otimizado tivemos que mudar o métodoirParaSalvar para irPara passando como parâmetro a classe que desejamos ir. Essamudança é boa mais causa um impacto em outros trechos do código. Conserte-os da

Page 50: Guia Aberto Android ed.2

40 CAPÍTULO 3. LIVRO DE RECEITAS

seguinte maneira:

1 /* ... */2 private void configurar() {3 listView.setOnItemClickListener(new OnItemClickListener() {4 public void onItemClick(AdapterView<?> parent, View view,5 int position, long id) {6 irPara(SalvarActivity.class, String.valueOf(id));7 }8 });9

10 listView.setOnItemLongClickListener(new OnItemLongClickListener() {11 public boolean onItemLongClick(AdapterView<?> parent, View view,12 final int position, final long id) {13 /* ... */14 public void onClick(DialogInterface dialog, int which) {15 switch (which) {16 case 0: // editar17 irPara(SalvarActivity.class, String.valueOf(id));18 break;19 /* ... */20

21 }22 }23 }24 }25 }

Código-fonte 42: Mudança em método irParaSalvar [MainActivity.java]

Por fim temos que selecionar o item que o usuário quer que esteja selecionado porpadrão ao inserir um novo contato. Assim, em SalvarActivity adicione o trecho:

1 private void carregar() {2 /* ... */3 contatoId = getIntent().getStringExtra(MainActivity._ID);4 if (contatoId != null) {5 carregarContato();6 } else {7 SharedPreferences preferencias =8 PreferenceManager.getDefaultSharedPreferences(this);9 spGrupo.setSelection(

10 Integer.parseInt(preferencias.getString( "lista_grupos" , "0" )));11 }12 }

Código-fonte 43: Obtem o valor padrão definido nas Preferências [SalvarActivity.java]

Page 51: Guia Aberto Android ed.2

3.4. GRUPO DE CONTATOS USANDO GRID 41

3.4 Grupo de Contatos usando Grid

Uma das coisas mais legais quando falamos de aparelhos móveis é a ideia da visão da listade aplicativos usada comumente com o ícone e o texto logo abaixo. Essa ideia pode serfacilmente implementada em um aplicativo Android usando GridView.

Nessa implementação vamos criar uma tela que mostra os grupos de contatos em formade Grid e ao clicar levaremos o usuário a lista de contatos mostrando apenas aquelescontatos de um determinado grupo.

3.4.1 Layout usando GridView

Para começar criaremos um layout em res/layout chamado grupos¯item.xml. Ele irá

conter a imagem e o texto que serão exibidos no GridView. Faça como mostra o trechoabaixo:

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= "match_parent"5 android:gravity= "center"6 android:orientation= "vertical" >7

8 <ImageView9 android:id= "@+id/iv_icone"

10 android:layout_width= "wrap_content"11 android:layout_height= "96.0dip"12 android:scaleType= "fitCenter" />13

14 <TextView15 android:id= "@+id/tv_texto"16 android:layout_width= "fill_parent"17 android:layout_height= "wrap_content"18 android:layout_marginBottom= "20.0dip"19 android:layout_marginTop= "2.0dip"20 android:gravity= "center"21 android:text= "TextView"22 android:textAppearance= "?android:textAppearanceMedium" />23 </LinearLayout>

Código-fonte 44: Item do Layout de Grupos [res/layout/grupos¯item.xml]

Hora de criar o GridView. Para isso crie um novo layout em res/layout chamadogrupos.xml. Adicione apenas um GridView como mostra o trecho de código abaixo:

Page 52: Guia Aberto Android ed.2

42 CAPÍTULO 3. LIVRO DE RECEITAS

1 <?xml version="1.0" encoding="utf-8"?>2 <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"3 android:layout_width= "match_parent"4 android:layout_height= "match_parent"5 android:orientation= "vertical" >6

7 <GridView8 android:id= "@+id/gv_grupos"9 android:layout_width= "match_parent"

10 android:layout_height= "wrap_content"11 android:numColumns= "3" >12 <!-- Preview: listitem=@layout/grupos_item -->13 </GridView>14

15 </LinearLayout>

Código-fonte 45: Layout de Grupos [res/layout/grupos.xml]

Dica: a ferramenta ADT provê uma forma de pré-visualizar seu layout. Note que nalinha 12 temos um comentário e nele temos a referência ao layout grupos

¯item. Para

isso apenas clique com botão direito do mouse na GridView e na opção Preview GridContent → Choose Layout... selecione grupos

¯item.

3.4.2 Activity para visualizar os Grupos

Como é de se imaginar temos que criar uma Activity para visualizar os Grupos.

1 public class GruposActivity extends Activity {2

3 private GridView grid = null;4

5 @Override6 protected void onCreate(Bundle savedInstanceState) {7 super.onCreate(savedInstanceState);8

9 setContentView(R.layout.grupos);10 carregar();11 }12

13 private void carregar() {14 grid = (GridView) findViewById(R.id.gv_grupos);15 }16 }

Código-fonte 46: Activity para visualizar Grupos [GruposActivity.java]

Page 53: Guia Aberto Android ed.2

3.4. GRUPO DE CONTATOS USANDO GRID 43

Temos que criar duas classes internas para nos ajudar a criar cada item do grupo decontatos. Para isso usaremos a classe abstrata BaseAdapter.

1 /* ... */2 static class IconeAdapter extends BaseAdapter {3

4 private Context context;5

6 public IconeAdapter(Context context) {7 super();8 this.context = context;9 }

10

11 static class GruposHolder {12 public ImageView icone;13 public TextView texto;14 }15

16 public int getCount() {17 return 0;18 }19

20 public Object getItem(int position) {21 return null;22 }23

24 public long getItemId(int position) {25 return 0;26 }27

28 public View getView(int position, View convertView, ViewGroup parent) {29 return null;30 }31 }

Código-fonte 47: Adapter responsável por cada item do Grid [GruposActivity.java]

Nesse momento precisamos usar a ferramenta Inkscape e criar alguns ícones. Para osexemplos a seguir você deve criar um ícone para cada item do grupo, sendo eles:

I amigos

I trabalho

I conhecidos

I família

Page 54: Guia Aberto Android ed.2

44 CAPÍTULO 3. LIVRO DE RECEITAS

Para título de exemplo crie apenas ícones simples e depois tente fazer itens mais sofis-ticados. Em http://developer.android.com/design/style/iconography.html vocêpode ver como devem ser criados os ícones para seu aplicativo.

Criando ícones com Inkscape

Use o Inkscape para criar um novo ícone. No menu Arquivo → Propriedades do Desenho...ou apenas Shift + Ctrl + D e altere a largura e altura para 512px.

Aperte 5 para centralizar a folha e crie um quadrado (F4) um pouco menor que apágina. Utilize Ctrl para criar um quadrado perfeito. Altere a borda usando o círculobranco no canto superior direito do quadrado. Selecione uma cor legal.

O Android possui uma paleta de cores que pode lhe ajudar inicialmente. Veja a tabelaabaixo:

Cor Tom claro Tom escuro

Azul #33B5E5 TTT #0099CC TTT

Roxo #AA66CC TTT #9933CC TTT

Verde #99CC00 TTT #669900 TTT

Laranja #FFBB33 TTT #FF8800 TTT

Vermelho #FF4444 TTT #CC0000 TTT

Tabela 3.1: Paleta de cores do Android

Mais detalhes em http://developer.android.com/design/style/color.html.

Para alterar a cor clique com botão direito domouse no quadrado e selecione Preenchimentoe contorno. Observe a entrada de texto onde aparece RGBA. Altere com os valores acimamantendo os dois últimos, pois eles são referentes a transparência.

Chegou a hora de exportar seu ícone para os tamanhos sugeridos pelo Android. Bastair no menu Arquivo → Exportar Bitmap... ou ainda Shift + Ctrl + E. Os tamanhosestão definidos na tabela abaixo:

Local Tamanho

res/drawable-xhdpi 96px

res/drawable-hdpi 72px

res/drawable-mdpi 48px

res/drawable-ldpi 36px

Tabela 3.2: Localização e tamanho dos ícones

Exporte o ícone para cada um desses diretórios, crie-os caso não existam. Como temosquatro grupos crie quatro ícones usando cores diferentes. Siga a nomenclatura sugeridaem 2.1.2 Convenção de nomes para ícones, exemplo: ic

¯launcher

¯grupo

¯amigos.png.

Page 55: Guia Aberto Android ed.2

3.4. GRUPO DE CONTATOS USANDO GRID 45

3.4.3 Implementando o Adapter

1 public class GruposActivity extends Activity {2 /* ... */3 static final int[] icones = {4 R.drawable.ic_launcher_grupo_amigos,5 R.drawable.ic_launcher_grupo_trabalho,6 R.drawable.ic_launcher_grupo_conhecidos,7 R.drawable.ic_launcher_grupo_familia8 };9

10 private void carregar() {11 /* ... */12 grid.setAdapter(new IconeAdapter(getBaseContext()));13 }14

15 static class IconeAdapter extends BaseAdapter {16

17 public int getCount() {18 return icones.length;19 }20

21 /* ... */22 public View getView(int position, View convertView, ViewGroup parent) {23 GruposHolder holder = null;24 View v = convertView;25 if (v == null) {26 LayoutInflater inflater = (LayoutInflater) context27 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);28 v = inflater.inflate(R.layout.grupos_item, null);29 holder = new GruposHolder();30 holder.texto = (TextView) v.findViewById(R.id.tv_texto);31 holder.icone = (ImageView) v.findViewById(R.id.iv_icone);32 v.setTag(holder);33 } else {34 holder = (GruposHolder) v.getTag();35 }36 holder.icone.setImageResource(icones[position]);37 holder.texto.setText(context.getResources()38 .getStringArray(R.array.array_grupos)[position]);39 return v;40 }41 }42 }

Código-fonte 48: implementação do Adapter [GruposActivity.java]

Page 56: Guia Aberto Android ed.2

46 CAPÍTULO 3. LIVRO DE RECEITAS

Como visto em 2.1.5 Mostrando os dados na View, no Adapter podemos fazer cachedos objetos e otimizar o código. Isso pode ser observado a partir da linha 25 até a linha35 , onde um teste é realizado para ver se a linha está em cache.

Observação: na linha 37 existe um trecho de código que não está nada otimizado. Noentanto usando string-array é a única maneira de dar certo. Isso poderia ser evitado seos grupos de contatos fossem retirados do banco de dados. Seguindo as instruções antesabordadas tente você mesmo implementar usando banco de dados. É uma ótima maneirade aprender melhor como funciona um aplicativo Android.

Finalize adicionando o Activity no AndroidManifest.xml. Clique na aba inferiorem Application e em Application Nodes clique em Add. Escolha Activity na lista deopções e no atributo Name clique em Browser e busque por GruposActivity.

Para visualizar a nova Activity é preciso adicionar um novo item no menu principal.Reveja 2.1.2 Activity, e implemente essa parte. Não esqueça de adicionar uma condiçãono método onOptionsItemSelected da classe MainActivity.

3.4.4 Selecionando contatos de um determinado grupo

Para não deixar dúvidas quanto a implementação deste trecho vamos fazer com que aoclicar em um determinado grupo, somente contatos daquele grupo apareçam na lista quefica em MainActivity.

Primeiro sobrescreva o método listar da classe ContatoHelper para que ele recebaum parâmetro, que irá representar o grupo.

1 public Cursor listar(String grupo) {2 String[] params = {grupo};3 return getReadableDatabase()4 .rawQuery( "SELECT _id, nome, fone, email, grupo FROM contato " +5 "WHERE grupo = ? ORDER BY nome" , params);6 }

Código-fonte 49: Método listar com parâmetro grupo [ContatoHelper.java]

A implementação do clique em um item do grid é semelhante a vista em 2.1.6 Editandodados existentes, onde criamos uma variável contendo o namespace do nosso parâmetro.

Copie o método irPara da classe MainActivity, mudando apenas o primeiro parâ-metro de intent.putExtra para o novo namespace, na linha 17 .

Por fim, inclua o método configurar em onCreate, o qual será responsável porconfigurar para onde ir ao clicar em um item do grid.

Page 57: Guia Aberto Android ed.2

3.4. GRUPO DE CONTATOS USANDO GRID 47

1 public static final String _GRUPO = "contatos.app._GRUPO" ;2

3 @Override4 public void onCreate(Bundle savedInstanceState) {5 /* ... */6 configurar();7 }8

9 private void configurar() {10 grid.setOnItemClickListener(new OnItemClickListener() {11 public void onItemClick(AdapterView<?> parent, View view, int position,12 long id) {13 irPara(MainActivity.class, String.valueOf(position));14 }15 });16 }17

18 private void irPara(Class<?> clazz, String id) {19 Intent intent = new Intent(GruposActivity.this, clazz);20 if (id != null) {21 intent.putExtra(_GRUPO, id);22 }23 startActivity(intent);24 }

Código-fonte 50: Evento de clique em um item do grid [GruposActivity.java]

Agora é preciso capturar o parâmetro em MainActivity. Para isso basta fazer comodescrito abaixo:

1 /* ... */2 private String grupo = null;3

4 private void carregar() {5 listView = (ListView) findViewById(R.id.lv_contatos);6 grupo = getIntent().getStringExtra(GruposActivity._GRUPO);7 if (grupo == null) {8 model = helper.listar();9 } else {

10 model = helper.listar(grupo);11 }12 startManagingCursor(model);13 adapter = new ContatoAdapter(model);14 listView.setAdapter(adapter);15 }

Código-fonte 51: Captura de parâmetro vindo de GruposActivity [MainActivity.java]

Page 58: Guia Aberto Android ed.2

48 CAPÍTULO 3. LIVRO DE RECEITAS

Muito bem, eis que temos um aplicativo já bem completo. Se tudo deu certo você deveter uma tela como vemos abaixo:

Figura 3.1: Tela de Grupos

Page 59: Guia Aberto Android ed.2

Apêndice A

Sobre o Autor

Estudante de Ciência da Computação no IFCE Campus Maracanaú, Ceará, Brazil. Pro-gramador Java, PHP, Ruby. Trabalha na Fidias Software, empresa que ajudou a fundarjuntamente com José Alberto e Shara Shami.

Sugestões e CríticasPara fazer sugestões e críticas envie e-mail para [email protected]. Para ficarantenado no mundo do Software Livre me acompanhe no Twitter:https://twitter.com/#!/atilacamurca.

Código-fonte deste guiaVocê pode baixar o código-fonte deste guia emhttps://github.com/atilacamurca/guia-aberto-android.

Visite também a página do projetohttp://atilacamurca.github.com/guia-aberto-android/ e verifique se há atualiza-ções.

49

Page 60: Guia Aberto Android ed.2

50 APÊNDICE A. SOBRE O AUTOR

Page 61: Guia Aberto Android ed.2

Glossário

ADT Android Development Tools (Ferramentas de Desenvolvimento Android), 1

API Application Programming Interface (Interface de Programação de Aplicativos), 1

AVD Android Virtual Device (Dispositivo Virtual Android), 4

DDL Data Definition Language (Linguagem de Definição de Dados), é a parte do SQLque permite que as tabelas do banco de dados sejam criadas, alteradas ou removidas.Ela também define índices (chaves), especifica ligações entre tabelas, além de imporrestrições entre tabelas, 14, 33

debug termo utilizado para indicar quais as operações que estão sendo executadas, veri-ficando assim se estão funcionando como deveriam ou se existem defeitos, 35

IDE Integrated Development Environment (Ambiente de Desenvolvimento Integrado),são softwares que auxiliam no desenvolvimento de outros softwares. Ex. NetBeansIDE http://netbeans.org/, Eclipse IDE http://www.eclipse.org/, 1

JDK Java Development Kit (Kit de Desenvolvimento Java). Refere-se ao Java utilizadopara desenvolvimento, 2

LTS Long Term Support (Termo de Suporte a Longo Prazo), indica que uma versão doUbuntu terá atualizações por um período de tempo maior, sendo assim você teráum ambiente estável e sempre atualizado, 1

lucid Codinome utilizado para a versão 10.04 do Ubuntu (Lucid Lynx), 1

PPA Personal Package Archives (Pacote de Arquivos Pessoais), pacotes de terceiros, ouseja, que não são oriundos do repositório oficial do Ubuntu, 2

SDK Software Development Kit (Kit de Desenvolvimento de Software), 3

Synaptic é um gerenciador de pacotes em modo gráfico baseado em GTK+ e APT. Elepermite que você instale, atualize e remova pacotes de software de uma maneira ami-gável. Para instalar, abra um terminal e digite como super usuário (root): apt-getinstall synaptic, 2

xml eXtensible Markup Language, foi desenvolvida com o propósito de estruturar, arma-zenar e transportar informações, 10

51