Explorar E-books
Categorias
Explorar Audiolivros
Categorias
Explorar Revistas
Categorias
Explorar Documentos
Categorias
1a edição
Gravataí/RS
Edição do Autor
2017
Copyright © Luiz Fernando Duarte Júnior, 2017
Criando apps para empresas com Android
Luiz Duarte
Duarte, Luiz,
Criando apps para empresas com Android - 1a edição
ISBN 978-65-900538-0-0
Atenção: se você não sabe o básico de Java, leia esse livro primeiro Java
para Iniciantes, do mesmo autor.
1 INTRODUÇÃO
Estamos vivendo uma Revolução Mobile. Ninguém tem dúvidas disso. A
pergunta é: você está preparado para surfar esta onda?
A teoria dos celulares é de 1947, mas somente em 1973 que a Motorola se
tornou a pioneira desse mercado ao construir o primeiro protótipo funcional
de um telefone celular que, dizem as histórias, foi utilizado pelo diretor da
Motorola na época para realizar uma ligação para seu rival da AT&T
avisando que ele havia ganho a corrida tecnológica pelo primeiro celular.
Entretanto, ainda levou 10 anos para os primeiros aparelhos celulares
chegarem ao mercado com tamanho em torno de 30cm e pesando 1kg. O
preço? Módicos U$4.000 que tornavam este um item de luxo tanto quanto os
carros que eram equipados com estes aparelhos, como Rolls Royces e
Bentleys. Sim, ou você acha que as pessoas carregavam aparelhos de 1kg no
bolso?
No início os celulares eram usados somente para realizar ligações telefônicas.
Somente em 1993 que surgiu o SMS, o sistema de envio de mensagens que
até o surgimento recente do WhatsApp dominava a mensageria telefônica
mundial, pondo bilhões no bolso das operadoras.
Ainda nesse ano não tão longe do início da década de 90, surgiram os
primeiros celulares com funções PDA, como agenda de contatos, calendário
de compromissos, alarmes, etc quando a IBM passou a investir mais forte
neste mercado. Os celulares estavam se tornando cada vez mais úteis.
Em 1996, este artefato tecnológico começou a ganhar uma conotação de
status. Não exatamente neste ano que ter um celular se tornou motivo de
status, mas foi em 1996 que a Motorola novamente foi pioneira lançando o
famoso Motorola StarTac, com design inspirado na nave espacial da série
Star Trek. Sim, design.
Estávamos entrando em uma era onde os celulares eram quase peças do
vestuário como os relógios. Na verdade, mais à frente os celulares acabaram
substituindo parcialmente os relógios de pulso, e de certa forma tem de
combinar com a personalidade e vestes do seu dono, não é mesmo?
Avançando no tempo, em 2001, a Kyocera, uma fabricante não tão famosa no
Brasil, lançou o primeiro smartphone do mercado. Ok, não era tão “smart”
assim, não tinha tantos recursos quanto os atuais, mas tinha um sistema
operacional de verdade e não um firmware embarcado em um hardware. Ele
podia ser formatado, podia ter aplicativos instalados. Não tínhamos à essa
altura uma loja de aplicativos ou sequer a liberdade de desenvolvê-los, mas
abriu as portas para as inovações que surgiram mais tarde.
Selfie tem sido a palavra mais usada atualmente nas redes sociais. Mas você
parou para pensar o que gerou essa onda de narcisismo digital?
Foi em 2002 que a Sanyo, outra fabricante de celulares pouco conhecida aqui
no ocidente teve a ideia de lançar um celular que viesse com uma câmera
digital embutida. Claro, era uma câmera VGA de 0.3MP, mas que gerou uma
revolução na fotografia digital, permitindo que fabricantes como a Nokia se
tornasse a maior vendedora de câmeras digitais do mundo no ano seguinte,
devido ao sucesso de seus smartphones, principalmente a linha N Series.
Mas e a Internet? Hoje todos vivemos conectados à ela com nossos
smartphones, certo?
Apenas em 2003 que o primeiro smartphone se conectou à web real, o HTC
Danger. Além disso ele foi o primeiro smartphone com comandos por voz
algo que hoje é muito popular com o Siri da Apple e o Google Now do
Google.
E a revolução continuou em 2003 com a Nokia lançando o primeiro
smartphone focado em games, o Nokia N-Gage, que inclusive tinha um
formato peculiar de console portátil, plataforma de games e até algum tipo de
rede social para os jogadores. Nokia Arena ou algo assim.
Foi em 2004 que a Motorola voltou a inovar com seus celulares-design,
lançando o famosíssimo Motorola Razr, mais conhecido como V3, que
durante 3 anos consecutivos se manteve na lista dos celulares mais vendidos
no mundo inteiro, e aqui no Brasil não foi exceção.
Ter um V3 era chamar a atenção toda vez que tinha de tirá-lo do bolso para
tirar uma foto, atender uma ligação ou...praticamente apenas isso. O V3 não
era um celular de ponta mesmo na sua época, seu apelo era mais social, com
design ultra fino, teclado no melhor estilo Tron e duas câmeras de diferentes
qualidades dependendo da versão.
E quantas versões, hein! Tinha V3 padrão (prata), Black, Pink, Dolce &
Gabanna (dourado) e muitas outras, sendo que o hardware variava pouco e o
design mudava basicamente a cor. Curioso não?!
Foi em 2005 que a Motorola lançou outro marco da indústria com a série
Rokr que eram celulares focados em ser os melhores tocadores de música do
mercado. Com enorme capacidade de armazenamento, um bom player e
caixas estéreo de alta potência, os Rokrs eram junto com os Sony Walkman
os melhores celulares para se escutar música na época, fazendo a alegria de
quem tinha grana para comprá-los e escutar no caminho para a faculdade ou
trabalho.
Foi praticamente o início da morte dos MP3 Players, que duraram no
mercado mais alguns anos até se extinguirem completamente. Afinal, para
quê carregar um celular e um MP3 no bolso, se um bom Rokr resolve os dois
problemas?
Em 2007 temos o maior marco da indústria mobile moderna. Algo como a
Revolução Francesa dos dispositivos móveis, uma vez que toda uma indústria
nova foi criada neste ano, a indústria dos apps.
Foi com a Apple, que em seu princípio era uma empresa de computadores,
que virou uma empresa de tocadores de música com iPod, que criou o mais
incrível de todos os smartphones até então, o iPhone.
Mas o mais incrível de 2007 não é o lançamento do iPhone em si, que era um
excelente telefone e trazia um conceito completamente novo , com uma
experiência completamente focada no touchscreen (que não era uma
tecnologia nova, diga-se de passagem), mas no ecossistema que a Apple criou
junto ao iTunes e a App store. Agora, qualquer desenvolvedor em qualquer
lugar do mundo podia escrever seu próprio aplicativo e distribuí-lo em um
marketplace, alcançando clientes do mundo inteiro.
O desenvolvimento de apps, até então centralizado nas mãos das empresas
credenciadas junto às fabricantes, agora estava aberto a qualquer
desenvolvedor com um computador na mão e uma ideia na cabeça. Se você
hoje está pensando em desenvolver um app para colocar na Apple Store ou na
Google Play, agradeça à Apple por ter criado este modelo de distribuição de
apps que forçou toda a indústria a se reinventar.
Não demorou muito até o Google se manifestar e querer entrar nesta briga,
lançando junto com a HTC o primeiro smartphone Android, seu novíssimo
sistema operacional, em 2008, o HTC Dream.
Enquanto que o mercado esquentou absurdamente em 2010 com a Samsung
se tornando a maior fabricante de celulares do mundo, com a Nokia perdendo
a liderança com seu defasado sistema Symbian, com a BlackBerry entrando
em colapso e perdendo seu lugar até mesmo para a Microsoft, a Apple não se
acomodava e antes do lendário Steve Jobs dizer adeus à empresa (e ao
mundo), o iPad foi lançado, iniciando todas em uma nova corrida por tablets
de todos os tipos, tamanhos e fabricantes. Os tablets não eram algo novo,
fizeram parte de um passado não tão distante, mas um passado desconectado
que fez com que não fossem bem sucedidos. Hoje, um tablet conectado à
Internet é tão útil quanto um notebook ou computador para 90% das pessoas,
e muito mais conveniente.
A história não termina aqui, mas acho que você já entendeu, não é mesmo?
As Gerações de Celulares
Na década de 80 quando os celulares começaram a se popularizar tivemos a
chamada 1G, onde celular era coisa para se fazer e receber ligações e
usávamos o padrão TDMA de comunicação que durou por décadas.
Na década de 90 tivemos a segunda geração, ou 2G, com novas redes digitais
como a CDMA e mais tarde com a GSM e a Internet móvel Wap.
No início dos anos 2000, com a profusão do GSM em larga escala e
praticamente morte do CDMA, padrão anterior, tivemos uma geração
intermediária e não oficial chamada 2.5G, caracterizada pelos celulares com
câmeras digitais entre 0.3MP e 2MP, Internet mais rápida (padrões GPRS e
EDGE) e MP3 players embutidos.
Por volta de 2009 começamos a galgar um aumento na velocidade da Internet
móvel com a terceira geração, ou 3G, caracterizada pela banda-larga móvel e
vídeo-chamada, com investimento pesado de players como Claro e Vivo e
mais tarde as demais operadoras, todas tentando mudar o hábito de consumo
de Internet no país, até então centralizado nas operadoras de telefonia fixa.
Tem alguns poucos anos que vemos o movimento 4G no Brasil. Com padrão
pouco definido e velocidades que deveriam estar cobertas pela 3G.
Infelizmente a quarta geração é muito mais antiga em países desenvolvidos,
sendo que atualmente estes mesmos países já possuem velocidades de
conexão de até 100Mbps em movimento e 5Gbps em repouso, o que não
temos nem mesmo em nossos computadores domésticos na época de escrita
deste livro.
Dispositivos Móveis e seus Nomes
Muitos são os nomes dados aos dispositivos móveis. Você conhece todos
eles?
Handheld ou Handset: nome dado a qualquer dispositivo móvel, com ou
sem a função de celular.
PDA ou Personal Digital Assistant: um Assistente Digital Pessoal não é um
celular, mas um celular pode ter funções de PDA. Um PDA é como os
antigos PalmTops e agendas eletrônicas de antigamente, que caíram em
desuso tem alguns anos.
Smartphone: um telefone inteligente é um telefone celular com um sistema
operacional de verdade. Ou seja, o hardware é construído e depois é instalado
um sistema operacional, que pode ser reinstalado outras vezes caso
necessário, bem como aplicativos.
Pocket PC: foi um celular com funções de PDA criado pela Microsoft, que
rodava o famigerado Windows CE, sistema operacional móvel criado pela
empresa de Redmond que não vingou por não ser tão móvel assim.
Tablet PC: ou simplesmente tablet é o nome dado ao meio termo entre os
smartphones e os notebooks, como pranchetas digitais com telas sensíveis ao
toque ou à canetas Stylus.
Market Share Mundial
Os números de 2017 mostram uma supremacia do sistema operacional
Android sobre todos os outros. Se esse livro tivesse sido escrito na década de
90 com revisões a cada 10 anos, mostraria o quanto esse mercado mudou
com o passar dos anos, com o surgimento e desaparecimento de sistemas
operacionais e fabricantes.
Esses números são de uma pesquisa da IDC e mostra que o Android reina no
mundo inteiro, com variações em cada continente, mas sempre com alguma
folga, como nos EUA onde tem 60% do mercado e na China, onde tem 90%.
2 INTRODUÇÃO AO ANDROID
Você sabia que não foi o Google que criou o Android?
O sistema operacional Android foi criado em 2005 por uma startup chamada
Android Inc. Que foi comprada pela empresa de Mountain View e se tornou a
equipe que criou este fantástico SO.
Apenas em outubro de 2008 que tivemos o lançamento oficial do Android no
mercado com o primeiro smartphone Android, o HTC Dream.
Mais tarde, em 2010 tivemos o lançamento do Samsung Galaxy Tab, o
primeiro tablet com Android.
Talvez a maior inovação trazida pelo Android não tenha sido suas APIs,
suporte a múltiplos hardwares, não somente celulares, mas sim o fato de ser
uma plataforma aberta, com todos seu código fonte disponível para download
e customização, inclusive para fins comerciais como bem tem feito a
Samsung nos últimos anos, que hoje fatura mais com o Android do que o
próprio Google.
A Plataforma
O Android é um sistema operacional que compartilha o mesmo kernel do
Linux, escrito em C e C++ com um pouco de linguagem de montagem
Assembly.
Ao contrário do que se pensa o Android não é escrito em Java, o que na
verdade o faria muito lento se fosse verdade.
Outro mito relacionado ao Android é de que ele é de propriedade do Google.
Embora o Google seja o principal mantenedor da plataforma, o Android é
propriedade da Open Handset Alliance, um consórcio de empresas criado
pelo Google e com participantes das principais fabricantes de celulares do
mundo como Motorola, Samsung e LG.
Curiosamente, em 2012 o Google comprou a divisão de mobilidade da
Motorola, seja para aumentar seu poder sobre o mercado ou apenas pensando
em capitalizar melhor a plataforma.
Além do sistema operacional, a plataforma engloba uma camada de aplicação
ou middleware, em Java, onde a maioria dos aplicativos reside, conforme
mostra a imagem abaixo.
Nesta camada o Android já entrega alguns apps genéricos como um browser
webkit, um alarme, uma agenda de contatos, uma calculadora e mais alguns.
A plataforma Android oferece suporte nativo à biblioteca gráfica OpenGL ES
2D e 3D para renderização de apps e games, além de suporte nativo ao banco
de dados SQLite.
Versões do Android
Desde seu lançamento em versões Alfa e Beta, o Android teve diversas
versões, sempre com nomes de sobremesas e em ordem alfabética,
começando na letra C uma vez que já tivemos a A (Alfa) e B (Beta).
O número de API entre parênteses é o número da biblioteca de
desenvolvimento, que usaremos mais tarde.
● Versão 1.5 Cupcake (API 3)
● Versão 1.6 Donut (API 4)
● Versão 2.0 a 2.1 Eclair (API 7)
● Versão 2.2 Frozen Yogurt (ou FroYo, API 8)
● Versão 2.3 Ginger Bread (API 9 e 10)
● Versão 3.0 Honeycomb (API 11 a 13)
● Versão 4.0 Ice-cream Sandwich (API 14 e 15)
● Versão 4.1 à 4.3 Jellybean (APIs 16, 17 e 18)
● Versão 4.4 Kit Kat (API 19 e 20)
● Versão 5.0 Lollipop (API 21 e 22)
● Versão 6.0 Marshmallow (API 23)
● Versão 7.0 Nougat (API 24 e 25)
● Versão 8.0 Oreo (API 26)
Até a versão 2.3 o Android era praticamente 100% focado para smartphones
e o uso destas versões do Android em tablets era sofrível, embora existente
até os dias atuais em dispositivos de segunda linha do mercado chinês.
Somente na versão 3.0 que o Android passou a atender de verdade o mercado
de tablets com a versão Honeycomb, que era exclusiva para esse tipo de
dispositivo. No entanto, essa nova versão trouxe à tona outro problema da
plataforma: a fragmentação.
No mundo inteiro diversos fabricantes lançaram celulares e tablets com
versões diferentes do Android, o que gera problemas até hoje para os
usuários, vendedores, fabricantes e nós, desenvolvedores.
A OHA e principalmente o Google tentou consertar essa fragmentação com a
versão 4.0, a Ice-cream Sandwich que visava unificar as vantagens da versão
2.3.3 com o suporte à tablets da versão 3.0 em uma versão completamente
reescrita e reestilizada.
Mais recentemente em 2014, o Google deu um novo empurrão em sua
plataforma anunciando no Google IO, seu evento global para os
desenvolvedores, que estaria lançando versões do Android para automóveis e
wearables, ou seja, em breve teremos Android em nossos carros, óculos,
relógios e até mesmo roupas!
E a empresa californiana não está para brincadeira, junto com grandes
montadoras como a Hyundai, o Google montou em analogia à OHA a Open
Automotive Alliance, com o intuito de definir os padrões e escrever o futuro
dos computadores de bordo e centrais multimídias dos carros usando a
plataforma Android.
Não obstante, o próprio Google Glass, óculos de realidade aumentada do
Google que ainda engatinha nas vendas, usa a plataforma Android.
E por fim, o suporte à Smart TVs e a aparelhos da linha branca como as
geladeiras inteligentes da Brastemp, mostram que o Android veio para ficar.
Como desenvolver
A dita plataforma Android não é apenas um sistema operacional. O Google
não nos presenteou apenas com um grande e gratuito sistema operacional
para smartphones e tablets, mas com todo um set de recursos para
desenvolver para ele.
Para desenvolver para Android você precisa ter instalado em sua máquina o
JDK (Java Development Kit) e o Android SDK (Software Development Kit),
que está disponível publicamente aos desenvolvedores desde setembro de
2008.
Isto considerando o desenvolvimento nativo tradicional, com a linguagem
Java. Neste post em meu blog falo de outras possibilidades de
desenvolvimento para Android: http://www.luiztools.com.br/post/conheca-
os-frameworks-de-desenvolvimento-mobile/
Como ambientes de desenvolvimento pode-se utilizar Eclipse, Netbeans ou
IntelliJ, entre outras.
O SDK oficial engloba o ADT ou Android Development Toolkit, um kit de
desenvolvimento que pode ser instalado em IDEs compatíveis que fornece
recursos de compilação e de conexão, como o ADB, a Android Debug
Bridge, e de simulação, como o AVD ou Android Virtual Device. Mas nem
só de plugins e componentes vive o SDK, ele possui todas as bibliotecas e
APIs para manipular os apps nativos da plataforma e os recursos de hardware
do dispositivo, como GPS, acelerômetros, tela sensível ao toque, redes de
dados, etc.
Mas o desenvolvimento para Android, que é um sistema tradicional escrito
em C, não está restrito a esta linguagem. Pode-se desenvolver em Android
com a plataforma .NET, com HTML+CSS+JS, com a própria linguagem C e
C++ (usando o NDK, o Native Development Kit), com a linguagem brasileira
Lua e com muitas outras, com diferentes níveis de performance,
compatibilidade e sets de recursos.
Apesar dos aplicativos Android em sua maioria serem escritos em Java, a
máquina virtual Java (JVM) que roda nos dispositivos Android não é a
tradicional que roda em desktops.
Chamada de Dalvik, é uma máquina virtual reduzida, com seu próprio set de
instruções e que não lê os mesmos bytecodes do Java desktop, ou seja, não há
compatibilidade entre os binários de ambas plataformas, e mesmo através de
recompilação, nem todas bibliotecas Java tradicionais funcionam no Android.
Tenha isso em mente, principalmente se quiser converter alguma aplicação
desktop para mobile.
Se quiser mais sobre a Dalvik, recomendo a leitura deste post em meu blog:
http://www.luiztools.com.br/post/tudo-sobre-maquina-virtual-dalvik-do-
android/
O Mercado de Aplicativos
O mercado de apps irá movimentar U$77 bilhões em 2017 segundo a
Gartner, devido a um volume de 268 bilhões de downloads de apps. São 2
milhões de apps para download na App Store e mais 2.2 milhões na Google
Play.
A empregabilidade de desenvolvedores de aplicativos está entre as mais altas
do mundo, mesmo dentro de um setor como a TI que já impressiona pelos
números. Nos EUA os salários beiram os U$100/h e mesmo dentro do Brasil
não é raro encontrar empresas pagando salários de R$5.000 a R$12.000 para
bons desenvolvedores de aplicativos, conforme mostrado pelo site Glassdoor:
https://www.glassdoor.com/Salaries/brazil-android-developer-salary-
SRCH_IL.0,6_IN36_KO7,24.htm
O mais impressionante de tudo isso é que para entrar nesse mercado não é
preciso muito.
Você pode desenvolver para Android com qualquer plataforma e com uma
infinidade de ferramentas gratuitas. Ao contrário do iOS, você pode distribuir
e vender seus aplicativos livremente sem pagar royalties a ninguém. Caso
queira publicar na Google Play existe uma taxa única de U$25 contra os
U$99 anuais da Apple.
Ou seja, todo o investimento é o de um computador e do seu tempo. Claro, se
você está lendo isso é porque comprou este livro também, então teve mais
algum investimento ☺.
Devido a isso de vez em quando aparecem grandes cases de sucesso
surpreendentes, como caso de Robert Nay que aos 14 anos, estudante da 8a
série da escola elementar, criou o game Bubble Ball que com 9 milhões de
downloads desbancou o trono de Angry Birds à época.
Tudo isso com um livro de programação mobile que encontrou na biblioteca
de sua escola.
Mas que tipos de aplicativos movem este mercado?
Muitas são as opções de aplicativos para desenvolver, mas algumas
categorias lideram em números:
Consumo de API
Basicamente um app de consumo de conteúdo é um app que não possui
conteúdo próprio, que se conecta a alguma API ou feed para carregar seu
conteúdo, como os apps de redes sociais, leitores de feed RSS, revistas
digitais, mobile bankings, entre outros.
Utilitários
Um app utilitário é um app que lhe ajuda a realizar outras tarefas como ver o
saldo da sua conta bancária, escrever e-mails, ou os discos virtuais.
Entram aqui também os diversos apps de fotografia e compartilhamento de
imagem e os apps mensageiros e de localização.
Advergames
Advergames são os jogos associados a grandes marcas de produtos, como os
jogos da Pepsi, Toddynho, Doritos, Axe, Boticário e Rexona, só para citar
alguns.
As grandes marcas estão cada vez mais investindo em jogos para engajar seu
público de uma maneira mais lúdica e alguns projetos de jogos que chegam
nas agências digitais e estúdios desenvolvimento chegam na casa dos R$100
mil.
Casual Games
Jogos casuais existem há décadas, divertindo seus jogadores nas horas livres,
nas filas dos bancos, no ônibus e nas longas viagens.
Um jogo casual é aquele que é simples de jogar mas extremamente viciante.
Geralmente um jogo casual tem muitos níveis com pouca variação, para lhe
manter o maior tempo possível jogando, mas sem uma história geralmente.
Em celulares, onde a jogabilidade é limitada, os jogos casuais reinam
absoluto.
Títulos como Clash Royale, Bejeweled e Candy Crush são exemplos de jogos
casuais sendo que a Supercell, empresa criadora do Clash Royale, vale
bilhões no mercado de capitais.
Adaptações de Grandes Games
Grandes empresas de games como a Electronic Arts (EA) atualmente
investem mais nas plataformas móveis do que nos consoles e PCs.
Em parte isso se deve ao baixo índice de pirataria dos jogos mobile e ao custo
de produção menor que o dos jogos tradicionais. Seja lá o motivo, as
adaptações de grandes games como FIFA e Pro Evolution Soccer para
celulares tem rendido milhões às contas de suas produtoras, só para citar dois
exemplos.
Futilidades
Nesta categoria encontram-se todos apps que não possuem uma utilidade
prática mas que ainda assim fazem enorme sucesso.
Exemplos incluem um ventilador que não faz vento, um app que zumbifica as
fotos dos seus amigos, flatulência digital e por aí vai.
Ganhando dinheiro com apps
Diversos são os valores destes aplicativos e 80% de todo o faturamento do
mercado de apps mobile vem de games gratuitos, que mais tarde vendem
bens dentro do jogo ou usam de publicidade. Os demais games possuem
valores entre U$0,99 e U$12, sendo que a imensa maioria se encontra na
extremidade de menor valor.
Seja qual for o gênero ou preço, o fato é que o mercado de apps está
bombando.
Empresas como a Evernote, possuem 100 milhões de usuário que geram mais
de U$150 milhões ao ano.
O Waze, popular app de mapas e rotas possui mais de 40 milhões de usuário
e foi comprado pelo Google por U$1,3 bilhões.
A Supercell, criadora de sucessos como Hay Day e Clash of Clans teve 51%
de suas ações compradas por U$1,5 bilhões por um banco japonês.
Outra notória compra foi a do Instagram, que com 260 milhões de usuários
foi comprado pelo Facebook, no valor de U$1 bilhão entre dinheiro e ações
da própria empresa.
A Google Play possui atualmente mais de 2.2 milhões de apps e por dia são
ativados 850 mil dispositivos Android no mundo.
O que você está esperando para ter o seu lugar ao sol?
Se quiser saber mais sobre como ganhar dinheiro com apps, recomendo este
post do meu blog http://www.luiztools.com.br/post/fiz-um-app-e-agora-
como-ganho-dinheiro/
3 A FERRAMENTA ANDROID STUDIO
Existem diversas ferramentas possíveis de se usar para desenvolver
aplicativos para Android.
Nenhuma delas supera a criatividade e competência de um bom
desenvolvedor, mas todas ajudam a aumentar sua produtividade e lhe
permitem criar apps cada vez mais profissionais.
Escolher uma boa ferramenta é uma boa maneira de começar na frente no
desenvolvimento de apps, uma vez que uma má ferramenta pode lhe atrasar
em demasia ou mesmo fazer com que perca tempo com configurações ou
mesmo falhas de software ao invés de apenas programar.
Recomendo e uso no desenvolvimento deste livro a ferramenta oficial do
Google, chamada de Android Studio, uma IDE construída sobre o IntelliJ,
outra IDE de código aberto assim como o famoso Eclipse.
O Android Studio encontra-se, na época de escrita deste livro, na sua versão
2.1, e tem se mostrado bem estável e com atualizações mensais, o que é uma
boa vantagem, mostrando que o Google realmente está investindo tempo e
dinheiro no seu desenvolvimento.
Usaremos esta ferramenta durante os estudos do livro e pode baixá-la neste
link: https://developer.android.com/studio/index.html .
Caso deseje usar outra ferramenta, em meu blog ensino como usar:
● Eclipse: http://www.luiztools.com.br/post/como-programar-apps-
android-no-eclipse/
● NetBeans: http://www.luiztools.com.br/post/como-programar-apps-
android-no-netbeans/
Instalando
Antes de instalar o Android Studio você irá precisar ter o JDK instalado em
sua máquina, que pode ser baixado no site oficial da Oracle (na época de
escrita deste livro a versão mais recente é a Java 8):
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-
2133151.html
No site da Oracle existirão uma dezena de versões do JDK para baixar,
procure o seu sistema operacional na lista e baixe a versão mais recente.
Baixe e instale o JDK apenas avançando durante o instalador, para somente
depois mandar instalar o Android Studio. Caso você não instale nessa ordem,
o Android Studio não irá encontrar sozinho o JDK e exigirá que você
configure seu sistema operacional manualmente, definindo uma variável de
ambiente JAVA_HOME para a pasta do seu JDK.
Assim que estiver com o JDK instalado, baixe a última versão do Android
Studio (que na época em que escrevo este livro é a 2.2) no site oficial:
https://developer.android.com/studio/index.html
Baixe e instale o Android Studio apenas avançando durante o instalador.
Após a instalação, siga em frente executando pela primeira vez o Android
Studio, seja pelo menu Inicializar do Windows, pela pasta de aplicativos no
Mac OSX ou como quer que chamem o “Inicializar do Linux”.
Atenção: certifique-se de instalar o Android Studio em um caminho que não
contenha espaços em branco ou acentos, para evitar problemas de
compatibilidade mais tarde.
Configurando
Ao abrir o Android Studio você deve visualizar a seguinte tela, logo após a
splash screen. Clique na opção Configure (no rodapé à direita) e depois em
SDK Manager.
Next e poderá escolher qual modelo de app irá usar para criar o seu. Escolha
a opção Empty Activity, que explicaremos do que se trata mais tarde.
Atenção: se você selecionar uma versão de Android que ainda não tenha
baixado para sua máquina, o Android Studio irá começar o download por
conta própria agora mesmo, o que pode demorar um pouco.
Avance e chegará à última tela, que lhe pede o nome da Activity (nem
sabemos o que é isso ainda), o nome do Layout e o Título da Activity. Deixe
tudo como está e mande encerrar clicando no botão de Finish.
Agora sim podemos explorar a ferramenta!
Atenção: o Android Studio é uma ferramenta bem pesada e com uso
constante de Internet. É praticamente impossível usá-lo completamente sem
estar conectado e você verá que muitas vezes ele poderá estar um pouco
lento, principalmente nesta primeira etapa de criação e configuração do
projeto e mais para frente em etapas de compilação. Ter um SSD ajuda muito
nestas horas pois o IO de disco é intenso.
Project
Na imagem acima temos a seção Project, que lista toda a estrutura de pastas e
arquivos do projeto.
Mais tarde iremos estudar exatamente para que servem cada uma destas
pastas e arquivos.
Por ora, apenas note que os fontes do nosso aplicativo ficam em app/java/ e
por fim o pacote das suas classes Java, onde estão a lógica do seu app. No
meu caso é o pacote com o nome de com.example.luizfduartejr.myapplication
Atenção: Se você não estiver vendo algo muito parecido com isso na sua
ferramenta pode estar com uma configuração de visualização do projeto
diferente da minha. Note um botão “Android” logo acima da pasta app,
clicando nele você pode mudar a forma de ver e gerenciar o projeto.
O Menu View
Caso perca esta seção (Project) ou outra qualquer, você pode facilmente
exibi-las novamente usando o menu View > Tool Windows e escolhendo a
janela ou seção que “perdeu” durante o desenvolvimento.
É no menu View que temos também dois recursos muito interessantes para
pessoas como eu, que tem de dar cursos de Android: Enter Presentation Mode
e Enter Full Screen.
A primeira opção otimiza toda área de trabalho do Android Studio para
exibição em um telão, com foco no editor de código em si. A segunda opção
maximiza a área de trabalho e é indicado para trabalhar em projetos com
grande quantidade de código Java a ser analisado, e até mesmo para aumentar
o foco do desenvolvedor no projeto sem ser distraído com outras janelas.
Qualquer uma destas opções pode ser revertida acessando o mesmo menu
View novamente e clicando em Exit Presentation Mode ou Exit Full Screen,
respectivamente.
Editor de Código
No centro da IDE, desde que uma classe Java esteja aberta (como
MyActivity.java), você verá o editor de código, organizado em abas para
melhorar a navegabilidade entre os documentos que estão sendo editados no
momento, com a possibilidade de fechar quaisquer documentos que não estão
sendo usados no botão ‘x’ no canto direito de cada aba.
Cada um desses documentos pode ser aberto através da seção Project à
esquerda, que foi vista no tópico anterior. Por ora vamos nos ater às
funcionalidades e não ao código que foi gerado automaticamente durante a
criação do projeto com o modelo Empty Activity.
Código 1: disponível em luiztools.com.br/livro-android-fontes
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Note que mesmo com a aba Text selecionada, ainda temos uma ferramenta
visual à direita para nos ajudar a entender o que estamos criando.
Quando alteramos o texto de algum controle na esquerda, o mesmo é
automaticamente exibido no simulador à esquerda.
Não obstante, o editor de código XML é muito bom e conta também com
recursos como code complete (vai dando sugestões enquanto você escreve) e
highlight syntax (colore as palavras de acordo com sua função), tornando
muito produtiva a tarefa de construção de interfaces em modo texto.
Ainda assim, se você preferir, pode utilizar a aba Design para construir sua
interface visualmente, arrastando componentes da Palette, que fica à esquerda
do simulador.
A cada componente arrastado, um trecho novo de código é adicionado em
background ao arquivo XML de interface, ou seja, no fundo, só existe uma
forma de construir o layout, sendo que a Palette é apenas um recurso gráfico
para facilitar sua vida.
O mais comum é que seja utilizado uma mescla das duas abordagens,
utilizando a Palette para criar o componente na interface e usando a aba Text
para configurar o layout e suas propriedades e às vezes até para copiar e colar
alguns trechos.
Falando em propriedades, cada um dos atributos do nó XML do arquivo de
layout é considerado uma propriedade do componente.
Além disso, quando selecionamos um componente no modo de edição visual,
na direita aparece uma seção Properties, com as propriedades passíveis de
configuração daquele componente, conforme mostra a imagem abaixo,
quando selecione com o mouse um TextView (rótulo de texto):
Estas propriedades tanto podem ser manipuladas visualmente pela seção
Properties quanto em modo texto. Note que as mesmas propriedades
aparecem nesse trecho de código do arquivo XML de layout:
Código 2: disponível em luiztools.com.br/livro-android-fontes
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello world!" />
Isso irá abrir a janela AVD Manager, como mostrado abaixo. O AVD
Manager serve para gerenciar as máquinas virtuais Android que usaremos
para a maioria dos testes e exemplos práticos deste livro.
Obviamente nada é melhor do que testar seus aplicativos em um dispositivo
de verdade, o que ensinaremos mais à frente, mas por ora, é importante
conhecermos as ferramentas nativas para teste.
No exemplo acima eu já possuo dois dispositivos virtuais de teste
configurados.
Para criar um novo, clique no botão Create Virtual Device, que abrirá o
wizard de configuração do dispositivo. Neste wizard definimos todas as
características de hardware e software do nosso aparelho virtual.
Na primeira tela escolhemos a plataforma, “Phone”, o modelo de exemplo,
“Nexus One” e avançamos com o botão “Next”.
Na tela seguinte escolhemos a imagem do sistema que vamos utilizar no
emulador.
Por padrão o Android Studio vem com a imagem do Android mais recente
instalado, mas esta janela do wizard irá lhe listar mesmo as imagens que você
ainda não baixou, o que forçará o seu download automaticamente.
Apenas selecione o Android Lollipop para celulares com chip ARM que são
os mais indicados na época de escrita deste livro e avance novamente.
Na última janela do wizard temos a opção de definir o nome da máquina
virtual (que deve ser único e preferencialmente sem acentos), a escala da tela
(para que seja melhor exibido no seu computador, uma vez que alguns
dispositivos podem ter resoluções maiores que a do seu monitor).
Duas outras opções permitem usar a GPU física do computador para
aumentar a velocidade do processamento gráfico, enquanto que a segunda
permite criar snapshots, que é como se o emulador fosse hibernado ao invés
de desligado, possibilitando inicializações mais rápidas no futuro.
Antes de finalizar você pode ainda querer definir algumas configurações
avançadas clicando em “Show Advanced Settings”, como memória RAM do
dispositivo (512MB para Android 2 ou 1GB para posteriores é o suficiente),
câmera frontal/traseira (que pode ser configurada para usar sua webcam ou
uma imagem pré-definida), memória interna, cartão SD, teclado físico e por
aí vai.
Conforme necessitarmos de tais recursos de hardware voltaremos nesta parte
para configurá-los.
Clique em Finish e nossa VM será criada em poucos minutos, bastando clicar
no botão de Play para iniciar a emulação.
Atenção: A inicialização do Android pode demorar bastante, então não é
algo que irá querer vivenciar a cada vez que fizer uma alteração em seu
código. A dica é: após inicializar uma vez um AVD completamente, não o
feche, até que não tenha mais nada para programar em Android por hoje.
Deixe a janela do AVD aberta, inclusive podendo a fechar a janela do AVD
Manager. Quando for testar seu código Java no dispositivo virtual, ele já
estará pronto e irá executar mais rapidamente.
Agora voltando ao Android Studio, com nosso app de Olá Mundo pronto de
fábrica, vamos clicar no botão de executar nosso aplicativo (Run), que é um
ícone de Play na toolbar.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:text="Centro"
android:id="@+id/btnCentro"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:text="Norte"
android:id="@+id/btnNorte"
android:layout_centerHorizontal="true"
android:layout_above="@+id/btnCentro"/>
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:text="Sul"
android:id="@+id/btnSul"
android:layout_below="@+id/btnCentro"
android:layout_centerHorizontal="true" />
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:text="Leste"
android:id="@+id/btnLeste"
android:layout_below="@+id/btnNorte"
android:layout_toRightOf="@+id/btnCentro" />
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:text="Oeste"
android:id="@+id/btnOeste"
android:layout_below="@+id/btnNorte"
android:layout_toLeftOf="@+id/btnCentro" />
Note que invés de dizermos que os botões Oeste e Leste estão abaixo do
botão Norte, poderíamos ter definido que eles estão acima do botão Sul, o
que provocaria o mesmo efeito. De qualquer forma, o objetivo final foi
alcançado, como mostra a imagem a seguir:
Linear Layout
O LinearLayout é um gerenciador de layout muito parecido com o
FlowLayout do Java Swing. Nele definimos a propriedade orientation como
sendo vertical ou horizontal e isso irá fazer com que todos componentes
sejam posicionados um embaixo do outro (vertical) ou um ao lado do outro
(horizontal).
Isto pode parecer um tanto inútil quando visto sob a ótica simplista de usar
apenas um gerenciador de layout por tela, mas está longe de ser verdade. O
LinearLayout é um gerenciador poderoso quando queremos montar telas com
componentes alinhados em linhas e colunas, como em uma tabela, mas muito
mais flexível.
Isso porquê o Android nos permite aninhar diferentes gerenciadores de
layouts para produzir os mais variados efeitos e um dos usos mais comuns
desse recurso é o de combinar LinearLayouts horizontais e verticais para criar
o efeito de linhas e/ou colunas, ou mesmo combinar RelativeLayouts com
LinearLayouts para criar layouts realmente responsivos, que se adaptem à
todo tipo de tela.
Para exemplificar, vamos criar um formulário onde tenhamos 3 linhas
imaginárias com elementos dispostos nelas, um ao lado do outro.Para isso,
devemos começar definindo o nosso layout do XML como sendo
LinearLayout com orientation vertical (você pode fazer isso selecionando
LinearLayout durante a criação de um novo Layout resource file).
Código 9: disponível em luiztools.com.br/livro-android-fontes
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"></LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"></LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"></LinearLayout>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Nome:"
android:id="@+id/textView" />
<EditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="@+id/editText" />
</LinearLayout>
Note que defini manualmente a largura e altura do TextView para que fique
esteticamente agradável na tela do dispositivo, bem como a largura do
EditText para ocupar o máximo de espaço possível, enquanto a altura do
mesmo ficou fixa para condizer com a altura do TextView. Por fim coloquei
um texto no TextView definido como “Nome:” que geralmente serve como
rótulo para o campo à direita em formulários.
Agora, passemos à segunda linha imaginária, onde repetiremos o processo,
apenas trocando o rótulo do campo para “Endereço:”.
Código 12: disponível em luiztools.com.br/livro-android-fontes
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Endereço:"
android:id="@+id/textView2" />
<EditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="@+id/editText2" />
</LinearLayout>
E por fim, nossa última linha imaginária terá apenas dois botões: um de
Cancelar e outro de Salvar, como segue:
Código 13: disponível em luiztools.com.br/livro-android-fontes
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:text="Cancelar"
android:id="@+id/button"/>
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:text="Salvar"
android:id="@+id/button2"/>
</LinearLayout>
Atenção com o editor visual: muitas vezes você notará que o editor visual
não é preciso e ficará brigando com ele durante várias horas. Não faça isso. O
melhor que você faz é arrastar os componentes visualmente para a tela e
depois ir ao editor XML para recortar, copiar, colar e configurar seus widgets
manualmente. Isso lhe dará um domínio e compreensão mais profundos da
construção de interfaces, além de ser muito mais assertivo.
Outro uso bem comum do LinearLayout é quando queremos distribuir a
largura ou altura dos componentes de maneira variável pela tela, proporcional
ao tamanho da mesma. Para isso usamos a propriedade layout_weight onde
definimos o “peso” (na verdade a importância) de cada componente dentro de
um LinearLayout, de maneira análoga a uma porcentagem. Para decidir se
queremos que a largura (width) ou altura (height) seja proporcional ao
tamanho da tela, devemos setar a característica correspondente (layout_width
ou layout_height) como 0dp.
No exemplo abaixo temos a seguinte configuração: três botões dentro de um
LinearLayout horizontal, com a propriedade layout_width como 0dp e
layout_weight com 3, 2 e 1, respectivamente do primeiro ao terceiro botão.
Com isso, o primeiro botão ocupará 3x mais espaço que o terceiro, enquanto
que o segundo será o meio termo. Isso garante que os mesmos se esticarão
horizontalmente para preencher a largura da tela, seja um smartphone ou uma
smarTV.
Quando você solta o componente ele exibe bordas ao seu redor com ícones
quadrados para redimensionamento nos cantos do componente e ícones
circulares para constraints nas laterais dele.
Clique no componente para selecioná-lo. Então clique e segure um dos ícones
circulares (constraint handle) arrastando até um ponto de ancoragem
disponível (a face de outro componente, do parent layout ou uma linha-guia).
Quando você soltar, a constraint será criada, com uma margem default
separando os dois componentes, como mostra abaixo.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Texto Grande"
android:id="@+id/lblTeste" />
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:text=""
android:id="@+id/txtTeste"/>
Uma vez que a digitação em teclados virtuais nem sempre é tão prática
quanto em teclados convencionais, onde temos mais espaço para posicionar
as teclas (e mãos), o Android fornece a opção de definir o tipo de entrada que
vai ser disponibilizada para o usuário, como textos numéricos, nomes
próprios, senhas, etc, o que muda automaticamente o comportamento do
teclado virtual, que passa a exibir primariamente os números ou letras, por
exemplo. Na paleta de componentes estão disponíveis uma série de
componentes EditText pré-configurados e você deve usá-los conforme a
necessidade, sendo que suas configurações básicas não mudam. Arraste um
para um layout XML e veja o que acontece ao lado.
A propriedade inputType define o tipo de texto que planejamos colocar nesse
EditText. No caso de textPersonName, o próprio teclado virtual vai gerenciar
o uso de maiúsculas e minúsculas nas palavras que irão compor o nome
próprio que será escrito, sem a necessidade de Shift ou Caps-Lock. Outros
inputTypes possíveis incluem numberDecimal, que faz com que o teclado
virtual já venha com os números à mostra.
Independente do inputType do EditText, a sua manipulação através de código
Java é idêntica. Sempre que quiser definir o texto presente no EditText ou ler
a informação que o usuário inseriu lá, use o seguinte código Java:
Código 17: disponível em luiztools.com.br/livro-android-fontes
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content">
<requestFocus />
</EditText>
Button e ImageButton
Nenhum formulário está completo sem botões. Seja para salvar, cancelar,
limpar ou validar um formulário, o widget Button pode ser usado. A
diferença crucial entre o Button tradicional e o ImageButton é que o segundo
pode possuir uma imagem criada por você ao invés do tradicional formato
retangular com texto dentro. No mais, são exatamente iguais.
Arraste um Button para seu formulário (sendo que o Android define alguns
tamanhos pré-definidos de botões na paleta que podem lhe ajudar) e teremos
o seguinte código no editor XML.
Código 19: disponível em luiztools.com.br/livro-android-fontes
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Botão"
android:id="@+id/btnTeste" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Botão"
android:id="@+id/btnTeste"
android:onClick="exibirMensagem" />
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cadastro);
}
Como você já deve ter entendido, para cada botão que eu quiser que seja
disparado em minha Activity, terei de criar um método para tratar o evento
onClick dele. Embora essa não seja a única maneira de fazer a ligação do
evento onClick como código Java, sem sombra de dúvida é a mais fácil.
Também é possível criar apenas um método para tratar todos os botões, pois
o parâmetro view contém todas as informações sobre qual o botão que
disparou este método. Entretanto esta abordagem não é usual, a menos que
muitos botões tenham comportamentos muito parecidos, como em uma
calculadora.
Atenção com o Toast: é muito comum os programadores esquecerem que o
Toast exige a chamada do método show() para que apareça de fato na tela do
app.
Para finalizar, com relação ao ImageButton, a única alteração a ser feita é a
exibição de uma imagem que já deve estar em seu projeto, na pasta de
res/drawable, como esta abaixo, por exemplo (vip.png). Cada imagem deve
ter um nome único (como de praxe, não pode conter acentos, hífen ou
espaços) e este nome servirá como identificador único da mesma na
aplicação.
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/salvar"
android:onClick="salvar"
android:id="@+id/btnImagem"/>
Note que a propriedade src define qual a imagem que vai ser utilizada, sem a
sua extensão (neste caso, salvar.png). Note também que o ImageButton
também possui uma propriedade onClick, que define o método Java a ser
executado na Activity que carregar este layout, assim como o botão
tradicional.
Atenção sobre imagens: imagens de botões geralmente são ícones que
ilustram o que aquele botão faz, como um disquete para salvar ou uma lixeira
para excluir. Um bom site para baixar ótimos ícones gratuitos é o
http://www.iconfinder.com e outro é o http://www.findicons.com.
Você também pode carregar a imagem dinamicamente a partir da web ou a
partir do cartão SD do dispositivo do usuário, em tempo de execução. Para
isto, veja mais à frente o funcionamento do carregamento dinâmico de
imagens como o widget ImageView, que é idêntico ao ImageButton, com
exceção de que não dispara eventos ao ser clicado.
Spinner
Muitas vezes precisamos exibir diversas opções aos usuários mas temos um
espaço limitado para tal. Um Spinner é um widget que permite que o usuário
selecione apenas uma opção dentre inúmeras disponíveis, como uma lista de
estados ou de profissões. Em alguns frameworks este controle também é
chamado de ComboBox ou DropDownList.
Arraste um Spinner para um layout XML e vamos configurá-lo!
Código 23: disponível em luiztools.com.br/livro-android-fontes
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/spinner" />
As opções que serão listadas no Spinner podem ser configuradas via arquivo
XML ou via código Java. Para configurar via arquivo XML (maneira mais
fácil) você deve criar dentro da pasta res/values um novo arquivo XML
(Values resource files) com o nome de estados.xml (por exemplo).
Coloque o seguinte conteúdo dentro dele:
Código 24: disponível em luiztools.com.br/livro-android-fontes
Neste exemplo coloquei apenas os 3 estados do sul do país para não ficar tão
extenso, mas você deve ter entendido a ideia. Aqui criamos um array de
Strings com o nome de “estados”, contendo diversos itens, sendo cada item a
sigla de um estado.
Agora no Spinner, para linkarmos o XML de estados com o widget, usamos a
propriedade entries, como segue:
Código 25: disponível em luiztools.com.br/livro-android-fontes
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/spinner"
android:entries="@array/estados"/>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cliente);
E por último, mas não menos importante, existem ocasiões em que você quer
que alguma ação seja realizada toda vez que um item for selecionado
(imediatamente). Nestes casos, você deve linkar o controle spinner com um
código Java em sua Activity. Não há qualquer alteração a ser realizada no
XML do exemplo de carregamento do Spinner, apenas no código Java da
Activity, como segue.
Código 28: disponível em luiztools.com.br/livro-android-fontes
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cliente);
spinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener()
{
@Override
public void onItemSelected(AdapterView<?> parent, View view, int
position, long id) {
String uf = spinner.getSelectedItem().toString();
Toast.makeText(getBaseContext(), "UF selecionado: " + uf,
Toast.LENGTH_LONG).show();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
Note como foi criado uma variável Spinner no escopo da classe mas fora do
evento onCreate. Isso garante que a variável seja carregada apenas uma vez
no onCreate e chamada quantas vezes precisar dentro a activity. Este evento
será disparado toda vez que um item do spinner for selecionado.
Para o código a ser executado, apenas um Toast exibindo o estado que foi
selecionado. Note que poderia ser a chamada Java que você quisesse, como
por exemplo carregar outro spinner na sequência com as cidades daquele
estado, por exemplo, ou ocultar/exibir outro campo.
O Spinner é um componente muito poderoso e ele permite inclusive que
possamos criar layouts inteiramente personalizados. Claro, essa não é uma
tarefa muito trivial e é de necessidade duvidosa uma vez que listagens
complexas deveriam ser ListViews (ver mais adiante, na seção de
Containers). Entretanto, existe mais uma coisa “avançada” que devemos
aprender antes de avançar para o próximo widget: Spinners com chave-valor!
Basicamente queremos que o Spinner exiba um texto, como o nome do
estado, mas quando a gente quiser ler o que foi selecionado, queremos pegar
um código, como a sigla do estado. Como fazer isso? É mais fácil do que
parece e primeiramente iremos precisar criar uma classe Estado no package
principal do nosso app. Nossa classe Estado, que está ilustrada abaixo, possui
apenas dois atributos (nome e sigla), um construtor e a sobrecarga do método
toString forçando os objetos de Estado a retornarem o seu nome quando
forçados a se tornarem Strings. Por quê? Veremos daqui a pouco, apenas
confie em mim por enquanto!
Código 29: disponível em luiztools.com.br/livro-android-fontes
@Override
public String toString(){ return this.nome; }
}
A seguir, o código de carregamento do nosso ArrayList de estados, que
obviamente poderia ser carregado a partir de um banco de dados ou
webservice. Por ora, deixaremos estático dentro do evento onCreate de uma
Activity qualquer (a mesma que terá o Spinner de estados). Após
carregarmos os estados, criamos nosso ArrayAdapter, mas desta vez ao invés
de usarmos Strings simples usaremos um ArrayAdapter<Estado> que permite
que coloquemos o nosso List<Estado> dentro, para em seguida carregar
nosso Spinner e definirmos o adapter com setAdapter.
Código 30: disponível em luiztools.com.br/livro-android-fontes
spinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int
position, long id) {
Estado uf = (Estado)spinner.getSelectedItem();
Toast.makeText(getBaseContext(), "UF selecionado: " + uf.getSigla(),
Toast.LENGTH_LONG).show();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/grpSexo">
</RadioGroup>
<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/grpSexo">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Masculino"
android:id="@+id/radMasculino"/>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Feminino"
android:id="@+id/radFeminino"/>
</RadioGroup>
Como efeito temos a seguinte tela renderizada.
E para descobrir qual dos dois RadioButtons está selecionado, use o código
abaixo, onde carregamos cada um dos RadioButtons em variáveis para usar o
método isSelected() que retorna true ou false, dependendo do estado do
RadioButton.
Código 34: disponível em luiztools.com.br/livro-android-fontes
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cliente);
RadioButton radMasculino =
(RadioButton)findViewById(R.id.radMasculino);
RadioButton radFeminino =
(RadioButton)findViewById(R.id.radFeminino);
if(radMasculino.isSelected()) {
//o sexo masculino foi selecionado durante o cadastro
}
else if(radFeminino.isSelected()){
//o sexo feminino foi selecionado durante o cadastro
}
}
radMasculino.setOnCheckedChangeListener(new
RadioButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean
isChecked) {
//esse método dispara no instante que o radio masculino for selecionado!
}
});
CheckBox
Um CheckBox é um componente composto por uma caixa que pode estar
selecionada ou não e um texto descritivo da característica associada à caixa.
Utilizamos Checkboxes quando queremos que o usuário informa Sim ou Não
para uma afirmação ou característica, como “Desejo receber e-mails com
informativos” ou “Este cliente é VIP”. Seja qual for o objetivo, para começar
você deve arrastar um CheckBox para seu layout.
Código 36: disponível em luiztools.com.br/livro-android-fontes
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Desejo receber informativos"
android:id="@+id/chkReceberInformativos"/>
chkReceberInformativos.setOnClickListener(new
CheckBox.OnClickListener() {
@Override
public void onClick(View v) {
boolean selecionado = chkReceberInformativos.isSelected();
//método dispara no instante em que o checkbox foi clicado
}
});
Nota sobre Spinner, RadioGroup e CheckBox: uma pergunta comum é:
quando devemos utilizar cada um deles? Na verdade, faça-se a pergunta:
quantas opções o usuário deve ter? Se o usuário tem apenas as opções Sim e
não, o CheckBox é a melhor alternativa, ou no máximo o RadioGroup. Se o
usuário tiver até umas três opções, o Radiogroup é uma boa pedida. Mais do
que isso, mas dentro de poucas dezenas use um Spinner. Note que se o
conjunto de opções realmente for grande ou muito dinâmico, não tem saída,
você terá de usar um EditText, para permitir que o usuário tenha mais
liberdade ou faça combinações de Spinners, como a divisão clássica
estado/cidade que é muito mais inteligente do que listar as quase 5 mil
cidades brasileiras pro usuário escolher uma.
ImageView
O controle ImageView pode ser utilizado tanto para exibir uma imagem
estática, que esteja na pasta res/drawable (neste exemplo eu possuo uma
arsenal.png) quanto uma imagem dinâmica, carregada do smartphone. O
primeiro exemplo é mais simples, e começa arrastando-se um ImageView
para o layout XML e configurando seu atributo src com o nome da imagem
sem a extensão, neste caso, arsenal.png.
Código 39: disponível em luiztools.com.br/livro-android-fontes
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/arsenal"
android:id="@+id/imageView"/>
Neste exemplo não limitamos as dimensões da imagem e por isso ela ocupará
a tela inteira pois era muito grande. Caso queira limitar as dimensões da
mesma, use as propriedades maxHeight e maxWidth.
A outra opção que temos é carregar dinamicamente a imagem através de
código Java. Ainda assim, a imagem deve estar no seu telefone, seja no
armazenamento interno ou cartão SD. Para carregar imagens da Internet você
teria de baixar a imagem primeiro para o disco ou uma variável antes de ser
configurada na ImageView. Uso de recursos da Internet será mostrado em
capítulos posteriores.
Independente disso, o código Java abaixo pode lhe ajudar a entender como
carregar uma imagem dinamicamente:
Código 40: disponível em luiztools.com.br/livro-android-fontes
Outra alternativa, muito mais simples, porém não tão dinâmica, é ter a
imagem que se deseja exibir na pasta drawables do projeto e chamá-la pelo id
único no código da Activity que carrega a imagem na ImageView, como
abaixo, onde existe uma imagem florianopolis.jpg na pasta drawable do
projeto (e que o id é mapeado pela classe R dentro de R.drawable):
Código 41: disponível em luiztools.com.br/livro-android-fontes
Existem diversos outros widgets que não serão abordados neste livro como
ProgressBar, SeekBar e WebView, além da categoria Date & Time que
possuem documentações completas no site oficial
http://developer.android.com
Containers
Containers são um tipo especial de widget que permite que outros widgets
sejam inseridos no seu interior. O RadioGroup que usamos anteriormente
para agrupar os RadioButtons é um exemplo de container bem específico,
que aceita apenas RadioButtons dentro dele. Geralmente os containers por si
só não possuem grandes efeitos no app, mas quando utilizados em conjunto
com outros widgets são extremamente poderosos.
ListView
ListView é um grupo de views que exibe uma lista de itens “roláveis”. Os
itens da lista são automaticamente inseridos na lista usando um Adapter que
puxa o conteúdo da fonte como um array ou base de dados e converte cada
item em uma view colocada na lista.
Você pode adicionar uma ListView como um widget normal, em qualquer
layout dando um id para que possamos programá-la depois. Poucas
propriedades precisam de atenção, e uma delas é colocar um id único na sua
ListView, assim como faz com qualquer widget. Neste exemplo a Activity
terá o layout abaixo, onde temos um campo de busca com botão no topo e
uma ListView logo abaixo.
Código 42: disponível em luiztools.com.br/livro-android-fontes
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<EditText
android:layout_width="fill_parent"
android:layout_height="45dp"
android:maxLength="10"
android:id="@+id/txtPesquisa"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" />
<Button
android:layout_width="80dp"
android:layout_height="45dp"
android:text="Buscar"
android:onClick="btnBuscar_OnClick"
android:id="@+id/btnBuscar"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/lstResultados"
android:layout_below="@+id/txtPesquisa"
android:layout_marginTop="10dp"/>
</RelativeLayout>
ListView lstResultados;
EditText txtPesquisa;
Button btnBuscar;
String[] cidades = { "Porto Alegre", "Florianópolis", "Curitiba", "São
Paulo" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtPesquisa = (EditText)findViewById(R.id.txtPesquisa);
btnBuscar = (Button)findViewById(R.id.btnBuscar);
lstResultados = (ListView)findViewById(R.id.lstResultados);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtPesquisa = (EditText)findViewById(R.id.txtPesquisa);
btnBuscar = (Button)findViewById(R.id.btnBuscar);
lstResultados = (ListView)findViewById(R.id.lstResultados);
lstResultados.setOnItemClickListener(new
ListView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int
position, long id) {
String cidade = lstResultados.getItemAtPosition(position).toString();
Toast.makeText(getBaseContext(), "Item " + cidade,
Toast.LENGTH_LONG).show();
}
});
}
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imgCidade"
android:src="@drawable/florianopolis"
android:layout_marginRight="10dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Florianópolis"
android:id="@+id/lblCidade"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/imgCidade" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="/SC"
android:id="@+id/lblUF"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/lblCidade"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Capital de Santa Catarina"
android:id="@+id/lblDescricao"
android:textColor="@android:color/darker_gray"
android:layout_below="@+id/lblCidade"
android:layout_toRightOf="@+id/imgCidade"/>
</RelativeLayout>
Agora que temos o layout personalizado que será utilizado para renderizar os
itens da nossa ListView, é hora de criarmos a classe cujos objetos irão
guardar as informações a serem exibidas. Nossa classe Cidade deverá se
parecer com a abaixo:
Código 46: disponível em luiztools.com.br/livro-android-fontes
Mas como o Android vai saber qual informação deve ir em cada parte do
nosso layout personalizado? Nós temos de dizer isso pra ele! O ArrayAdapter
tradicional não consegue dar conta deste recado, por isso devemos criar o
nosso Adapter personalizado, que vamos chamar de CidadeAdapter e que
será uma subclasse do Adapter original. Nesse Adapter personalizado,
colocaremos a lógica de como fazer o binding dos campos de cada item da
ListView conforme o layout XML que criamos para o mesmo. Segue abaixo
um exemplo onde o método getView será disparado uma vez para cada item
que adicionarmos na ListView, carregando a cidade em questão e
adicionando cada um dos seus atributos ao widget correspondente no layout
item_modelo.xml.
Código 48: disponível em luiztools.com.br/livro-android-fontes
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null) {
Context ctx = getContext();
LayoutInflater vi =
(LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE
v = vi.inflate(R.layout.item_modelo, null);
}
Cidade cidade = items.get(position);
if (cidade != null) {
((TextView)
v.findViewById(R.id.lblCidade)).setText(cidade.getNome());
((TextView) v.findViewById(R.id.lblUF)).setText("/" +
cidade.getUf());
((TextView)
v.findViewById(R.id.lblDescricao)).setText(cidade.getDescricao());
((ImageView)
v.findViewById(R.id.imgCidade)).setImageResource(cidade.getIdImagem());
}
return v;
}
}
Realizando o mesmo teste que fizemos com o app anterior, mas desta vez
com a nossa nova versão com objeto e layout personalizados, obtemos o
seguinte resultado:
E por fim, como mencionado anteriormente, no evento de click de um item
da lista, na hora que quisermos fazer alguma ação com base no objeto
selecionado, teremos de fazer uma conversão um pouco diferente do toString
usado anteriormente, como segue:
Código 50: disponível em luiztools.com.br/livro-android-fontes
lstResultados.setOnItemClickListener(new ListView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Cidade cidade = (Cidade)lstResultados.getItemAtPosition(position);
Toast.makeText(getBaseContext(), "Item " + cidade.getNome(),
Toast.LENGTH_LONG).show();
}
});
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/scrollView">
</ScrollView>
</RelativeLayout>
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/scrollView">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</RelativeLayout>
</ScrollView>
A classe Dialog é a classe base para dialogs, mas você deve evitar instanciar
Dialog diretamente. Ao invés disso, use uma das seguintes subclasses:
AlertDialog
Um dialog que pode mostrar um título, até três botões, uma lista de itens
selecionáveis ou um layout personalizado.
DatePickerDialog ou TimePickerDialog
Um dialog com uma interface pré-definida que permite ao usuário selecionar
data ou hora.
ProgressDialog
Android inclui outra classe dialog chamada ProgressDialog que exibe um
dialog com uma barra de progresso. Entretanto, se você precisa indicar o
carregamento ou progresso indeterminado, você deve ao invés disso usar uma
ProgressBar em seu layout, como indicam as guidelines do Android.
Usando Dialogs
Você pode criar, configurar e disparar um dialog da seguinte maneira:
Código 53: disponível em luiztools.com.br/livro-android-fontes
Uma vez que a lista aparece na área do conteúdo do dialog, ele não pode
exibir uma lista e uma mensagem ao mesmo tempo e você deve definir um
título para o dialog com setTitle(). Para especificar itens para a lista chame
setItems(), passando um array. Alternativamente, você pode especificar uma
lista usando setAdapter(). Isto permite a você retornar à lista com dados
dinâmicos (como de uma base de dados) usando ListAdapter.
Abaixo o exemplo de array utilizado no código anterior, salvo em um arquivo
cores.xml na pasta res/values:
Código 56: disponível em luiztools.com.br/livro-android-fontes
Por padrão, tocar um item da lista desfaz o dialog, a menos que esteja usando
os métodos setMultiChoiceItems (checkboxes) e setSingleChoiceItems (radio
buttons).
Criando um Dialog com layout personalizado
As classes que acabamos de ver definem o estilo e estrutura básica para seu
dialog, mas se quiser ir mais longe terá de usar um DialogFragment como
container. A classe DialogFragment fornece todos os controles que você
precisa para criar seu dialog e gerencia sua aparência, ao invés de chamar os
métodos do objeto Dialog.
Atenção: a classe DialogFragment foi originalmente criada com Android 3.0
(API 11) e mais tarde incorporada à Support Library para que fosse possível
ser utilizada em versões do Android 1.6+. Para usar a mesma versão deste
material, certifique-se de referenciar a biblioteca
android.support.v4.app.DialogFragment ao invés de
android.app.DialogFragment.
Logo abaixo está um AlertDialog personalizado básico, estendendo a classe
DialogFragment. Este exemplo foi retirado da documentação oficial do
Android e apenas usaremos o mesmo como um breve exemplo. Dentro do
evento onCreateDialog coloca-se a lógica de construção do nosso dialog
usando o design pattern Builder (se você ainda não conhece os design
patterns, deveria!), configurando a mensagem (com o método setMessage), a
ação do clique do botão “positivo” (setPositiveButton) e a ação do botão
“negativo” (setNegativeButton). Por último retornamos nosso diálogo criado
chamando o método create().
Código 57: disponível em luiztools.com.br/livro-android-fontes
Agora, quando criar uma instância desta classe e chamar o método show() em
um objeto do tipo FireMissilesDialogFragment e o dialog aparecerá como na
figura abaixo.
Código 58: disponível em luiztools.com.br/livro-android-fontes
Mas queremos ir mais longe que isso, certo? E se quisermos criar um dialog
onde o usuário possa digitar um texto em um EditText e a partir deste texto
realizarmos alguma ação? O primeiro passo é criarmos o layout desse dialog,
que chamei de dialog_nova_pasta e que está guardado junto com os demais,
na pasta res/layout, como segue:
Código 59: disponível em luiztools.com.br/livro-android-fontes
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Digite o nome da nova pasta:" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/txtNovaPasta" />
</LinearLayout>
O que deve se parecer com isso aqui (note que não coloquei os botões
propositalmente):
@Override
public Dialog onCreateDialog(Bundle bundle){
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Nova Pasta")
.setPositiveButton("Criar", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which) {
//...
}
});
return builder.create();
}
}
@Override
public Dialog onCreateDialog(Bundle bundle){
final Activity activity = getActivity();
LayoutInflater inflater = activity.getLayoutInflater();
View v = inflater.inflate(R.layout.dialog_nova_pasta, null);
Para disparar este nosso dialog personalizado, basta uma simples instanciação
de um objeto da classe NovaPastaDialog e a chamada ao método show(),
como segue:
Código 63: disponível em luiztools.com.br/livro-android-fontes
new NovaPastaDialog().show();
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<item android:id="@+id/menu_nova_pasta" android:title="Nova
Pasta"
android:orderInCategory="100" app:showAsAction="never" />
<item android:id="@+id/menu_novo_arquivo" android:title="Novo
Arquivo"
android:orderInCategory="200" app:showAsAction="never" />
<item android:id="@+id/menu_sair" android:title="Sair"
android:orderInCategory="300" app:showAsAction="never" />
</menu>
Para usar o menu em sua activity, você precisa carregar o resource de menu
(também chamado de “inflar”, que nada mais é do que converter um resource
XML em um objeto programável) usando MenuInflater.inflate(). Na seções
seguintes, você irá ver como inflar um menu de cada tipo.
Menu de Opções
Usamos options menu quando queremos incluir ações e outras opções que
são relevantes ao contexto da activity como “Buscar”, “Escrever e-mail” e
“Configurações”. Seus itens/opções aparecem na tela em um local que
depende da versão do Android:
● ao usar Android 2.3.x (API 10) ou anterior, as opções irão aparecer no
rodapé da tela quando usuário pressionar o botão de menu. Você pode
ter até 6 items no menu que serão visíveis e se adicionar um sétimo, o
Android cria automaticamente uma espécie de paginação no menu.
● Com Android 3.0 ou superior (API 11), os itens do menu estão
disponíveis na action bar e podem ser exibidos ao tocar o canto
superior direito (com o ícone de menu) ou pressionando o botão físico
de menu no dispositivo.
Para especificar um menu de opções para uma activity, sobrescreva o método
onCreateOptionsMenu(). Neste método, você pode inflar seu resource XML
de menu em um Menu fornecendo no callback. Por exemplo:
Código 65: disponível em luiztools.com.br/livro-android-fontes
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
Você pode também adicionar itens no menu usando o método add() e retornar
itens com findItem().
Eventos de Clique
Quando o usuário seleciona um item do options menu (incluindo itens de
ação na action bar), o sistema dispara o método onOptionsItemSelected() da
sua activity. Este método passa o MenuItem selecionado. Você pode
identificar o item chamando getItemId(), que retorna o ID único para o item
do menu (definido pelo atributo android:id no resource de menu ou por um
inteiro fornecido no método add() ). Você pode comparar este ID com
prováveis Ids conhecidos para executar a ação apropriada, como segue:
Código 66: disponível em luiztools.com.br/livro-android-fontes
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_nova_pasta) {
//ação de criar nova pasta
return true;
}
else if(id == R.id.menu_novo_arquivo){
//ação de criar novo arquivo
return true;
}
else if(id == R.id.menu_sair){
finish();
}
return super.onOptionsItemSelected(item);
}
registerForContextMenu(lstArvore);
Se sua activity usa um ListView/GridView e você quer que cada item mostre
o mesmo menu contextual, registre todos itens para um menu contextual
passando a ListView/GridView para registerForContextMenu(), como
mostrado acima. Depois disso, implemente o método
onCreateContextMenu() na sua Activity.
Quando a view registrada recebe um evento de clique-longo, o sistema
dispara seu método onCreateContextMenu(). Aqui é onde você define seus
itens do menu, normalmente inflando um resource XML de menu, como
segue:
Código 68: disponível em luiztools.com.br/livro-android-fontes
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
if (v.getId() == R.id.lstArvore) {
getMenuInflater().inflate(R.menu.menu_context, menu);
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
int id = item.getItemId();
if(id == R.id.menu_ctx_editar){
//ação editar
String itemSelecionado =
lstArvore.getItemAtPosition(info.position).toString();
Toast.makeText(this, itemSelecionado, Toast.LENGTH_LONG).show();
return true;
}
else if(id == R.id.menu_ctx_excluir){
//ação excluir
return true;
}
return super.onContextItemSelected(item);
}
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
}
}
Eventos
Um evento nada mais é do que um método que não é chamado pela gente
durante a programação, mas sim pelo próprio sistema operacional Android
sob determinadas circunstâncias. O onCreate é o primeiro evento que vamos
estudar e ele está intimamente relacionado ao funcionamento geral da
Activity pois tudo começa com ele. Outros eventos importantes também são
vistos neste tópico, que juntos formam o ciclo de vida de uma Activity, ou
seja, manipulam os estados possíveis de uma Activity desde a sua criação até
sua finalização, como mostra a imagem a seguir:
Evento onCreate
Primeiro: o evento onCreate é chamado uma única vez quando a Activity é
carregada em memória (instanciada). Ou seja, é aqui que realizamos todos os
carregamentos únicos da nossa atividade, como layout que será utilizado
(através da chamada do método setContentView) e demais widgets que
quisermos manipular, como veremos mais adiante.
Código 72: disponível em luiztools.com.br/livro-android-fontes
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
}
}
EditText txtTeste;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
txtTeste = (EditText)findViewById(R.id.txtTeste);
}
}
Evento onRestart
Como mencionado anteriormente, o evento onCreate somente é executado
uma vez, quando a Activity é criada. Entretanto, podemos querer executar
alguma(s) tarefa(s) toda vez que a Activity voltar a ser o centro das atenções
do usuário, ou seja, toda vez que uma Activity estiver no topo da pilha de
Activities do Android após ter sido deixada em segundo plano (ex: um
aplicativo que vai para uma Activity de tirar foto e depois volta para a
Activity de seleção de imagem). Nessas horas devemos usar o evento
onRestart, que deve ser sobrescrito da superclasse Activity.
Código 76: disponível em luiztools.com.br/livro-android-fontes
@Override
protected void onRestart(){
super.onRestart();
//faz algo ao reiniciar
}
Esse evento pode ser colocado em qualquer ponto da sua classe que extende
Activity (MyActivity.java, por exemplo) e obrigatoriamente deve ter como
primeira instrução a chamada ao onRestart da superclasse, sendo que logo
abaixo podemos colocar o código que quisermos.
Evento onCreateOptionsMenu e onOptionsItemSelected
Estes dois eventos estão intimamente relacionados com o processo de criação
de funcionamento dos menus contextuais do seu aplicativo. Tão logo sua
Activity é criada e o evento onCreate é disparado, temos também outro
evento que entra em ação, que é onCreateOptionsMenu, que cria as opções
que existirão no menu contextual desta Activity. Os menus foram melhor
explicados no capítulo anterior, sobre containers e sua leitura é recomendada
uma vez que os menus são itens recorrentes em apps.
Outros Eventos
O ciclo de vida de uma Activity Android é muito mais complexo do que
apenas três ou quatro eventos. A imagem abaixo mostra um pouco dos
callbacks mais comuns de serem utilizados para manipular os eventos que
podem ocorrer nativamente com uma Activity, independente dos controles
que existirem na mesma. Consulte a documentação oficial do Android em
developers.android.com para saber mais detalhes acerca do ciclo de vida de
activities Android.
Os eventos relacionados aos widgets (click do Button, select do RadioButton,
etc) foram tratados em detalhes nos tópicos correspondentes do capítulo
anterior e em nada afetam o comportamento do ciclo de vida da Activity.
Código 77: disponível em luiztools.com.br/livro-android-fontes
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
//a activity está sendo criada
}
@Override
protected void onResume(){
super.onResume();
//a activity se tornou visível
}
@Override
protected void onPause(){
super.onPause();
//outra activity está assumindo o foco
}
@Override
protected void onStop(){
super.onStop();
//esta activity já não é mais visível
}
@Override
protected void onStart(){
super.onStart();
//a activity está sendo inicializada
}
@Override
protected void onDestroy(){
super.onDestroy();
//a activity está sendo finalizada
}
}
Iniciando e Finalizando Activities
Uma vez que é extremamente comum nossos apps terem mais de uma
Activity, é extremamente necessário que tenhamos o conhecimento de como
realizar as transições entre as mesmas. Para iniciar uma Activity usamos o
método startActivity, herdado da superclasse Activity, conforme abaixo.
Código 78: disponível em luiztools.com.br/livro-android-fontes
@Override
public boolean onOptionsItemSelected(MenuItem item){
int id = item.getItemId();
if(id == R.id.action_settings){
Intent intent = new Intent(this, OutraActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
int id = item.getItemId();
if(id == R.id.action_settings){
Intent intent = new Intent(this, OutraActivity.class);
startActivity(intent);
}else{
finish();
}
return super.onOptionsItemSelected(item);
}
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="fill_parent"
android:layout_height="50dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="/"
android:id="@+id/txtPath"
android:textStyle="bold"/>
<ListView
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="8"
android:id="@+id/lstArvore" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="Nova Pasta"
android:onClick="btnNovaPasta_OnClick"
android:id="@+id/btnNovaPasta" />
<Button
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:onClick="btnNovoArquivo_OnClick"
android:text="Novo Arquivo"
android:id="@+id/btnNovoArquivo" />
</LinearLayout>
</LinearLayout>
TextView txtPath;
ListView lstArvore;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtPath = (TextView)findViewById(R.id.txtPath);
lstArvore = (ListView)findViewById(R.id.lstArvore);
}
void atualizarArvore(){
String raiz = Environment.getExternalStorageDirectory().getPath();
String path = txtPath.getText().toString();
File file = new File (raiz + path);
String[] tree = file.list();
if(tree != null) {
ArrayList<String> arr = new ArrayList<>(Arrays.asList(tree));
Collections.sort(arr);
if(!path.equals("/")){
arr.add(0, "..");//se não estamos na raiz, deve dar esta opção para
voltar
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, arr);
lstArvore.setAdapter(adapter);
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
atualizarArvore();
}
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
/>
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
/>
O resultado pode ser visto na imagem abaixo, onde é possível ver a listagem
de pastas presentes na raiz do armazenamento externo, que pode ser tanto o
cartão SD, se presente, quanto o armazenamento interno (internal storage).
Nosso próximo passo agora é programar o clique de um item da lista. Caso
este item seja uma pasta, a lista deve ser atualizada com o conteúdo da
mesma. Caso o item seja um arquivo de texto, a FormActivity deve ser aberta
com o conteúdo do arquivo (neste caso apenas passamos o caminho do
arquivo e um flag edit=true, a FormActivity é quem se encarregará da lógica
restante, como veremos mais para frente). E por fim, caso o arquivo não seja
de texto, devemos apenas exibir uma mensagem de arquivo não suportado.
Para programar esta lógica, temos de mapear o gatilho OnItemClickListener
em nossa lstArvore (ListView), como abaixo, ainda dentro do nosso evento
onCreate.
Código 88: disponível em luiztools.com.br/livro-android-fontes
lstArvore = (ListView)findViewById(R.id.lstArvore);
lstArvore.setOnItemClickListener(new ListView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String path = txtPath.getText().toString();
String item = lstArvore.getItemAtPosition(position).toString();
if(!item.equals("..")) {//se não é o item 'voltar'
File file = new File(Environment.getExternalStorageDirectory()+ path
+ "/" + item);
if (file.isDirectory()) {//se é uma pasta
txtPath.setText(path.endsWith("/") ? path + item : path + "/" +
item);
} else if (file.getName().endsWith(".txt")) {//se é um arquivo de texto
Intent intent = new Intent(MainActivity.this, FormActivity.class);
intent.putExtra("path", file.getAbsolutePath());
intent.putExtra("edit", true);
startActivity(intent);
} else {//outros arquivos
Toast.makeText(view.getContext(), "Arquivo não suportado!",
Toast.LENGTH_LONG).show();
}
}
else{
String[] partes = path.split("/");
String abovePath = path.replace(partes[partes.length-1], "");
txtPath.setText(abovePath);
}
atualizarArvore();
}
});
Note que existe uma bifurcação principal baseado no texto do item clicado,
logo no início do código do evento OnItemClickListener: caso o item seja
“..” devemos reescrever o path na TextView do topo da tela, para que quando
ocorrer a próxima atualização da listagem (atualizarArvore()) dê a impressão
de que voltamos ao diretório anterior. Caso contrário, seguem as condições
anteriormente comentadas, alterando o txtPath no caso de uma pasta (o que
forçará a entrar neste diretório na próxima atualização da listagem),
disparando a FormActivity no caso de um arquivo de texto (note como foi
passado o caminho absoluto do arquivo como Extra) ou apenas exibindo um
Toast de arquivo não suportado nos demais casos.
Agora vamos programar o botão de criar Nova Pasta. Como a criação de uma
pasta é muito simples, bastando dar um nome à mesma, ao invés de abrir uma
nova Activity para criar a pasta vamos apenas exibir um Dialog contendo um
campo de texto e um botão de Salvar.
Conforme visto anteriormente, no capítulo de Interface na seção de
Containers, podemos criar caixas de diálogo personalizadas, visando tornar
nossas Activities mais dinâmicas e menos numerosas. Para isso, devemos
criar nossa própria classe de Dialog estendendo a base DialogFragment,
como mostrado no exemplo abaixo, onde crio uma classe para a nossa caixa
de diálogo de criar nova pasta.
Código 89: disponível em luiztools.com.br/livro-android-fontes
@SuppressLint("ValidFragment")
public NovaPastaDialog(String path){
this();
this.path = path;
}
@Override
public Dialog onCreateDialog(Bundle bundle){
final Activity activity = getActivity();
LayoutInflater inflater = activity.getLayoutInflater();
View v = inflater.inflate(R.layout.dialog_nova_pasta, null);
Não dê bola para o erro grafado no exemplo anterior, ele diz respeito a não
ser recomendável criar um construtor que não seja vazio em um
DialogFragment. O layout utilizado por este dialog é bem simples e pode ser
conferido logo abaixo:
Código 90: disponível em luiztools.com.br/livro-android-fontes
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Digite o nome da nova pasta:" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/txtNovaPasta" />
</LinearLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.fernando.gerenciadordearquivos.FormActivity"
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/txtPath"
android:text="Pasta:"/>
<EditText
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Novo Arquivo.txt"
android:hint="Nome do Arquivo"
android:id="@+id/txtNomeArquivo"/>
<EditText
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="7"
android:text="Lorem ipsum dolor sit amet"
android:id="@+id/txtConteudoArquivo"/>
<LinearLayout
android:layout_width="fill_parent"
android:orientation="horizontal"
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Cancelar"
android:onClick="btnCancelar_OnClick"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Salvar"
android:onClick="btnSalvar_OnClick"/>
</LinearLayout>
</LinearLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_form);
txtPath = (TextView)findViewById(R.id.txtPath);
txtNomeArquivo = (EditText)findViewById(R.id.txtNomeArquivo);
txtConteudoArquivo =
(EditText)findViewById(R.id.txtConteudoArquivo);
if(edit){
String[] partes = path.split("/");
String arquivo = partes[partes.length-1];
txtNomeArquivo.setText(arquivo);
txtPath.setText(path.replace(arquivo,""));
txtConteudoArquivo.setText(lerArquivo(path));
}else{
txtPath.setText(path);
}
}
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
...e os eventos dos cliques dos botões, extremamente simples. Apenas preste
atenção ao evento que cria o arquivo de texto onde chamamos o método
createNewFile (somente se o arquivo não existir, o que sabemos a partir da
chamada de file.exists()) a partir de um objeto do tipo File e depois usamos
uma série de classes da biblioteca java.io para colocar o texto dentro do
arquivo (FileOutputStream e OutputStreamWriter basicamente).
Código 95: disponível em luiztools.com.br/livro-android-fontes
E o que falta agora? Bom, ainda temos de colocar a opção de excluir pastas e
arquivos certos? Esse tipo de opção geralmente costuma ficar associada à
ação de pressionar um item da lista durante algum tempo para exibição de
opções adicionais, em um menu contextual. A criação de menus contextuais
foi mostrada anteriormente na seção de containers, então vamos repassar
rapidamente os passos necessários.
O primeiro passo, considerando que será um menu com opções estáticas, é
criar o arquivo XML de menu na pasta res/menu, que eu vou chamar de
menu_context.xml e colocar apenas dois itens: “Editar Arquivo” e “Excluir
Arquivo”, conforme mostra o XML de exemplo abaixo:
Código 97: disponível em luiztools.com.br/livro-android-fontes
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
if (v.getId() == R.id.lstArvore) {
getMenuInflater().inflate(R.menu.menu_context, menu);
}
}
Para que este método seja carregado quando um item da nossa lista for
pressionado durante alguns instantes (clique longo), devemos registrar esse
menu contextual para nossa ListView, dentro do método onCreate da
MainActivity:
Código 99: disponível em luiztools.com.br/livro-android-fontes
registerForContextMenu(lstArvore);
atualizarArvore();
}
...e para lidar com o evento gerado pelos itens do menu contextual devemos
sobrescrever o método onContextItemSelected, conforme a imagem na
próxima página. O resultado é que, quando realizarmos um clique longo
sobre algum item da lista, aparecerá um menu contextual com duas opções:
caso escolha Editar, você será direcionado para a tela de Edição de Arquivo,
caso escolha Excluir será exibido um dialog de confirmação, e caso opte por
OK o arquivo/pasta será excluído usando o método delete presenta na classe
File, que neste caso pode apontar tanto para um arquivo quanto para um
diretório. Em caso da exclusão a lista será atualizada devido ao evento
onWindowsFocusChanged que programamos anteriormente que será ativado
quando o foco sair do dialog e voltar à ListView.
Atenção: o método delete() somente exclui arquivos e pastas vazias. Caso
deseje excluir uma pasta com conteúdo, deverá excluir seu conteúdo
primeiro.
Visualmente esse menu contextual deve parecer com a imagem a seguir.
Existem diversas melhorias que poderíamos fazer para tornar este
gerenciador de arquivos mais completos. Aplicando a mesma técnica de itens
personalizados que vimos no tópico sobre ListView na seção de containers
podíamos colocar ícones de pastas e arquivos ao lado esquerdo do nome dos
mesmos. Talvez poderíamos colocar um ícone de um lápis ao lado direito dos
arquivos de texto, assinalando que estes são editáveis. Também poderíamos
programar a visualização de arquivos de imagem, apenas exibindo-os em
uma ImageView em outra activity. As possibilidades são inúmeras e acredito
que você tenha conseguido pegar a ideia de como prosseguir.
Apenas recapitulando os métodos da classe File que usamos neste exemplo:
● createNewFile: cria um novo arquivo com o caminho/nome
especificado;
● mkdir e mkdirs: cria a(s) pasta(s) no caminho especificado;
● delete: exclui o arquivo ou pasta (apenas vazias);
● list: retorna uma coleção de Strings contendo o “conteúdo” de uma
pasta;
Código 100: disponível em luiztools.com.br/livro-android-fontes
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
int id = item.getItemId();
if(id == R.id.menu_ctx_editar){
Intent intent = new Intent(MainActivity.this, FormActivity.class);
intent.putExtra("path", path);
intent.putExtra("edit", true);
startActivity(intent);
return true;
}
else if(id == R.id.menu_ctx_excluir){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Excluir")
.setMessage("Tem certeza que deseja excluir " + itemSelecionado
+ "?")
.setPositiveButton("Sim", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which) {
if(new File(path).delete()){
Toast.makeText(getBaseContext(), itemSelecionado + "
excluído com sucesso!", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getBaseContext(), "Não foi possível
excluir " + itemSelecionado + "!", Toast.LENGTH_LONG).show();
}
}
})
.create()
.show();
return true;
}
return super.onContextItemSelected(item);
}
Banco de Dados
Em Android, o banco de dados local que é utilizado é o SQLite, assim como
no iOS da Apple e diversas outras plataformas móveis e embarcadas. Quando
falamos de banco de dados móvel temos que ter em mente que o intuito não é
ter cópias de bancos de dados empresas rodando na palma de sua mão.
Bancos de dados de apps corporativos geralmente armazenam informações de
apoio ao sistema central, geralmente um ERP ou um CRM, e não são uma
cópia dos originais. Vamos dizer que eles servem mais como cache local para
uso offline do app, e não substituem o uso do sistema tradicional.
Com isso em mente, você notará e entenderá melhor que as limitações
técnicas de um banco de dados móvel não existem por incompetência técnica,
mas por limitação de hardware e por uma questão de design correto de
aplicações móveis. No âmbito de apps corporativos considere sempre o seu
device como uma extensão ao seu computador de trabalho, e não um
substituto definitivo ao mesmo.
SQLite
SQLite é uma biblioteca em linguagem C que implementa um banco de
dados SQL embutido. Ela foi criada e é mantida pela Apache Foundation e
programas que usem a biblioteca SQLite podem ter acesso a banco de dados
SQL sem executar um processo SGBD separado, mas também sem a robustez
dos bancos tradicionais, servindo como um excelente repositório móvel de
dados.
SQLite não é uma biblioteca cliente usada para conectar com um grande
servidor de banco de dados, mas sim uma biblioteca do próprio servidor, se é
que podemos chamá-lo assim. A biblioteca SQLite lê e escreve diretamente
para e a partir do arquivo do banco de dados no disco, com a extensão .db.
O uso do SQLite é recomendado onde a simplicidade da administração,
implementação e manutenção são mais importantes que incontáveis recursos
que SGBDs mais voltados para aplicações complexas possivelmente
implementam. As situações onde a simplicidade é a melhor escolha são muito
mais freqüentes do que pode-se imaginar.
Exemplos de uso do SQLite são:
● Sites com menos de cem mil requisições por dia
● Dispositivos e sistemas embarcados
● Aplicações desktop
● Ferramentas estatísticas e de análise
● Aprendizado de banco de dados
● Implementação de novas extensões de SQL
Não se recomenda o uso do SQLite para sites com:
● Muitos acessos
● Grande quantidades de dados (talvez maior que algumas dúzias de
gigabytes)
● Sistemas com grande concorrência
● Aplicações cliente/servidor
O SQLite:
● É Software Livre/domínio público e multiplataforma
● É um mecanismo de armazenamento seguro com transações ACID
● Não necessita de instalação, configuração ou administração
● Implementa a maioria da especificação SQL92
● Permite guardar o banco de dados em um único arquivo
● Suporta bases de dados abaixo de 2 terabytes
● Não tem dependências externas
Vale salientar também que muitos recurso tradicionalmente existentes em
SGBDs são inexistentes ou extremamente limitados no SQLite e entre eles
podemos citar:
● Afinidade por Tipos (Tipagem fraca): SQLite possui tipagem fraca, o
que permite retornar e escrever dados em formatos diferentes do que
foi proposto na especificação da tabela. Ele também trabalha com
pouquíssimos tipos como text (texto em geral), integer (inteiros), real
(ponto flutuante) e blob (binário).
● Alocação dinâmica: não precisamos definir o tamanho de cada coluna
da tabela, o SQLite varia o tamanho conforme a necessidade.
● Integridade Referencial: chaves estrangeiras até podem ser criadas,
mas não são respeitadas da maneira como esperamos.
● Transactions, Triggers e JOINs: extremamente limitados, não
recomenda-se o seu uso
● Stored Procedures e Functions: inexistente
Para saber mais sobre o SQLite e suas limitações, consulte o site oficial:
http://www.sqlite.org
Criando um Banco
Para se criar um banco de dados SQLite para o seu app (cada app tem o seu
próprio banco, que é armazenado no Internal Storage, dentro da pasta do
próprio app), você deve criar uma classe que extende SQLiteOpenHelper,
geralmente chamada de DbHelper. O DbHelper é responsável pela criação e
atualização do banco de dados, que nada mais é do que um conjunto de
tabelas (entenda que você não precisa dar um CREATE DATABASE ou algo
parecido) como mostrado na classe de exemplo a seguir, que criará um banco
com apenas uma tabela: Cliente, com ID autoincremental, nome, data de
nascimento, uma coluna indicando se ele é um cliente VIP, estado e cidade e
o sexo do cliente.
Note como temos de usar a criatividade uma vez que temos poucos tipos de
dados à disposição. Minha data de nascimento será text, no formato dd-mm-
yyyy, enquanto que a coluna VIP será um integer, com 0 ou 1 (sim ou não,
em representação binária). O sexo é text também, e conterá ‘m’ (masculino)
ou ‘f’ (feminino). Para finalizar, a sintaxe SQL dispensa uso de maiúsculas e
minúsculas em seus comandos, então descreva os comandos como preferir.
Código 101: disponível em luiztools.com.br/livro-android-fontes
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE Clientes(id integer primary key
autoincrement," +
"nome text not null, dataNascimento text not null," +
"vip integer not null, uf text not null, cidade text not null," +
"sexo text not null);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
}
}
Usando o banco
Com a classe DbHelper, o próximo passo é criar a classe que irá executar
nossos comandos e consultas no banco de dados, que chamamos de
DbAdapter, conforme mostrado na imagem a seguir. Esta classe conterá os
métodos de abrir conexão com o banco de dados e envio de comandos e
consultas.
Na hora de abrir a conexão devemos escolher se queremos conectar no banco
em modo leitura ou em modo escrita, conforme utilizado no exemplo. Os
efeitos dos dois tipos de conexão são óbvios: você só pode dar comandos de
alteração de dados (INSERT, UPDATE e DELETE) se possuir uma conexão
com permissão de escrita (método getWritableDatabase), mas usar sempre
essa forma de conexão pode travar o seu banco de dados para uso por outros
processos da sua aplicação. Se você tiver certeza de que o banco não terá
qualquer tipo de acesso concorrente (que nem mesmo é encorajado com
SQLite) não terá muito o que se preocupar.
Outro método que vale salientar é o executarConsultaSQL que envia um
comando SELECT pro banco de dados e como retorna devolve um Cursor.
Um Cursor é um objeto que aponta para uma linha da tabela de retorno por
vez. Ou seja, se o retorno da consulta trouxer 10 linhas, o Cursor irá apontar
para uma de cada vez, devendo avançar após coletar os valores de cada
coluna de cada linha.
Mostrarei na sequência como manipular esse Cursor visando construir
objetos a partir dos dados.
Código 103: disponível em luiztools.com.br/livro-android-fontes
SQLiteDatabase db = null;
DbHelper dbHelper = null;
Essa é uma classe genérica de uso de banco de dados SQLite. Nela pretendo
ter apenas métodos que podem ser utilizados independente de regras de
negócio ou de entidades específicas de um app ou outro, aumentando seu
reuso. Métodos específicos de entidades e do negócio devem ser
implementados em outras classes, como a GerenciadorClientes.java que
exemplifico abaixo, que inicialmente tem apenas um método de
retornarClientes que usa a DbAdapter por trás como era de se esperar.
Código 104: disponível em luiztools.com.br/livro-android-fontes
while(cursor.moveToNext()){
int id = cursor.getInt(0);
String nome = cursor.getString(1);
String data = cursor.getString(2);
String sexo = cursor.getString(3);
String cidade = cursor.getString(4);
String uf = cursor.getString(5);
boolean vip = cursor.getInt(6) == 1 ? true : false;
Cliente cliente = new Cliente(id,nome,sexo,data,vip,cidade,uf);
clientes.add(cliente);
}
dba.fecharConexao();
return clientes;
}
}
Neste método eu crio um novo adapter e mando executar uma consulta por
todos os clientes do banco de dados, com todas as suas informações,
recebendo como retorno um cursor que aponta para a tabela de retorno, que
pode ou não conter dados. Caso a tabela esteja vazia este código nem mesmo
entrará no while uma vez que o método moveToNext tenta avançar para a
primeira linha do resultado e se não conseguir retornará false.
Entrando dentro do laço usamos os métodos getInt e getString para pegar os
valores já convertidos de cada coluna e salvando em variáveis locais que
serão utilizadas para criar um objeto Cliente e adicioná-lo à nossa List que
será retornada após todos clientes serem instanciados e a conexão for
encerrada.
Note que o valor inteiro passado aos métodos getInt e getString é a posição
da coluna nas linhas retornadas pela consulta, motivo pelo qual fizemos o
SELECT informando as colunas em uma ordem específica.
Este procedimento está longe de ser o mais simples para uso com banco de
dados mas também não é muito complicado. É trabalhoso eu diria, mas como
é algo recorrente e não muda muito se quisermos ter tabelas Pedidos, por
exemplo, é algo que logo você dominará.
Abaixo listo a classe Cliente que estou utilizando, que nada mais é do que um
“espelho” da tabela do banco de dados, o que chamamos de ‘entidade’ do
banco de dados.
Código 105: disponível em luiztools.com.br/livro-android-fontes
public class Cliente implements Serializable {
int id;
String nome;
String sexo;
String dataNascimento;
boolean vip;
String cidade;
String uf;
@Override
public String toString(){
return this.nome;
}
}
while(cursor.moveToNext()){
int id = cursor.getInt(0);
String nome = cursor.getString(1);
String data = cursor.getString(2);
String sexo = cursor.getString(3);
String cidade = cursor.getString(4);
String uf = cursor.getString(5);
boolean vip = cursor.getInt(6) == 1 ? true : false;
Cliente cliente = new Cliente(id,nome,sexo,data,vip,cidade,uf);
clientes.add(cliente);
}
dba.fecharConexao();
return clientes;
}
}
Outro exemplo de método que espera parâmetros para montar o SQL correto
a ser executado (que basicamente é o que muda entre os métodos) seria um
método para salvar um cliente no banco de dados, que poderia ser como esse,
que apenas recebe os parâmetros e monta o INSERT que é executado na
tabela correspondente.
Código 107: disponível em luiztools.com.br/livro-android-fontes
Note que o que realmente muda desta versão do método salvarCliente para a
anterior é o SQL construído, que caso o cliente passado por parâmetro possua
um ID, será um UPDATE ao invés de um INSERT. Com isso temos métodos
de busca, de retorno e de salvamento/atualização de clientes, faltando apenas
um de exclusão para incluir as operações elementares de sistemas de cadastro
(que vamos criar na sequência), os chamados CRUDs (Create, Retrieve,
Update e Delete, sigla comum entre os programadores para designar a
funcionalidade básica de gerenciamento de uma entidade do banco de dados
pelo sistema).
Código 109: disponível em luiztools.com.br/livro-android-fontes
Simples, não?! Claro, neste exemplo não estou considerando nenhuma regra
de negócio como verificar se este cliente PODE ser excluído, o que é bem
comum em sistemas comerciais.
E agora, usando as nossas classes DbHelper, DbAdapter, Cliente e
GerenciadorClientes, podemos criar um app de que tal criarmos um app de
‘Cadastro de Clientes’ para exercitar?
Exemplo: Cadastro de Clientes
Comece o novo projeto abrindo o Android Studio e indo em “Start a new
Android Project”, ou, se já estiver com o Android Studio aberto, apenas indo
no menu File > New Project.
Dê o nome de Cadastro de Clientes e avance com Next.
Escolha a opção “Phones e Tablets”, “Android 4.0.3” ou semelhante (o que
deve atingir mais de 97% dos smartphones do mundo) e avance novamente
com Next.
Escolha o template de Empty Activity e avance novamente com Next.
O XML dessa tela deve ter ficado assim, com o componente ListView
possuindo o id ‘listView’ mesmo:
Código 110: disponível em luiztools.com.br/livro-android-fontes
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.luizfduartejr.cadastrodeclientes.MainActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listView" />
</RelativeLayout>
Agora vamos programar para que este ListView seja carregado com todos os
clientes existentes em nosso banco de dados local. Para isso preciso que você
tenha implementado as classes que mostrei anteriormente neste tópico:
DbHelper, DbAdapter, Cliente e GerenciadorClientes, ficando com uma
estrutura de projeto como segue:
Assim, na classe MainActivity.java, mais precisamente no método onCreate
da Activity, vamos chamar nosso GerenciadorClientes para retornar todos os
clientes existentes no banco de dados e listá-los em nosso componente cujo id
é listView, como segue:
Código 111: disponível em luiztools.com.br/livro-android-fontes
ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView)findViewById(R.id.listView);
carregarListagem();
}
public void carregarListagem(){
List<Cliente> clientes = new
GerenciadorClientes(this).retornarClientes();
if(clientes.size() == 0){
Toast.makeText(this, "Nenhum cliente cadastrado!",
Toast.LENGTH_SHORT).show();
}
ArrayAdapter<Cliente> clientesAdapter =
new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
clientes);
listView.setAdapter(clientesAdapter);
}
}
Note que está implícito a necessidade de alguns imports para este código Java
funcionar. Basicamente o Android Studio irá te sugerindo estes imports
conforme você for digitando o nome das classes, basta seguir as dicas
pressionando ALT+SPACE e em seguida ENTER para confirmar o import
que ele sugeriu.
Note também que estou usando um ArrayAdapter de Cliente ao invés de
Strings. Isso fará com que quando o Android for renderizar a ListView na
tela do smartphone, ele irá usar o método toString() da classe Cliente para
imprimir algo para o usuário. Para que ele imprima o que desejamos
realmente (por padrão apareceria o nome da classe), temos de sobrescrever o
método toString() da classe Cliente, como abaixo (se você está usando a
mesma classe Cliente citada anteriormente, este trecho de código já está lá):
Código 112: disponível em luiztools.com.br/livro-android-fontes
@Override
public String toString(){
return this.nome;
}
Obviamente se a gente executar esse código agora, quando ainda nem mesmo
temos a tela de cadastro do cliente, ele irá exibir o Toast de “Nenhum cliente
cadastrado!”. Então vamos deixar este código quieto por enquanto e vamos
adicionar uma nova nova activity em nosso projeto!
Com o botão direito do mouse sobre o package onde estão todas as classes do
seu projeto, escolha New > Activity > Empty Activity e dê o nome de
CadastroActivity à essa aqui, em seguida Finish.
Isso irá criar tanto a classe Activity quanto o layout da mesma, pois deixamos
o checkbox “Generate Layout File” marcado.
Agora vá em res > layouts e abra o novo layout XML que acabou de
aparecer, com o nome de activity_cadastro.xml. Vamos posicionar nele os
componentes necessários para cadastrar o cliente do nosso sistema, que
possui os atributos id (que será gerado automaticamente pelo banco), nome,
data de nascimento, VIP (um booleano true/false), uf, cidade e sexo.
No exemplo acima usei um EditText com hint para os campos de nome, data
de nascimento e cidade, definindo para cada um o inputType correto.
Ressalto também a “jogada” com um LinearLayout envolvendo o EditText de
cidade e o Spinner de estados, que eu eu populei com um XML de Strings
estáticas. Segue o código inicial:
Código 113: disponível em luiztools.com.br/livro-android-fontes
tools:context="com.example.luizfduartejr.cadastrodeclientes.CadastroActivity"
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:hint="Nome do Cliente"
android:ems="10"
android:id="@+id/txtNome" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="date"
android:hint="Data de Nascimento"
android:ems="10"
android:id="@+id/txtDataNascimento"
android:layout_below="@+id/txtNome" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/localizacao"
android:layout_below="@id/txtDataNascimento"
android:orientation="horizontal">
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="7"
android:inputType="textPersonName"
android:hint="Cidade"
android:ems="10"
android:id="@+id/txtCidade" />
<Spinner
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="3"
android:id="@+id/spnUf"
android:entries="@array/estados"></Spinner>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sexo:"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/lblSexo"
android:layout_below="@id/localizacao"/>
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/grpSexo"
android:layout_toRightOf="@+id/lblSexo"
android:layout_below="@id/localizacao">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Masculino"
android:id="@+id/radMasculino"/>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Feminino"
android:id="@+id/radFeminino"/>
</RadioGroup>
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Cliente VIP"
android:id="@+id/chkVip"
android:layout_below="@id/grpSexo"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/botoes"
android:layout_below="@id/chkVip"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:text="Cancelar"
android:onClick="btnCancelarOnClick"
android:id="@+id/btnCancelar"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:text="Salvar"
android:onClick="btnSalvarOnClick"
android:id="@+id/btnSalvar"/>
</LinearLayout>
</RelativeLayout>
Cliente cliente;
EditText txtNome, txtDataNascimento, txtCidade;
Spinner spnUf;
RadioButton radMasculino;
RadioGroup grpSexo;
CheckBox chkVip;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cadastro);
}
}
Para o botão de Salvar, a única complicação adicional (já que ele também
deverá voltar à tela de listagem após o salvamento, é de ler as variáveis que
representam os componentes da tela e depois enviar estas informações ao
gerenciador de clientes, como segue.
Código 120: disponível em luiztools.com.br/livro-android-fontes
Com isso deixamos tudo preparado para a volta após um cadastro completo!
No entanto, ainda não dissemos como que o usuário vai ir para a tela de
cadastro. Para que isso seja possível, devemos programar o menu da nossa
tela de listagem, para que ali exista a opção de cadastrar um novo cliente.
O código a seguir deve ser colocado dentro da MainActivity, logo abaixo do
método onRestart que criamos anteriormente e basicamente fornece uma
opção de menu “Novo Cliente”, que quando selecionado apenas abre a tela de
cadastro.
Código 123: disponível em luiztools.com.br/livro-android-fontes
@Override
public boolean onCreateOptionsMenu(Menu menu){
menu.add("Novo Cliente");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
Intent intent = new Intent(MainActivity.this, CadastroActivity.class);
startActivity(intent);
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView)findViewById(R.id.listView);
carregarListagem();
listView.setOnItemLongClickListener(new
ListView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
E a edição como fica? Bem simples também, basta que a gente trabalhe o
listener de click normal sobre um item da lista, ao invés do click longo como
fizemos anteriormente. Antes disso, temos apenas de fazer uma pequena
alteração na classe Cliente, para que seja possível transferir objetos cliente de
uma tela para outra: implementando a interface Serializable. Se a sua classe
Cliente foi criada de maneira idêntica ao do código anteriormente mostrado,
ela já está implementando Serializable.
Código 125: disponível em luiztools.com.br/livro-android-fontes
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView)findViewById(R.id.listView);
carregarListagem();
listView.setOnItemClickListener(new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int
position, long id) {
Cliente cliente = (Cliente)listView.getItemAtPosition(position);
Intent intent = new Intent(MainActivity.this, CadastroActivity.class);
intent.putExtra("cliente", cliente);
startActivity(intent);
}
});
//o resto do código continua igual
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cadastro);
txtNome = (EditText)findViewById(R.id.txtNome);
txtCidade = (EditText)findViewById(R.id.txtCidade);
txtDataNascimento = (EditText)findViewById(R.id.txtDataNascimento);
spnUf = (Spinner)findViewById(R.id.spnUf);
radMasculino = (RadioButton)findViewById(R.id.radMasculino);
chkVip = (CheckBox)findViewById(R.id.chkVip);
grpSexo = (RadioGroup)findViewById(R.id.grpSexo);
spnUf.setSelection((((ArrayAdapter)spnUf.getAdapter()).getPosition(cliente.
if(cliente.sexo.equals("M"))
grpSexo.check(R.id.radMasculino);
else
grpSexo.check(R.id.radFeminino);
chkVip.setChecked(cliente.vip);
}
}
Note que salvo o objeto inteiro do cliente em uma variável da classe. Isso
porque vou usá-lo nos ajustes do botão Salvar, a seguir.
Código 128: disponível em luiztools.com.br/livro-android-fontes
{"ip":"8.8.8.8","country_code":"US","country_name":"United
States","region_code":"","region_name":"","city":"","zip_code":"","time_zone":"","latitud
Mas “o que isso tem a ver com acesso a bancos de dados remotos?”, você
deve estar se perguntando. O FreeGeoIP nada mais é do que uma base de
dados remota onde seus desenvolvedores criaram um webservice REST para
consulta de dados a partir de qualquer plataforma, ou seja, eles permitem
através da API que qualquer um possa acessar seu banco de dados, e é
exatamente isso que um desenvolvedor Android necessita fazer para integrar
de maneira prática e eficiente um banco de dados remoto ao seu app.
Exemplo: App com API
O primeiro passo é abrir nossa ferramenta, o Android Studio. Mande criar um
novo projeto do tipo Android Application e lhe dê o nome de LocationApp.
A versão de Android fica ao seu gosto, enquanto eu utilizei a versão 4.0 em
meus testes, oferecendo compatibilidade com toda a família IceCream
Sandwich e posteriores (JellyBean, KitKat, Marshmallow, etc).
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LocationActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/ip">
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="7"
android:text="177.155.44.231"
android:ems="10"
android:id="@+id/txtIP"
android:hint="Digite o IP"
android:inputType="number|text" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="Carregar"
android:id="@+id/btnCarregar"
android:onClick="btnCarregarOnClick" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Geolocalização"
android:textStyle="bold"
android:id="@+id/lblTitulo"
android:layout_below="@+id/ip" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="País: Brazil"
android:id="@+id/lblCountry"
android:layout_below="@+id/lblTitulo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Estado: Rio Grande do Sul"
android:id="@+id/lblRegion"
android:layout_below="@+id/lblCountry" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Cidade: Gravataí"
android:id="@+id/lblCity"
android:layout_below="@+id/lblRegion" />
</RelativeLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
txtIP = (EditText)findViewById(R.id.txtIP);
lblCountry = (TextView)findViewById(R.id.lblCountry);
lblRegion = (TextView)findViewById(R.id.lblRegion);
lblCity = (TextView)findViewById(R.id.lblCity);
}
}
try {
while ((line = r.readLine()) != null) {
total.append(line).append('\n');
}
}catch(Exception ex) {
ex.printStackTrace();
}
return total.toString();
}
try {
String ip = txtIP.getText().toString();
Localizacao localizacao = ClienteGeoIP.retornarLocalizacaoPorIp(ip);
lblRegion.setText("Estado: " + localizacao.getRegion());
lblCity.setText("Cidade: " + localizacao.getCity());
lblCountry.setText("País: " + localizacao.getCountry());
}
catch(Exception ex){
Toast.makeText(getBaseContext(), ex.getMessage(), Toast.LENGTH_LONG).show();
}
}
echo $json;
?>
{
"nome": "Luiz Fernando",
"idade": 28,
"profissao": "Professor",
"Cidade": "Gravataí"
}
Você deve estar pensando: mas isto não é uma API, afinal sempre retorna os
dados da mesma pessoa! De fato, por isso que é imprescindível outros
conhecimentos para que nosso exemplo de impressão JSON em PHP se torne
uma API de verdade. Em primeiro lugar é imprescindível que se capture as
informações passadas por parâmetro na requisição HTTP GET que será
realizada pelos apps que forem criados. Em PHP, podemos capturar as
variáveis da querystring (parte da URL precedida por um ‘?’) usando a
variável pré-definida $_GET podemos passar o nome da variável da URL que
desejamos ler, para processar nosso script PHP de acordo. Imagine que temos
uma API de consulta de clientes com a seguinte URL:
Http://localhost:8080/index.php?nome=Luiz
Em nossa página busca.php precisamos ter o seguinte código para verificar o
nome do cliente que estamos buscando:
Código 139: disponível em luiztools.com.br/livro-android-fontes
$nome = $_GET["nome"];
Com base nesse nome podemos consultar em uma base MySQL (muito
utilizada em conjunto com PHP) por clientes semelhantes e retornarmos
todos no formato JSON, para serem listados depois em nossos apps.
Comandos comuns para realizar esta operação incluem os listados no site
oficial: http://php.net/manual/pt_BR/ref.mysql.php
Obviamente esta é uma das maneiras possíveis de se criar uma simples API
JSON com PHP. Existem diversos frameworks que facilitam enormemente
esta tarefa e que a tornam também mais padronizada de acordo com padrões
de mercado. Não estamos lidando aqui com questões de segurança, por
exemplo, ou com outros pormenores da linguagem, que cabe ao programador
averiguar visando uma API realmente funcional que possa ser implantada em
ambiente de produção.
API JSON COM ASP.NET
Nota: o foco deste livro não é ASP.NET, então serão dadas apenas
orientações básicas a respeito de como criar uma API com esta plataforma.
Busque os treinamentos oficiais da Microsoft para exemplos mais detalhados.
Existem atualmente duas formas largamente utilizadas para criação de APIs
JSON em ASP.NET: com WCF (Windows Communication Foundation) ou
com Web API (parte do ASP.NET MVC). Assim como no PHP, existem
outras maneiras de realizar esta tarefa, mas as citadas anteriormente são as
mais largamente utilizadas. Usaremos a primeira opção neste exemplo.
Para criar uma API JSON com ASP.NET iremos precisar da IDE Microsoft
Visual Studio, que inclusive já vem com o servidor web IIS Express. Nele
temos a opção criar novo projeto, onde escolheremos o template WCF
Service Application, utilizado para criação de webservices modernos com
tecnologia Microsoft.
namespace Percutz.Api
{
[ServiceContract]
public interface ITurmaService
{
[OperationContract]
[WebGet(UriTemplate = "/EmAndamento", ResponseFormat =
WebMessageFormat.Json)]
List<TurmaDTO> RetornarTurmasEmAndamento();
[OperationContract]
[WebGet(UriTemplate = "/EmFormacao", ResponseFormat =
WebMessageFormat.Json)]
List<TurmaDTO> RetornarTurmasEmFormacao();
[OperationContract]
[WebGet(UriTemplate = "/Turma/{id}", ResponseFormat =
WebMessageFormat.Json)]
TurmaDTO RetornarTurma(string id);
}
}
Neste exemplo nossa API Possui três operações no seu contrato (assinaladas
com a anotação [OperationContract]), sendo a primeira para retornar as
turmas em andamento na escola, as turmas em formação ou retornar uma
turma através de um ID específico passado por parâmetro. A segunda
anotação logo abaixo de [OperationContract] diz respeito ao método HTTP
que deve ser utilizado para invocar este método (GET, nestes exemplos), o
path da URL (afinal, as chamadas aos métodos da API são com base na URL)
e o formato da resposta (JSON obviamente).
Como em qualquer interface teremos apenas a assinatura dos referidos
métodos que retornam objeto(s) do tipo TurmaDTO, o qual segue abaixo para
visualização (esta classe não aparece na imagem do projeto pois pertence à
outro projeto da mesma solução).
Código 141: disponível em luiztools.com.br/livro-android-fontes
namespace Percutz.Lib.DTO
{
[DataContract]
public class TurmaDTO
{
[DataMember]
public string Filial { get; set; }
[DataMember]
public string Nivel { get; set; }
[DataMember]
public short DiaSemana { get; set; }
[DataMember]
public short HoraInicio { get; set; }
[DataMember]
public short HoraFim { get; set; }
public TurmaDTO() { }
<%@ ServiceHost
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
Language="C#" Debug="true"
Service="Percutz.Api.TurmaService"
CodeBehind="TurmaService.svc.cs" %>
namespace Percutz.Api
{
public class TurmaService : ITurmaService
{
public List<TurmaDTO> RetornarTurmasEmAndamento()
{
return
ControladorTurma.RetornarTurmasEmAndamento(DateTime.Now.Year);
}
[{"DiaSemana":5,"Filial":"Cachoeirinha","HoraFim":1650,"HoraInicio":1415,"Nivel":"In
1"}]