Documente Academic
Documente Profesional
Documente Cultură
Corpo Editorial
Editor Geral
Atendimento ao Leitor
A DevMedia conta com um departamento exclusivo
para o atendimento ao leitor. Se voc tiver algum problema no recebimento do seu exemplar ou precisar de
algum esclarecimento sobre assinaturas, exemplares
anteriores, endereo de bancas de jornal, entre outros,
entre em contato com:
Sub Editores
Capa
Antonio Xavier
webdesigner@devmedia.com.br
Kaline Dolabella
Gerente de Marketing e Atendimento
kalined@terra.com.br
(21) 3382-5038
Na Web
Publicidade
Guinther Pauli
Luciano Pimenta
www.devmedia.com.br/webmobile/pagina.asp
Reviso
Kaline Dolabella
publicidade@devmedia.com.br
Diagramao
Para fechar parcerias ou aes especficas de marketing com a DevMedia, entre em contato com:
Distribuio
Kaline Dolabella
publicidade@devmedia.com.br
kalined@terra.com.br
editor@portalwebmobile.com.br
NDICE
NDICE
6 - Depurando JavaScript com NetBeans
Melissa Villela
Ricardo Ogliari
entre em contato com os editores, informando o
ttulo e mini-resumo do tema que voc gostaria
de publicar:
editorwebmobile@devmedia.com.br
sua sugesto!
Se voc estiver interessado em publicar um artigo
Rogrio Arajo
Feedback
eu
d i o
A Web Mobile tem que ser feita aoD seu feedback sobre esta edio!
seu gosto.
Para isso, precisamos saber o que voc, leitor, acha da revista!
A .NET Magazine tem que ser feita ao seu
D seu voto sobre este artigo, atravs do link:
gosto. Para isso, precisamos saber o que
www.devmedia.com.br/webmobile/feedback acha da revista!
voc, leitor,
D
s
sobre e
s
Apoio
e
ta
Assinatura
Aplicao Completa Utilizando Hibernate - Aula 2 - Definindo as Entidades: Nesta aula abordamos a
criao das entidades referentes s tabelas criadas no banco de dados. Este procedimento um dos mais
importantes para entender como proceder no restante do desenvolvimento. Criamos tambm algumas
propriedades adicionais para resolver possveis problemas de design em uma aplicao normal.
Vdeos
Aplicao Completa Utilizando Hibernate - Aula 3 - Trabalhando com Entidades: Nesta aula
continuamos criando as entidades relacionadas com o banco de dados. Veremos como criar as entidades e
fazer os relacionamentos UM-PARA-MUITOS e MUITOS-PARA-UM.
Aulas de .NET:
Mobilidade com SmartPhone Parte I e II: Veja nesta vdeo aula como criar projetos mobile para
SmartPhone no Visual Studio 2005.
Feedback
eu
edio
ta
D
s
II) Com Crditos DevMedia, voc pode comprar uma edio online avulsa ou pode comprar somente os
*artigos* que voc desejar voc pode at mesmo misturar artigos de vrias edies, de forma 100%
online! Para saber mais sobre Crditos DevMedia, acesse www.devmedia.com.br/creditos; Para visitar a
biblioteca digital de artigos da WebMobile, visite http://www.devmedia.com.br/assgold/listmag.asp?site=5
A WebMobile tem que ser feita ao seu gosto. Para isso, precisamos saber o que voc, leitor, acha da revista!
D seu voto sobre esta edio, artigo por artigo, atravs do link:
www.devmedia.com.br/webmobile/feedback
Para votar, voc vai precisar do cdigo de banca desta edio, que : camaleao
Depurando JavaScript
com NetBeans
Como utilizar um ambiente de
desenvolvimento web integrando
diversas tecnologias
Melissa Villela
melissa@globalcode.com.br
Desenvolvendo a aplicao
Neste artigo, desenvolveremos uma aplicao para cadastrar
clientes. Como regras de negcio: (1) foi estabelecido que o
campo nome obrigatrio; (2) para o campo estado civil, se
selecionado a opo casado, a aplicao deve mostrar dinamicamente um campo para preenchimento do nome do cnjuge,
que tambm ser obrigatrio.
Java W eb
Criando um script
Figura 6. Nomeando o JSP
Funo carregaValorEstadoCivil
Esta funo responsvel por carregar a varivel com o texto
do estado civil selecionado pelo usurio. Ser utilizada por
outras funes que precisam conhecer a opo do estado civil
selecionado pelo usurio.
Java W eb
Funo escondeConjuge
Esta funo ser utilizada em dois momentos, ao carregar o
arquivo e quando o valor selecionado no combo de estado civil
for diferente da opo casado.
Demarcamos no documento html toda a linha da tabela que
contm as clulas com informaes sobre o cnjuge, utilizando o
id linhaConjuge (<tr id=linhaConjuge>). Com esta demarcao
podemos facilmente controlar o desaparecimento da linha na
pgina conforme mostra o trecho de cdigo da Listagem 3.
Listagem 3. Funo escondeConjuge
1. function escondeConjuge(){
2.
var linhaConjuge = document.getElementById(linhaConjuge);
3.
linhaConjuge.style.display = none;
4. }
Na linha 2 estamos recuperando o elemento com o id linhaConjuge e na linha 3 com o uso de CSS estamos dizendo que
o elemento no deve ser exibido.
Funo carregaConjuge
Esta funo responsvel por mostrar o elemento demarcado com o id linhaConjuge quando o usurio selecionar a
Funo valida
Por ltimo temos a funo valida, que responsvel por verificar se os campos obrigatrios foram preenchidos antes do envio
dos dados do cadastro para o servidor (ver Listagem 3).
Na linha 3 estamos recuperando o elemento com o id txtNome, caso ele seja nulo ou vazio mostramos na linha 5 uma
mensagem ao usurio dizendo que o campo nome obrigatrio
e na linha 7 estamos saindo da funo, uma vez que os dados
esto invlidos.
Se o campo nome foi preenchido corretamente, a linha 10
atualiza o valor selecionado no combo de estado civil e caso o
combo estiver com a opo casado selecionada, validaremos se
o campo com o nome do cnjuge foi corretamente preenchido.
<body onload=escondeConjuge();>
Depurando o script
Para depurar o arquivo, o NetBeans solicita autorizao para
instalao de um plug-in no browser selecionado ao executar a
opo de debug pela primeira vez (para este artigo usaremos
o Firefox e o plug-in que ser instalado o Firebug).
Para depurar a aplicao, importante selecionarmos um
10
getElementById(selEstCivil).options[indEstadoCivil].text;
}
</script>
<head>
<meta http-equiv=Content-Type content=text/html;
charset=UTF-8>
<title>Modelo depurao JavaScript</title>
</head>
<body onload=escondeConjuge();>
<form onsubmit=return valida();>
<table border=1>
<thead>
<tr>
<th colspan=2>Cadastro de cliente</th>
</tr>
</thead>
<tbody>
<tr>
<td>Nome</td>
<td><input type=text id=txtNome/></td>
</tr>
<tr>
<td>Estado civil</td>
<td>
<select id=selEstCivil
onchange=carregaConjuge();>
<option>Solteiro</option>
<option>Casado</option>
<option>Divorciado</option>
<option>Vivo</option>
<option>Outros</option>
</select>
</td>
</tr>
<tr id=linhaConjuge>
<td><label id=lblConjuge>Nome do
conjuge</label></td>
<td><input type=text id=txtConjuge
value= /></td>
</tr>
<tr>
<td colspan=2><input type=submit
value=Gravar /></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
Java W eb
ponto de parada (breakpoint), para isto basta clicar com o mouse na barra lateral do cdigo e demarcar um ponto de parada.
A linha demarcada ser nosso ponto de parada e ficar com o
fundo rosa para distinguir das demais linhas, veja a Figura 9,
onde selecionei o ponto de parada na linha da funo valida.
Concluso
Quando vamos construir uma aplicao, normalmente utilizamos mais do que um ambiente de desenvolvimento devido
necessidade de trabalharmos com mais de uma tecnologia.
Os ambientes de desenvolvimento integrados esto cada vez
mais poderosos e completos, e por isso vale a pena expandir
nossos conhecimentos estudando e abrindo espao para outros ambientes que nem sempre so aqueles que utilizamos
no dia a dia.
O NetBeans tem evoludo muito rpido na integrao de
diversas tecnologias, como JavaScript, JRuby, Groovy, entre
outros e pode tornar-se uma boa alternativa para o desenvolvimento da sua aplicao.
Links teis
Link para download do JDK
http://java.sun.com/javase/downloads/index.jsp
11
Augusto Marinho
augusto@claimant.com.br
Analista de Sistemas formado pela UNESA atuando h trs anos com projetos de desenvolvimento de software utilizando a tecnologia Java para
aplicaes Web. Atualmente, atua como consultor Java numa grande empresa de telecomunicaes e; com consultoria em treinamentos Java para
Claimant, que o seu mais novo desafio profissional.
12
Java W eb
Nota do DevMan 1
Java Virtual Machine JVM (Mquina Virtual Java)
Uma Mquina Virtual Java (Java Virtual Machine JVM) um conjunto de programas de software e estrutura de dados que usa um modelo de mquina virtual para a
execuo de outros programas computacionais e scripts. O modelo usado por uma JVM
aceita uma forma de linguagem intermediria de computador comumente referenciada como bytecode Java. Esta linguagem representa conceitualmente o conjunto de
instrues de uma arquitetura orientada a pilha. Em 2006 foi estimado que existe um
nmero em torno de 4 bilhes de dispositivos de JVM habilitados em todo o mundo.
As Mquinas Virtuais Java operam sobre bytecode Java, que normalmente, mas
no necessariamente, gerado a partir de cdigo Java; uma JVM pode tambm ser
usada para implementar linguagens de programao diferentes de Java. Por exemplo, cdigo fonte em Adapode ser compilado para bytecode Java, que poder ento
ser executado por uma JVM.
A JVM um componente crucial da Plataforma Java. Visto que JVMs esto disponveis para muitas plataformas de hardware e software, Java pode ser tanto middlewaree uma plataforma da a marca: escreve uma vez, roda em qualquer lugar
(write once, run anywhere). O uso do mesmo bytecode para todas as plataformas
permite que a linguagem seja descrita como compila uma vez, roda em qualquer
lugar (compile once, run anywhere).
A JVM distribuda junto com um conjunto de bibliotecas de classes padres que
implementam a API (Application Programming Interface) Java. A mquina virtual e
a API tm que ser consistentes entre si e so, portanto, agrupadas em conjunto como
o famoso Java Runtime Environment- JRE.
A arquitetura de JVM permite um controle muito fino sobre as aes liberadas para
o cdigo que est rodando na VM. Isso permite a execuo de cdigo confivel de
fontes remotas, um modelo usado pelos applets. Osappletsrodam dentro de uma
VM incorporada ao browser do usurio, executando cdigo baixado de um servidorHTTPremoto. O cdigo remoto roda em umasandbox, que protege o usurio de
cdigos maliciosos. O autor doappletpode aplicar um certificado para assinar digitalmente o applet como seguro dando a ele permisso de sair dosandboxe acessar
,
livremente a mquina onde est rodando.
Os programas que rodam sobre uma JVM devem ser compilados em um formato
binrio portvel padronizado, que tipicamente vem na forma de arquivos .class. Um
programa pode ser composto de muitas classes em diferentes arquivos. Para facilitar
a distribuio de programas maiores, os diversos arquivos de classes podem ser empacotados juntos em um arquivo .jar (acrnimo para Java ARchive).
Subdivises
Gerao Jovem
Gerao Estvel
Quadros, representados na Figura 1 por q1, q2, q3 e q4.
No foram encontrados subdivises na literatura e fontes de consulta.
13
Para ficar mais claro, descrito abaixo a importncia e utilizao de cada regio de memria criada pela JVM.
Gerao Jovem
a regio de memria alocada dentro do Heap destinada a alocar
os objetos recentemente instanciados na memria pela JVM.
Est regio ainda subdividida em:
o den
Espao de memria onde so alocados os objetos recentemente instanciados pela JVM. Os objetos s permanecem nesta
regio at serem promovidos para as reas de troca (Origem e
Destino) e, conseqentemente, irem para Gerao Estvel.
o Origem e Destino
Esta a Regio de memria onde so alocados os objetos
que na passagem do Garbage Collection (coletor de lixo)
so trocados de Regio atravs de algoritmos de Cpia. A
combinao da Regio Origem e Destino forma a chamada
Regio dos Sobreviventes.
Gerao Estvel
Est regio armazena os objetos que sobreviveram a vrias
coletas na Gerao Jovem, por isso so chamadas de Gerao
Estvel. O algoritmo utilizado pela Garbage Collection fica responsvel por definir quando os objetos devem ser promovidos
a esta regio do Heap.
Gerao Permanente
Est regio responsvel por armazenar processos que no
estejam relacionados instncia de Objetos no Heap. A Gerao Permanente fica alocada fora do Heap (Gerao Jovem
+ Gerao Estvel), e destinada a armazenar o Class Loader
(responsvel por carregar as classes compiladas bytecodes
para a memria), cdigos compilados (chamada de rea de
mtodos) e por armazenar classes geradas dinamicamente,
como pginas JSP e Objetos JNI (Java Native Interface).
Pilha
A pilha mais uma regio criada pela JVM definida fora do
Heap. Esta regio responsvel por armazenar constantes,
valores de variveis locais; tambm tem a funo de preparar
parmetros a serem passados a mtodos e receber seus resultados. A forma de gerenciamento de memria utilizado pelo
JVM para esta regio a alocao Esttica.
Atravs da Figura 2 so ilustradas as divises da Pilha na
Memria
Para cada Thread em execuo criada uma Pilha respectivamente com seus quadros, e por sua vez os quadros com
seu array de variveis locais e sua pilha de operandos. Os
dados de um quadro e outro no so compartilhados entre
os Threads. Por este motivo que para cada Thread criada sua
prpria pilha.
14
Java W eb
15
Nota 1. Observao
importante lembrar que os exemplos apresentados so para ambiente Solaris, Linux ou
similares, mas isso no que dizer que seja impeditivo implantar este ambiente em Windows.
Para que isso seja possvel, o Shell script setenv.sh deve ser substituindo em ambiente Windows
pelo Batch setenv.bat.
As variveis de ambiente utilizadas tanto em Windows quando em Solarios\Linux so as
mesmas, deve apenas ser levado em considerao a estrutura de formao e definio de
variveis de ambiente do Apache Tomcat para Windows.
Para maiores detalhes de como estruturar estes arquivos para ambiente Windows acesse:
http://tomcat.apache.org/tomcat-6.0-doc/index.html
Estudo de Caso
O exemplo criado para demonstrao dos parmetros
disponibilizados pela JVM simula um ambiente com alto
consumo de memria. Para simular este ambiente, foi desenvolvida uma aplicao que captura um ArrayList contendo
um milho de objetos Cliente serializados para dentro do
arquivo webmobile1.txt.
Quando a pgina index.jsp lida pelo servidor, este arquivo
JSP fica responsvel por ler o arquivo serializado webmobile1.
txt e inserir cada um dos objetos Cliente na sesso do servidor atravs do objeto implcito session do JSP.
O objeto Cliente um Bean, ou seja, uma classe que apenas possui atributos e mtodos gets e sets. Na Listagem 3
descrita a estrutura do Bean Cliente.
Listagem 3. Cdigo referente ao Bean Cliente
A classe SerializaObjetos responsvel pela leitura do arquivo serializado webmobile1.txt, capturar o ArrayList de objetos
Cliente atravs do mtodo getDadosSerializadosComArray(). Para
ter acesso ao ArrayList capturado do arquivo, deve ser feito uso
do mtodo getLista().
Para melhor visualizar a estrutura da classe, na Listagem 4
apresentado o cdigo-fonte da classe SerializaObjetos.
Na Figura 4 apresentada a estrutura do projeto da aplicao
de exemplo no Eclipse.
16
Java W eb
Agora, no passo atual, consideremos que o Deploy da aplicao de exemplo webmobile1.war j est no ar, mas ainda no
foi executada por ningum.
Quando acessarmos pela primeira vez o contexto webmobile1
no endereo http://localhost:8080/webmobile1 perceba na Figura
6 a surpresa que teremos.
A aplicao est com erro! O que houve? O que programei
errado?
Estas devem ser umas das muitas indagaes quando nos
esquecemos de dimensionar o volume de informaes da nossa
aplicao com as possibilidades de gerenciamento da JVM no
ambiente de produo.
A exceo lanada foi um OutOfMemoryError (Heap Space). O
que podemos concluir com isso? Que a nossa aplicao uma
aplicao bomba?
No exatamente, o grande problema identificado pela JVM
foi a falta de espao no Heap para armazenar um milho de
objeto Cliente em uma JVM cliente default com 64MB de espao
definido com o mximo a ser utilizado. Com este volume de
informaes nunca ser possvel acessar a aplicao de exemplo
e apresentar o contedo to esperado.
Agora como podemos viabilizar o acesso a aplicao se a JVM
identificou o meu Sun Netra 105 como cliente? Mas eu queria
17
18
-Xss128k
A opo Xss define o tamanho que cada quadro da pilha
dever assumir como sendo 128 KB. A pilha com um tamanho de quadro maior evita que ocorra StackOverFlowError em
aplicaes de vida longa.
importante ter um certo cuidado com a configurao deste
parmetro, pois em um ambiente que a JVM trabalha com um
tamanho de quadro muito grande, a aplicao pode ter perda
de desempenho, e este no nosso objetivo.
-XX:PermSize=50m
O parmetro XX:PermSize define o valor mnimo reservado
para Gerao Permanente, que ser de 50 MB. Lembrando que
este espao no est alocado dentro do nosso Heap definido
com 200MB.
Em aplicaes de vida longa, importante configurar esta
regio, pois as coletas feitas pelo Garbage Collection nesta Regio
so mais raras.
Uma JVM configurada com uma Gerao Permanente muito
grande pode gerar perda de desempenho, e mais uma vez este
no nosso objetivo.
-XX:MaxPermSize=50m
O parmetro XX:MaxPermSize define o tamanho mximo
reservado na memria para a Gerao Permanente que tambm
ser de 50 MB. Mas uma vez, definimos o tamanho inicial
igual ao tamanho mximo. Isto se deve ao mesmo fato da
configurao do tamanho do Heap.
Com a passagem do Garbage Collection nesta regio de memria, a JVM evita ter o trabalho de recalcular o tamanho mnimo
que dever assumir aps a coleta.
-Dcom.sun.management.jmxremote=true
atravs deste parmetro que a aplicao Lambda Probe consegue obter informaes sobre a instncia da JVM responsvel
pelo Apache Tomcat. Este parmetro habilita a monitorao
remota da JVM por agentes JMX.
A Listagem 5 descreve como ficaria o cdigo do nosso arquivo Shell script setenv.sh.
Listagem 5. Cdigo resultante do Sheel script stenv.sh
#!/bin/bash
JAVA_OPTS=-d64 server Xms200m Xmx200m Xss128k
XX:PermSize=50m XX:MaxPermSize=50m
-Dcom.sun.management.jmxremote=true
Export JAVA_OPTS
Java W eb
19
20
Java W eb
Concluses
Links
19.02.08
18:15:13
magazine
Engenharia de Software
Saiba seu significado e para que serve
Edio Especial
Requisitos
Especial
Projeto
Processos
21
Criando um aplicativo
LBS para consulta
de pontos tursticos
em cidades
Receba avisos ao se aproximar de
pontos tursticos atravs de um
aplicativo Java ME com acesso a dados
de geolocalizao
De que se trata o artigo
O artigo apresenta o desenvolvimento de um aplicativo LBS (Location Based
Service) direcionado para telefones celulares. Estes aparelhos acessam um servidor web com dados de pontos tursticos de uma cidade e, atravs destas informaes e da recuperao de dados de geolocalizao no dispositivo mvel, avisam
o usurio quando este se aproximar de um dos pontos cadastrados no banco de
dados do servidor web. A partir deste aviso, o usurio pode visualizar uma imagem
ou requisitar mais informaes sobre o referido ponto. No segundo artigo desta
srie, o usurio poder cadastrar pontos tursticos apenas capturando uma foto do
local e enviando ao servidor web.
Para que serve
Utilizar informaes de georeferenciamento atravs da Java Location API
em aplicativos Java ME. Alm disso, trata da utilizao de listeners que avisam o usurio da aproximao de um ponto conhecido, configurado pela sua
posio (latitude e longitude). O segundo artigo desta srie tambm mostrar informaes de mdia com a Mobile Media API.
Em que situao o tema til
Na utilizao de informao de georeferenciamento e na utilizao de listeners de aproximao de pontos geogrficos.
Ricardo Ogliari
rogliariping@gmail.com
22
WebMobile Magazine - Criando um aplicativo LBS para consulta de pontos tursticos em cidades
Java M obile
23
Nota do DevMan 1
JavaDB
Java DB uma distribuio da Sun para o banco de dados 100% de tecnologia Java
Apache Derby. Ele totalmente transacional, seguro, simples de usar, baseado em padres SQL, JDBC API e Java EE e pequeno, apenas 2MB. O projeto Apache Derby
possui uma comunidade forte e crescente que inclui desenvolvedores de grandes companhias tais como Sun Microsystems e IBM, assim como colaboradores individuais.
A tarefa a ser executada controlada por um parmetro chamado acao. Veja a Listagem 1 com o trecho de cdigo Java que
inserido na pgina JSP logo nas primeiras linhas.
Listagem 1. Parte da implementao do index.jsp
1. String acao = request.getParameter(acao);
2.
3.
Class.forName(org.apache.derby.jdbc.ClientDriver);
4.
Connection conn = DriverManager.
getConnection(jdbc:derby://localhost:1527/PONTOS);
5.
6.
Statement st = conn.createStatement();
7.
Statement stDeletar = conn.createStatement();
8.
Statement stSalvar = conn.createStatement();
9.
10.
if (acao != null && acao.equals(ver))
11. {
12. ResultSet rs = st.executeQuery(select * from
pontohistorico where codigo = +
13.
request.getParameter(codigo));
14.
rs.next();
15. %>
16.<table border=1>
17.<tr>
18.<td>Nome:</td>
19.<td><%=rs.getString(nome)%></td>
20.</tr>
21.<tr>
22.<td>Imagem:</td>
23.<td><%=rs.getString(imagem)%></td>
24.</tr>
25.<tr>
26.<td>Texto</td>
27.<td><%=rs.getString(texto)%></td>
28.</tr>
29.<tr>
30.<td>Latitude</td>
31.<td><%=rs.getString(latitude)%></td>
32.</tr>
33.<tr>
34.<td>Longitude</td>
35.<td><%=rs.getString(longitude)%></td>
36.</tr>
37.<tr>
38.<td></td>
39.</tr>
40.</table>
41.
<%
42. else if (acao != null && acao.equals(alterar))
43.
...
44.
else if (acao != null && acao.equals(inserir))
45. ...
46.
else
47.
...
Existe apenas um arquivo JSP chamado index.jsp, que controla a interface principal da pgina (Figura 2) e todas as aes
relacionadas, como insero, alterao e remoo de registros.
24
Na aplicao mobile onde veremos a utilizao da Java Location API. A compreenso do projeto simples, so somente
duas classes: MostraLocalizacao e AcessoHTTP. A primeira
contm a interface e a lgica da aplicao. A segunda classe
foi criada para tratar especificamente das conexes HTTP. A
aplicao faz uso de dois arquivos .jsp: recuperaPonto e recuperaPosicoes. A primeira pgina traz as informaes de nome,
descrio e imagem para um ponto especfico, j a segunda,
WebMobile Magazine - Criando um aplicativo LBS para consulta de pontos tursticos em cidades
Java M obile
por sua vez, traz os cdigos e as coordenadas (latitude e longitude) de todos os pontos tursticos cadastrados no banco de
dados JavaDB.
A tela inicial do aplicativo, mostrada na Figura 3, traz dois
campos de texto que informam a latitude e longitude, e dois
comandos: o primeiro (Iniciar) instancia as classes necessrias para o correto funcionamento da JSR 179, alm de iniciar
o listener que responde aos eventos de mudana de posio
do terminal. O comando Baixar Pontos acessa a pgina
recuperaPosicoes, recebendo todas as coordenadas dos pontos
cadastrados no servidor. Com isso, so criados os listeners de
proximidade aos pontos.
O mtodo recebePontos primeiramente armazena os trs vetores em variveis de instncia da sua classe (linhas 2, 3 e 4).
Posteriormente, analisa se a instncia de LocationProvider j foi
criada (linha 6), caso contrrio, inicia a thread que chama o
mtodo run mostrado na Listagem 2. A partir disso possvel
adicionar os listeners de proximidade. Para isso, necessrio chamar o mtodo addProximityListener, passando como
parmetro a instncia de uma classe que herde diretamente
de ProximityListener, uma instncia da classe Coordinates, que
recebe trs valores double, representando a latitude, longitude e
altitude do ponto a ser monitorado e, por fim, um valor float que
indica o raio que o listener deve considerar como aproximao.
No nosso exemplo, construamos uma cerca de 150 metros
de dimetro. Tudo isso feito na linha 15 da Listagem 4.
Listagem 5. Cdigo para procura de sensores
1. public void recebePontos(Vector vetCodigos, Vector
vetLatitudes, Vector vetLongitudes) {
2. his.vetCodigos = vetCodigos;
t
3. his.vetLatitudes = vetLatitudes;
t
4. his.vetLongitudes = vetLongitudes;
t
5.
6. f (lp == null)
i
7.
{
8. Thread t = new Thread(this);
9. t.start();
10. }
11.
12. for (int i = 0; i < vetLatitudes.size(); i++)
13. {
14. try {
15. lp.addProximityListener(this, new Coordinates(Double.
parseDouble(vetLatitudes.elementAt(i).toString()),
Double.parseDouble(vetLongitudes.elementAt(i).
toString()), 0), 150);
16. } catch (LocationException ex) {
17. fmMain.append(+ex);
18. break;
19. }
20. }
21. }
25
<waypoints>
<waypoint time=1500 latitude=-23.532268 longitude=46.632334 altitude=310 />
3. . . .
4. waypoint time=1500 latitude=-23.535098 longitude=<
46.634624 altitude=310 />
5. </waypoints>
No External Event Generator, h duas possibilidades de utilizao: a primeira colocar os dados de latitude, longitude
e altitude diretamente nos campos, o que pode se tornar
maante se quisermos simular uma caminhada contendo
vrios pontos. A segunda maneira criando um arquivo
XML que define uma seqncia de pontos, que seguida
pela ferramenta. Este XML deve seguir o padro apresentado na Listagem 6. O tag root sempre ser waypoints, cada
coordenada deve ser especificada com a tag waypont. Na
Listagem 6 existem apenas duas coordenadas, porm, no
arquivo XML criado foram inseridas 14 pontos geogrficos.
Para utilizar este arquivo, basta clicar no boto Browse...
e selecionar o .xml criado. Depois disso, apenas clique no
boto de play e a rota comea a ser emulada.
Para conseguir criar um ambiente de testes para nosso
aplicativo, foi criado um arquivo .xml que gera uma rota comeando nas proximidades da estao da Luz, na cidade de
So Paulo. Suas ltimas coordenadas especificadas apontam
para posies geogrficas prximas estao da Luz (menos
26
WebMobile Magazine - Criando um aplicativo LBS para consulta de pontos tursticos em cidades
Java M obile
else if (c == cmSim)
{
acessoHttp.buscaInformacoes(codigoEnc);
}
...
public void mostraDadosPonto(String nome, String texto,
byte[] img) {
8. iNome.setText(nome);
s
9. iDescricao.setText(texto);
s
10. imgPonto = Image.createImage(img, 0, img.length);
11.
12. fmDados.deleteAll();
13. fmDados.append(siNome);
14. fmDados.append(siDescricao);
15. fmDados.append(imgPonto);
16.
17. display.setCurrent(fmDados);
18. }
Concluso
Neste artigo foi possvel verificar como simples utilizar
a Java Location API. Porm, apesar de sua facilidade, seu
poder imenso. Assim como criamos um aplicativo Mobile
Learning para mostrar a aproximao de pontos histricos,
poderamos ter criado um aplicativo para mostrar pontos de
interesse para o usurio, seguindo a mesma idia e a mesma
estrutura utilizada neste artigo.
Alm disso, o uso de sistemas LBS est crescendo e as projees so de que este crescimento s aumente no decorrer
dos prximos anos. A requisio de aplicativos desse porte
Links
Documentao da Java Location API
http://jcp.org/en/jsr/detail?id=179
Tutoriais, artigos e vdeo aulas sobre JME
www.devmedia.com.br
27
28
WebMobile Magazine - Criando um aplicativo LBS para consulta de pontos tursticos em cidades
Java M obile
29
Conferindo o tempo
com Android
30
ANDROID
Definindo um objetivo
Visto que nosso objetivo efetuar a comunicao com um web
service, nada melhor do que utilizar um existente ao invs de
criarmos uma aplicao ponta-a-ponta, afinal no queremos
perder o foco.
A sugesto desenvolver um aplicativo a ser chamado de
ClimaTempo, capaz de nos informar como est o tempo em
uma dada localidade.
Felizmente existe um servio no GeoCities que torna disponvel estas informaes, atravs de uma srie de centrais de
observao do tempo e clima dispostos pelo mundo, bastando
informar a latitude e longetude (as quais podem ser obtidas
atravs do GPS do Android, ou Google Maps) ou ainda o
cdigo internacional dos aeroportos (ICAO Internacional
Civil Aviation Organization). Este ltimo servio (que faz
uso do ICAO) nos retorna informaes como temperatura,
velocidade e direo do vento, horrio da observao e nome
da central, e por bvio est limitado cidades que possuem
um aeroporto.
Vamos comear pelo caso mais simples, onde definimos uma
cidade padro, fazemos a chamada ao servio web - enviando
o ICAO - e tratamos a resposta para exibir convenientemente
ao usurio.
Nota do DevMan 1
JSON
JSON (JavaScript Object Notation) um formato leve de troca de dados. Um formato de texto completamente independente de linguagem que faz uso de convenes
familiares aos programadores de linguagens da famlia C (C, C++, Java, Javascript..).
Nota do DevMan 2
REST
REST uma descrio analtica de arquiteturas web existentes, e assim, a interrelao entre o estilo e protocolo HTTP subjacente aparece de forma transparente.
Alm do acesso a internet, nossa aplicao possuir uma nica tela onde o usurio poder verificar a temperatura, o tipo de
nvens no cu (com direito a imagem), a velocidade do vento, a
data e hora da observao de tais informaes no observatrio
escolhido. Esta tela pode ser visualizada na Figura 1.
Desenvolvendo o ClimaTempo
Uma boa forma de se iniciar um projeto pequeno definir e
delimitar suas funcionalidades.
J sabido que estaremos trabalhando com um servio web.
Por este motivo, precisamos de permisso de acesso internet,
o que no Android feito via AndroidManifest. A Listagem 1
nos apresenta na linha 6 uma forma de especificar o uso desta
permisso. O restante do arquivo como um AndroidManifest
qualquer, que define sua nica atividade nas linhas 7 15.
Listagem 1. AndroidManifest.xml
01.<?xml version=1.0 encoding=utf-8?>
02.<manifest xmlns:android=http://schemas.android.com/apk/res/
android
03.
package=webmobile.android.climatempo
04.
android:versionCode=1
05.
android:versionName=1.0.0>
06.
<uses-permission android:name=android.permission.INTERNET />
07.
<application android:icon=@drawable/icon
08.
android:label=@string/app_name>
09.
<activity android:name=.ClimaTempo
10.
android:label=@string/app_name>
11.
<intent-filter>
12.
<action android:name=android.intent.action.
MAIN />
13.
<category android:name=android.intent.
category.LAUNCHER />
14.
</intent-filter>
15.
</activity>
16.
</application>
17.</manifest>
31
Listagem 2. main.xml
01. <?xml version=1.0 encoding=utf-8?>
02.
<AbsoluteLayout
03.
android:id=@+id/widget0
04.
android:layout_width=fill_parent
05.
android:layout_height=fill_parent
06.
xmlns:android=http://schemas.android.com/apk/res/android>
07. TextView
<
08.
android:id=@+id/lblTemperatura
09. ndroid:layout_width=66px
a
10. ndroid:layout_height=59px
a
11. ndroid:text=19
a
12. ndroid:textSize=40sp
a
13. ndroid:typeface=serif
a
14. ndroid:layout_x=170px
a
15. ndroid:layout_y=2px/>
a
16. TextView
<
17. ndroid:id=@+id/lblData
a
18. ndroid:layout_width=138px
a
19. ndroid:layout_height=27px
a
20. ndroid:text=05/10/2008
a
21. ndroid:layout_x=176px
a
22. ndroid:layout_y=120px/>
a
23. TextView
<
24. ndroid:id=@+id/txtGrau
a
25. ndroid:layout_width=wrap_content
a
26. ndroid:layout_height=wrap_content
a
27. ndroid:text=o
a
28. ndroid:layout_x=236px
a
29. ndroid:layout_y=5px/>
a
30. TextView
<
31. ndroid:id=@+id/lblNuvens
a
32. ndroid:layout_width=wrap_content
a
33. ndroid:layout_height=wrap_content
a
34. ndroid:text=Nvens Esparsas
a
35. ndroid:layout_x=175px
a
36. ndroid:layout_y=65px/>
a
37. ImageSwitcher
<
38. ndroid:id=@+id/imgTempo
a
39. ndroid:layout_width=153px
a
40. ndroid:layout_height=127px
a
41. ndroid:layout_x=6px
a
42. ndroid:layout_y=7px/>
a
43. TextView
<
44. ndroid:id=@+id/lblVento
a
45. ndroid:layout_width=wrap_content
a
46. ndroid:layout_height=wrap_content
a
47. ndroid:text=Vento: 150km/h
a
48. ndroid:layout_x=176px
a
49. ndroid:layout_y=93px/>
a
50. TextView
<
51. ndroid:id=@+id/txtCelsius
a
52. ndroid:layout_width=wrap_content
a
53. ndroid:layout_height=42px
a
54. ndroid:text=C
a
55. ndroid:textSize=24sp
a
56. ndroid:textStyle=bold
a
57. ndroid:layout_x=249px
a
58. ndroid:layout_y=7px/>
a
59. /TextView>
<
60.</AbsoluteLayout>
Listagem 3. ClimaTempo.java
01. public class ClimaTempo extends Activity {
02. rivate ImageSwitcher imgTempo;
p
03. rivate TextView lblTemperatura;
p
04. rivate TextView lblData;
p
05. rivate TextView lblVento;
p
06. rivate TextView lblNuvens;
p
07.
08.
/** Called when the activity is first created. */
09.
@Override
10.
public void onCreate(Bundle savedInstanceState) {
11.
super.onCreate(savedInstanceState);
12.
setContentView(R.layout.main);
13.
14.
imgTempo = (ImageSwitcher) findViewById(R.id.imgTempo);
15.
lblTemperatura = (TextView) findViewById(R.id.lblTemperatura);
16.
lblData
= (TextView) findViewById(R.id.lblData);
17.
lblVento = (TextView) findViewById(R.id.lblVento);
18.
lblNuvens = (TextView) findViewById(R.id.lblNuvens);
19.
20.
atualizar();
Uma vez definida a tela principal, pode-se iniciar o desenvolvimento da atividade que a compreende. Vamos comear a
editar a classe ClimaTempo de forma a dar vida aplicao.
A Listagem 3 define tal atividade realizando a vinculao
dos campos de texto onde sero exibidas as informaes de
temperatura, velocidade do vento, tipo de nvens, data e hora.
Alm do ImageSwitcher que estar ilustrando o tempo, com
base no tipo de nvem. Toda essa vinculao pode ser visualizada nas linhas 14 18. Logo em seguida, nas linhas 23 38,
instanciamos uma Estao, a qual nos fornece uma Observao do tempo. Esta Observao utilizada para alimentar os
componentes em tela, atualizando a interface.
Uma Observao no ClimaTempo no passa de um POJO
(Plain Old Java Object), ou seja um objeto Java comum, com
as propriedades e acessores utilizados pela Listagem 3. J a
Estao, uma classe que vale a pena ser abordada, pois ela
responsvel pela conexo com o web service e tratamento da
resposta. Por bvio, estas responsabilidades sero distribudas
entre duas outras classes, para melhor compreenso do que se
passa no processo de comunicao com o servio web.
32
21.
}
22.
23.
public void atualizar(){
24.
Observacao tempo;
25.
try {
26.
tempo = new Estacao(SBFL).getTempo();
27.
lblTemperatura.setText(tempo.getTemperatura());
28.
lblData.setText(tempo.getHorario());
29.
lblVento.setText(Vento: + tempo.getVelocidadeDoVento()
30.
+ km/h);
31.
imgTempo.setBackgroundResource(
32.
ImagensDeNuvem.getImagem(tempo.getNuvens()));
33.
lblNuvens.setText(tempo.getNuvens());
34. } catch (InformacoesIndisponiveis e) {
35. TODO Auto-generated catch block
//
36.
e.printStackTrace();
37. }
38.
}
39. }
ANDROID
Listagem 4. Estacao.java
01. public class Estacao{
02. private String icao;
03.
04. public Estacao(String icao){
05. this.icao = icao;
06. }
07.
08. public Observacao getTempo() throws InformacoesIndisponiveis{
09. Observacao tempo = null;
10. Proxy proxy = null;
11. try {
12. proxy = new Proxy(http://ws.geonames.org/weatherIcaoJSON?
13.
+ ICAO= + this.icao);
14. tempo = new TratadorJSON().tratar(proxy.conectar());
15. } catch (Exception e) {
16. throw new InformacoesIndisponiveis();
17. } finally {
18. proxy.encerrar();
19. proxy = null;
20. }
21. return tempo;
22. }
23.}
Tratando a resposta
A parte importante da resposta recebida pelo proxy a
entidade HTTP. Esta entidade possui um valor no formato
JSON que pode ser encarado como uma String e exatamente
o que faremos para obter um objeto de consulta.
A Listagem 6 contm um exemplo de retorno proveniente
do servio, obtido atravs de uma requisio direta de um navegador web qualquer. Antes de mais nada vamos analis-lo.
primeira vista, nota-se que a resposta possui uma rea til,
descrita por uma propriedade chamada weatherObservation.
Esta propriedade poderia ser encarada como um objeto cujas
propriedades so as informaes que desejamos exibir ao
usurio sim, temos muito mais informao disponvel do
que o ClimaTempo atualmente utiliza.
Embora seja extremamente fcil desenvolver um interpretador para mensagens como esta, vamos utilizar a API JSON
(disponvel para download no SourceForge), a qual foi criada
para este fim e desempenha seu papel muito bem.
Uma das formas de se criar um objeto JSON fornecer
uma String ao seu construtor, da a API se encarregar de
interpretar a mensagem (String da entidade) e montar uma
estrutura equivalente de objetos JSON, de forma a facilitar o
acesso aos dados da mesma.
Na Listagem 7 est definido um tratador JSON, que ao
receber uma entidade HTTP obtm seu valor no formato de
texto JSON, convertendo esta mensagem num JSONObject.
Este objeto por sua vez - representa o que seria o envelope na
arquitetura SOAP -, possui uma nica propriedade chamada
weatherObservation, de onde obtemos as demais informaes
utilizando mtodos prticos da API para construir o objeto
Observacao, a ser retornado at a atividade ClimaTempo,
fechando o clico de vida da nossa aplicao.
Note o uso de Strategy Pattern nesta classe. O motivo para isto,
num exemplo to simples, que bastaria modificar o contedo do
mtodo tratar para interpretar XML (utilizando SAX, por exemplo)
ao invs de texto JSON, para atender a um servio SOAP.
33
Listagem 6. WeatherIcaoJSON
01. {
02. weatherObservation:{
03. clouds:scattered clouds,
04. weatherCondition:n/a,
05. observation:SBFL 011700Z 35015KT 9999 SCT030 BKN045
23/15 Q1017,
06. windDirection:350,
07. ICAO:SBFL,
08. elevation:5,
09. countryCode:BR,
10. lng:-48.5333333333333,
11. temperature:23,
12. dewPoint:15,
13. windSpeed:15,
14. humidity:60,
15. stationName:Florianopolis Aeroporto ,
16. datetime:2008-11-01 17:00:00,
17. lat:-27.6666666666667,
18. hectoPascAltimeter:1017
19. }
20.}
Listagem 7. TratadorJSON
01. public class TratadorJSON implements TratadorResposta<Observacao> {
02.
03. public Observacao tratar(HttpEntity resposta) throws Exception {
04. JSONObject envelope = new JSONObject(
05. EntityUtils.toString(resposta));
06.
07. JSONObject observacao = envelope
08. .getJSONObject(weatherObservation);
09.
10. Observacao tempo = new Observacao();
11. tempo.setNuvens(observacao.getString(clouds));
12. tempo.setTemperatura(observacao.getString(temperature));
13. tempo.setHorario(observacao.getString(datetime));
14. tempo.setVelocidadeDoVento(observacao.getString(windSpeed));
15.
16. return tempo;
17. }
18.}
Concluses
A Web Mobile tem que ser feita ao seu gosto. Para isso, precisamos saber
o que voc, leitor, acha da revista!
34
graduado em Cincia da Computao pela Universidade da Amaznia (UNAMA). Trabalha com a tecnologia Java desde 2005. Possui experincia nas trs
especificaes: JSE, JEE e JME. Trabalhou com desenvolvimento de aplicaes
mveis comerciais (M-Commerce / M-Payment). um dos evangelistas de
Android no Brasil, promovendo o uso da plataforma em cursos e palestras.
Atualmente mestrando da Universidade Federal de Pernambuco (UFPE)
na rea de Engenharia de Software, mais especificamente em Model-Driven
Architecture (Arquitetura Dirigida a Modelos) e um dos membros do projeto
ORCAS (www.orcas.eu).
35
36
Nota do DevMan 1
Compatibilidade entre verses do SDK
Um dos maiores problemas que estamos enfrentamos durante o desenvolvimento
de uma aplicao em Android talvez seja este bombardeio de verses de releases
do SDK que a plataforma tem sofrido durante este perodo de amadurecimento do
Google Android, o que implicou severamente na parcial incompatibilidade entre as
aplicaes desenvolvidas em verses diferentes. Elas eram desenvolvidas em uma
verso e quase sempre sofriam ajustes (renomeaes de APIs, remoo de classes,
etc) para que fosse possvel rod-la na verso mais recente.
Alm disso, existe uma correspondncia entre a verso de um SDK e a verso do
plug-in ADT. Por exemplo, o SDK 1.0 Release 2 (verso mais atual disponvel durante
a escrita deste artigo) requer a verso 0.8.0 do plug-in Eclipse ADT para que o desenvolvimento de aplicaes funcione corretamente.
Sendo assim, tenha em mente esta caracterstica quando estiver desenvolvendo,
adaptando ou migrando aplicaes em Android que foram construdas utilizando
verses de SDKs diferentes. Para baixar a ltima verso do SDK acesse http://code.
google.com/intl/pt-BR/android/download.html. Para mais informaes de como
instalar/atualizar o plug-in Eclipse ADT acesse http://code.google.com/intl/pt-BR/
android/intro/installing.html#installingplugin.
Listagem 1. fade.xml
<?xml version=1.0 encoding=utf-8?>
<alpha xmlns:android=http://schemas.android.com/apk/res/android
android:interpolator=@android:anim/accelerate_interpolator
android:fromAlpha=0.0 android:toAlpha=1.0
android:duration=100 />
Incrementando a Activity
Aqui vai um lembrete essencial: pelo fato de mostrarmos um
mapa em nossa Activity, devemos em vez de estender simplesmente Activity (criado por padro), alteramos para WSCepActivity herdar de MapActivity (ler Nota DevMan 2), haja vista
que este tipo de Activity j possui funcionalidades (threads)
ANDROID
Listagem 2.main.xml
<?xml version=1.0 encoding=utf-8?>
<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android
a
ndroid:orientation=vertical android:layout_width=wrap_content
a
ndroid:layout_height=wrap_content android:id=@+id/rootLayout>
<ViewFlipper android:id=@+id/flipper
android:layout_width=fill_parent android:layout_
height=wrap_content
android:flipInterval=2000 android:padding=10px>
<TextView android:layout_width=fill_parent
a
ndroid:layout_height=wrap_content
android:gravity=center_horizontal
a
ndroid:textSize=16px android:text=Entre com o CEP, />
<TextView android:layout_width=fill_parent
a
ndroid:layout_height=wrap_content
android:gravity=center_horizontal
android:textSize=16px android:text=clique na lupa
ao lado ou />
<TextView android:layout_width=fill_parent
a
ndroid:layout_height=wrap_content
android:gravity=center_horizontal
a
ndroid:textSize=16px android:text=pressione ENTER />
</ViewFlipper>
<LinearLayout android:orientation=horizontal
android:layout_width=wrap_content android:layout_
height=wrap_content>
<TextView android:id=@+id/tvCepDesc android:layout_
width=wrap_content
android:layout_height=wrap_content android:text=@
string/cep_desc />
<EditText android:id=@+id/etCEP android:layout_
width=240px
a
ndroid:hint=Digite o CEP android:layout_height=wrap_
content />
<ImageButton android:id=@+id/imgBtnPesquisar
android:layout_width=wrap_content android:layout_
height=wrap_content
android:src=@drawable/search />
</LinearLayout>
<LinearLayout android:orientation=vertical
android:layout_width=fill_parent android:layout_
height=wrap_content>
<
TextView android:id=@+id/tvEstado android:layout_
width=wrap_content
android:textSize=12px android:layout_height=wrap_
content
android:text=@string/estado />
<TextView android:id=@+id/tvCidade android:layout_
width=wrap_content
android:textSize=12px android:layout_height=wrap_content
android:text=@string/cidade />
<TextView android:id=@+id/tvBairro android:layout_
width=wrap_content
android:textSize=12px android:layout_height=wrap_content
android:text=@string/bairro />
<TextView android:id=@+id/tvTipoLogradouro
android:layout_width=wrap_content
android:textSize=12px
android:layout_height=wrap_content android:text=@
string/tipo_logradouro />
<TextView android:id=@+id/tvLogradouro
android:layout_width=wrap_content
android:textSize=12px
android:layout_height=wrap_content android:text=@
string/logradouro />
<TextView android:id=@+id/tvComplemento
android:layout_width=wrap_content
android:textSize=12px
android:layout_height=wrap_content android:text=@
string/complemento />
<
/LinearLayout>
<
RelativeLayout xmlns:android=http://schemas.android.com/apk/res/
android
android:layout_width=fill_parent android:layout_
height=fill_parent>
<com.google.android.maps.MapView
android:id=@+id/map android:layout_width=fill_parent
android:layout_height=fill_parent android:apiKey={api_
key_gerada}
android:clickable=true />
<LinearLayout android:id=@+id/map_zoom
android:layout_width=wrap_content android:layout_
height=wrap_content
android:layout_alignParentBottom=true
android:layout_centerHorizontal=true />
<
/RelativeLayout>
</LinearLayout>
37
Listagem 3. WSCepActivty.java
/* package & imports */
public class WSCepActivity extends MapActivity implements View.
OnClickListener, View.OnKeyListener {
/* declarao de variveis*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
flipper = (ViewFlipper) findViewById(R.id.flipper);
Animation in = AnimationUtils.loadAnimation(this,
android.R.anim.fade_in);
Animation out = AnimationUtils.loadAnimation(this,
android.R.anim.fade_out);
flipper.setInAnimation(in);
flipper.setOutAnimation(out);
flipper.startFlipping();
/* inicializando widgets */
etCEP = (EditText) findViewById(R.id.etCEP);
tvEstado = (TextView) findViewById(R.id.tvEstado);
tvCidade = (TextView) findViewById(R.id.tvCidade);
tvBairro = (TextView) findViewById(R.id.tvBairro);
tvTipoLograd = (TextView) findViewById(R.id.tvTipoLogradouro);
tvLograd = (TextView) findViewById(R.id.tvLogradouro);
tvComplemento = (TextView) findViewById(R.id.tvComplemento);
imgBtnPesquisar = (ImageButton) findViewById(R.id.imgBtnPesquisar);
mapView = (MapView) findViewById(R.id.map);
38
imgBtnPesquisar.setOnClickListener(this);
etCEP.setOnKeyListener(this);
@Override
protected boolean isRouteDisplayed() {
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
SubMenu subMenu = menu.addSubMenu(0,1,2,Modo de Mapa).
setIcon(android.R.drawable.ic_menu_mapmode);
subMenu.add(0,2,1,Trfego);
subMenu.add(0,3,2,Satlite);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case 2:
mapView.setTraffic(true);
mapView.setSatellite(false);
break;
case 3:
mapView.setTraffic(false);
mapView.setSatellite(true);
break;
}
return true;
ANDROID
Listagem 4. AndroidManifest.xml
<?xml version=1.0 encoding=utf-8?>
<manifest xmlns:android=http://schemas.android.com/apk/res/
android
package=android.webmobile.ws.cep android:versionCode=1
a
ndroid:versionName=1.0.0>
<uses-permission android:name=android.permission.INTERNET />
<uses-permission android:name=android.permission.ACCESS_
COARSE_LOCATION />
Listagem 5. strings.xml
uses-library android:name=com.google.android.maps />
<
activity android:name=WSCepActivity android:label=@string/
<
app_name>
<intent-filter>
action android:name=android.intent.action.MAIN />
<
category android:name=android.intent.category.LAUNCHER />
<
</intent-filter>
/activity>
<
</application>
</manifest>
Nota do DevMan 2
Obtendo uma API Key para ativar o uso de MapViews
A partir da verso 0.9 do SDK, os MapViews e as aplicaes para poderem rodar
nos dispositivos em Android devem ser assinados obrigatoriamente. Isto se torna necessrio, pois eles permitem acesso aos dados do Google Maps. Sendo assim, preciso
se registrar no servio do Google Maps e aceitar aos Termos de Servios para que seu
MapView possa obter qualquer tipo de dado retornado pelo Google Maps. E isso se
aplica tanto durante o desenvolvimento das aplicaes no emulador quanto para uma
aplicao que ir rodar normalmente em um dispositivo que rode Android (como o HTC
G1 T-Mobile, atualmente o nico dispositivo mvel disponvel comercialmente rodando
a plataforma do Google).
Registrar um MapView a fim de se obter uma chave privada vlida comumente chamada de API Key simples, de graa e pode ser seguido basicamente em dois passos:
1 - Registrar o fingerprint (impresso digital) MD5 do certificado que voc utilizar
para assinar a sua aplicao. Depois, deixe que o prprio servio de registro do Google
Maps fornea a chave gerada para ser utilizada nas aplicaes que foram assinadas com
o certificado que voc utilizou.
2 - Adicionar em cada MapView utilizado, uma referncia para a API Key gerada (via
XML ou via cdigo), desde que esta chave tenha sido a que foi gerada pelo fingerprint
que voc utilizou durante o processo de registro.
possvel que voc crie seu prprio certificado (da mesma maneira que utilizvamos para assinatura de Applets nos tempos ureos de Java...) utilizando a
ferramenta keytool que vem integrada em qualquer SDK de Java. Em termos de
desenvolvimento, Android j disponibiliza um certificado um arquivo chamado
debug.keystore (conhecido tambm como Debug Certificate) - que fica armazenado num diretrio especfico que varia de plataforma para plataforma. A Tabela 1
mostra o diretrio em que o arquivo debug.keystore est armazenado de acordo
com a plataforma. Porm, para deploy das aplicaes em dispositivos, necessrio
que outro certificado seja utilizado. Mas se voc estiver usando o Eclipse/ADT para
desenvolvimento, o local deste arquivo pode ser obtido indo em Windows > Preferences > Android > Build.
Diretrio
Windows Vista
C:\Users\<user>\AppData\Local\Android\debug.keystore
Windows XP
OS X e Linux
39
Posio no Array
Descrio
resultado[0]
resultado[1]
Logradouro (Endereo)
resultado[2]
Complemento
resultado[3]
Bairro
resultado[4]
Cidade
resultado[5]
40
obtido, etc.
Comeamos declarando trs variveis pblicas finais estticas
que representam, respectivamente, a URL do WebService (URL) o
nome da operao responsvel por buscar o CEP (OPERATION),
o namespace do WS (NAMESPACE), o nome de usurio (USERNAME) e a senha (PASSWORD).
Seguindo, declaramos o mtodo esttico pesquisarCEP(),
passando como parmetro uma String que representar o CEP
informado pelo usurio. Depois, comeamos a utilizar a primeira
das principais classes da biblioteca SoapObject (varivel request)
- que representar o encapsulamento da requisio que ser feita
ao Web Service, ou seja, o que vai dentro do envelope. Ela recebe
como parmetro uma String representando o namespace referente ao WS e o nome da operao, que no nosso caso traz_cep.
Em seguida, criamos um objeto SoapSerializationEnvelope
(varivel envelope) que a abstrao de um envelope SOAP e
passamos como parmetro a verso do protocolo SOAP que
iremos utilizar (SoapEnvelope.VER11). Chamamos envelope.
setOutputSoapObject(request) para encapsularmos request
como corpo do envelope SOAP a ser enviado.
Agora criamos um StringBuffer que ir formatar o parmetro
no esquema correto aceito pelo WS. Adicionamos - por meio
do mtodo addProperty() - a String dados_cep que ser uma
espcie de chave para seu valor - o parmetro formatado. Instanciamos um objeto HttpTransportSE (SE uma referncia para
Standard Edition de Java uma vez que estamos usando a verso
de KSOAP2 para JSE) e passamos como parmetro a URL para
acessar o Web Service. Finalmente, chamamos o mtodo call()
de HttpTransportSE (varivel httpTransport), passando uma
string em branco (no precisaremos de nenhuma SoapAction) e o
envelope que construmos anteriormente e esperamos a resposta
do servidor. Assim que a resposta retornada, o valor obtido
recuperado pela chamada envelope.getResponse().
O resultado pode vir em dois formatos: uma String com os
valores da localidade, todos concatenados (mais informaes
do formato retornado, revisitar a seo Entendendo o funcionamento do Web Service de CEP) caso o CEP seja vlido
ou a String ##### (na verdade como se o campo de cada
informao de localidade estivesse vazio) caso o CEP no seja
encontrado. Por fim, instanciamos o objeto CepBean (Listagem
7) para encapsularmos os dados retornados da consulta.
ANDROID
Listagem 6. WSConnection.java
package android.webmobile.ws.cep;
/* imports */
public class WSConnection {
private static final String URL = http://www.maniezo.com.br/
webservice/soap-server.php;
private static final String OPERATION = traz_cep;
private static final String NAMESPACE = http://www.maniezo.
com.br/soap-server.php;
private static final String USERNAME = ramonrabello;
private static final String PASSWORD = trip22;
public static Object pesquisarCEP(String cep) {
SoapObject request = new SoapObject(NAMESPACE, OPERATION);
SoapSerializationEnvelope envelope = new
SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
StringBuffer params = new StringBuffer();
params.append(cep.concat(#));
params.append(USERNAME.concat(#));
params.append(PASSWORD.concat(#));
request.addProperty(dados_cep, params.toString());
HttpTransportSE httpTransport = new HttpTransportSE(URL);
try {
httpTransport.call(, envelope);
String response = (String) envelope.getResponse();
if (response.equals(#####))
return null;
else {
String[] dadosCep = response.split(#);
CepBean cepBean = new CepBean();
cepBean.setTipoLogradouro(dadosCep[0]);
cepBean.setLogradouro(dadosCep[1]);
cepBean.setComplemento(dadosCep[2]);
cepBean.setBairro(dadosCep[3]);
cepBean.setCidade(dadosCep[4]);
cepBean.setUf(dadosCep[5]);
cepBean.setCep(cep);
return cepBean;
}
}
catch (IOException ioex) {
return null;
}
catch (XmlPullParserException e) {
return null;
}
Listagem 7. CepBean.java
package android.webmobile.ws.cep;
public class CepBean {
private
private
private
private
private
private
private
}
String
String
String
String
String
String
String
cep;
uf;
cidade;
logradouro;
complemento;
tipoLogradouro;
bairro;
41
Listagem 8. WSCepActivity.java
/* package e imports */
public class WSCepActivity extends MapActivity implements View.
OnClickListener,
View.OnKeyListener, Runnable
{
/* declarao de variveis */
/* restante do cdigo */
private void pesquisarCep() {
progressDialog = ProgressDialog.show(this, Buscando CEP,
Por favor, Aguarde..., true, false);
Thread t = new Thread(this);
t.start();
}
public void run() {
if (etCEP.getText().toString().equals()) {
Bundle bundle = new Bundle();
bundle.putString(titulo, CEP em branco);
bundle.putString(msg, Por favor, informe o CEP);
Message m = Message.obtain();
m.setData(bundle);
handlerError.sendMessage(m);
}
else {
cepBean = (CepBean) WSConnection.pesquisarCEP(etCEP.
getText().toString().trim());
if (cepBean != null) {
try {
Geocoder geocoder = new Geocoder(this);
String local = cepBean.getTipoLogradouro() + +
cepBean.getLogradouro() + , + cepBean.getCidade();
Address localidade = geocoder.getFromLocationName(local,
1).get(0);
if (localidade != null) {
latitude = localidade.getLatitude() * 1E6;
longitude = localidade.getLongitude() * 1E6;
geoPoint = new GeoPoint(latitude.intValue(),
longitude.intValue());
mapController = mapView.getController();
mapController.setZoom(17);
mapController.animateTo(geoPoint);
marker = getResources().getDrawable(R.drawable.pin);
if (mapView.getOverlays().size() > 0)
mapView.getOverlays().clear();
mapView.getOverlays().add(new
LocationCepOverlay(marker));
handler.sendEmptyMessage(0);
}
else {
Bundle bundle = new Bundle();
bundle.putString(titulo, Localidade no encontrada);
bundle.putString(msg,No foi possvel encontrar uma
localidade no mapa para este cep.);
Message m = Message.obtain();
m.setData(bundle);
handlerError.sendMessage(m);
}
}
catch (IOException ex) {
Bundle bundle = new Bundle();
bundle.putString(titulo, Erro de IO);
bundle.putString(msg, Erro ao obter localidade.
Mensagem: + ex.getMessage());
Message m = Message.obtain();
m.setData(bundle);
handlerError.sendMessage(m);
} catch (Exception ex) {
42
}
}
else {
Bundle bundle = new Bundle();
bundle.putString(titulo, CEP no encontrado);
bundle.putString(msg,Desculpe, o CEP no pde ser
encontrado. Tente novamente.);
Message m = Message.obtain();
m.setData(bundle);
handlerError.sendMessage(m);
}
progressDialog.dismiss();
};
// Handler para mostrar mensagens de erro
private Handler handlerError = new Handler() {
public void handleMessage(Message msg) {
if (progressDialog.isShowing()) progressDialog.dismiss();
tvEstado.setText(getString(R.string.estado));
tvCidade.setText(getString(R.string.cidade));
tvBairro.setText(getString(R.string.bairro));
tvTipoLograd.setText(getString(R.string.tipo_logradouro));
tvLograd.setText(getString(R.string.logradouro));
tvComplemento.setText(getString(R.string.complemento));
String titulo = msg.getData().getString(titulo);
String mensagem = msg.getData().getString(msg);
alertDialog = new AlertDialog.Builder(WSCepActivity.this).
create();
alertDialog.setButton(OK, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
}
};
alertDialog.setTitle(titulo);
alertDialog.setMessage(mensagem);
alertDialog.setIcon(android.R.drawable.ic_dialog_alert);
alertDialog.show();
ANDROID
Listagem 9. WSCepActivity.java
/* package & imports */
public class WSCepActivity extends MapActivity implements View.
OnClickListener,
View.OnKeyListener, Runnable
{
/* cdigo omitido */
public void run() {
if (etCEP.getText().toString().equals()) {
/* cdigo omitido */
}
else {
cepBean = (CepBean) WSConnection.pesquisarCEP(etCEP.
getText().toString().trim());
if (cepBean != null) {
try {
Geocoder geocoder = new Geocoder(this);
String local = cepBean.getTipoLogradouro() +
+ cepBean.getLogradouro() + , +
cepBean.getCidade();
Address localidade = geocoder.
getFromLocationName(local, 1).get(0);
if (localidade != null) {
latitude = localidade.getLatitude() * 1E6;
longitude = localidade.getLongitude() * 1E6;
geoPoint = new GeoPoint(latitude.intValue(),
longitude.intValue());
mapController = mapView.getController();
mapController.setZoom(17);
mapController.animateTo(geoPoint);
}
else {
/* cdigo omitido */
}
}
catch (IOException ex) {
/* cdigo omitido */
} catch (Exception ex) {
/* cdigo omitido */
}
}
else {
/* cdigo omitido */
}
}
}
}
43
/* restante do cdigo */
private class LocationCepOverlay extends ItemizedOverlay<OverlayItem> {
List<OverlayItem> overlayItems = new ArrayList<OverlayItem>();
/* declarao de variveis */
/* cdigo omitido */
public void run() {
try {
localidade = geocoder.getFromLocationName(cepBean.
getTipoLogradouro() + + cepBean.getLogradouro() +
, + cepBean.getCidade(), 1).get(0);
@Override
protected OverlayItem createItem(int i) {
return overlayItems.get(i);
}
if (localidade != null) {
/* cdigo omitido */
marker = getResources().getDrawable(R.drawable.pin);
mapView.getOverlays().add(new
LocationCepOverlay(marker));
handler.sendEmptyMessage(0);
}
else {
/* cdigo omitido */
}
}
catch (IOException ex) {
/* cdigo omitido */
} catch (Exception ex) {
/* cdigo omitido */
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, shadow);
boundCenterBottom(marker);
}
@Override
public int size() {
return overlayItems.size();
}
Concluses
Como voc pde perceber, Android ainda no possui uma
API que j venha embutida que trate especificamente de Web
Services. Sendo assim, para ser possvel trabalharmos com
WS, Android possui a capacidade de integrar as mesmas
bibliotecas de Java SE, como vimos com a verso de KSOAP2,
em aplicaes comerciais reais.
A plataforma Android, por mais que ainda esteja muito
44
Introduo ao
desenvolvimento de
aplicaes para o iPhone
com o iPhone SDK
Rogrio Arajo
rogerio.araujo@gmail.com
desenvolvedor especialista em tecnologias WEB, Mobile e Desktop. Atualmente trabalha na empresa Druid Search com solues de buscas corporativas
para grandes empresas.
45
Histria do iPhone
O iPhone o primeiro celular produzido pela fabricante de
computadores Apple. Ele revolucionou o mercado de celulares
ao apresentar uma gama de funcionalidades inditas neste tipo
de dispositivo, onde a principal delas seu teclado virtual que
pode ser utilizando bastando somente tocar na tela, chamado
de touch screen (ver Figura 1).
46
Nota do DevMan 1
XIB
O XIB um formato de arquivo usado para descrever de forma declarativa a
estrutura de uma tela de uma aplicao para o iPhone, contendo informaes
como tamanho, posicionamento, componentes presentes na tela, caractersticas
e comportamentos dos mesmos.
WebMobile Magazine - Introduo ao desenvolvimento de aplicaes para o iPhone com o iPhone SDK
M OBILE
Ao confirmar, ser apresentada a tela de boas vindas ao instalador do iPhone SDK (Figura 5). Clique no boto Continuar.
Ao continuar a instalao voc ser conduzido a uma tela
contendo os termos da licena de uso da IDE Xcode (Figura 6),
que a IDE usada para criar as aplicaes para o iPhone. Leia
47
Agora poderemos confirmar o local onde o SDK ser instalado (atravs do boto Alterar Localizao da Instalao...).
Manteremos a instalao no local padro. Ento, para iniciar a
instalao dos pacotes clique no boto Instalar (Figura 9).
Figura 10. Informando usurio e senha com permisso para instalar o SDK
48
WebMobile Magazine - Introduo ao desenvolvimento de aplicaes para o iPhone com o iPhone SDK
M OBILE
49
Agora que temos a estrutur bsica de nossa aplicao disponvel, ns vamos partir para a construo da interface da
aplicao em primeiro lugar. Para isso, selecione o arquivo
ConversorViewController.xib na janela da Figura 18, d dois
cliques sobre o mesmo para abr-lo em modo de edio no
Interface Builder conforme podemos ver na Figura 19.
Aps adicionar os componentes na tela, voc pode modificar tambm seus atributos. Para isso, basta clicar em um dos
componentes que voc adicionou na View e ento editar seus
atributos na janela do Attribute Inspector conforme podemos
ver na Figura 21.
Figura 19. Tela principal do Interface Builder (1 Document Window; 2
Attributes, Connections, Identity and Size Inspectors Window; 3 Library)
Na Figura 20 ns temos a interface de nossa aplicao parcialmente definida, todos os componentes presentes na paleta de
componentes na janela da direita (Library) podem ser arrastados
e soltados na janela da esquerda, que a janela de nossa aplicao
(View). Observe na Figura 20 a correspondncia entre os componentes da paleta com os componentes adicionados na janela:
1. UILabel: Componente que apresenta um texto. A funo
deste componente ser exibir o rtulo do tipo de dado que
dever ser associado aos outros componentes da tela, como o
UITextField ou o UIPickerView.
2. UITextField: Componente de entrada de dados. Teremos este
componente na janela da nossa aplicao para que digitemos o
dado que ser utilizado no clculo da converso de medidas.
50
WebMobile Magazine - Introduo ao desenvolvimento de aplicaes para o iPhone com o iPhone SDK
M OBILE
Figura 22. Selecionando o recurso que ser mapeado pelo Interface Builder.
51
52
WebMobile Magazine - Introduo ao desenvolvimento de aplicaes para o iPhone com o iPhone SDK
M OBILE
contm a definio de todos os componentes visuais do iPhone (UILabel, UITextField e etc) e o segundo arquivo contm a
definio de classes base do iPhone.
Nas linhas 3 a 12 temos a definio de nossa classe controladora
(ConversorViewController). Na linha 3 estamos declarando a nossa
classe e de quem ela herda. Podemos observar tambm que essa
classe utiliza-se do protocolo UIPickerViewDelegate, que adiciona a
esta classe a capacidade de processar eventos do UIPickerView (que
consiste em um protocolo no Objective-C que o que chamamos
de interface na linguagem Java),especificando mtodos que uma
classe deve implementar. Neste caso, estamos nos referindo a
mtodos que correspondem a eventos de um UIPickerView. Nas
linhas 5 a 10 estamos declarando as variveis dos outlets presentes
na janela da nossa aplicao, indicando tambm a qual componente cada outlet est fazendo referncia. Por ltimo, na linha 11
ns temos a declarao de um mtodo presente nesta classe.
A Listagem 2 contm a implementao da classe que acabamos de declarar.
Na primeira linha estamos importando o arquivo de cabealho que comtm a definio de nossa classe. Nas linhas 2 a
5 onde temos a implementao de nossa classe, sendo que
temos o corpo do mtodo btnConverter_clicked presente nas
linhas 3 a 4.
De posse do cdigo da classe de nossa janela devidamente gerado, ns precisamos agora dar vida nossa aplicao. Para isso,
precisamos fazer algumas modificaes nos cdigo apresentados nas Listagens 1 e 2, conforme descrito na Listagem 3.
Note que diferente do que temos na Listagem 1, a Listagem 3
contm a declarao de trs novas variveis: tiposDeConverso (um
1. import <UIKit/UIKit.h>
#
2. import <Foundation/Foundation.h>
#
3. interface ConversorViewController :
@
UIViewController<UIPickerViewDelegate>{
4.
IBOutlet UIButton
*btnConverter;
5.
IBOutlet UILabel
*lblQuantidade;
6.
IBOutlet UILabel
*lblResultadoConversao;
7.
IBOutlet UILabel
*lblTipoConversao;
8.
IBOutlet UIPickerView *pkvTipoConversao;
9.
IBOutlet UITextField
*txtQuantidade;
10.
NSArray
*tiposDeConversao;
11.
NSInteger
medidaOrigemSelecionada;
12.
NSInteger
medidaDestinoSelecionada;
13. }
14. - (IBAction)btnConverter_clicked;
15. @end
53
21. efault:
d
22.
break;
23. }
24. SString *siglaMedidaDestino = [tiposDeConversao objectAtIndex:
N
medidaDestinoSelecionada];
25. numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[
26. [numberFormatter setDecimalSeparator:@,];
27. [numberFormatter setFormat:@0.00000;0.00000;-0.00000];
28. blResultadoConversao.text = [[[numberFormatter
l
stringFromNumber:resultado] stringByAppendingString:@ ]
stringByAppendingString:siglaMedidaDestino];
29.
}
30. (void)viewDidLoad
31.
{
32. self = [super init];
33. pkvTipoConversao.delegate = self;
34. [self.view addSubview:pkvTipoConversao];
35. tiposDeConversao = [[NSArray arrayWithObjects:
36. Cm, @Metros, @Km, @Milhas, nil] retain];
@
37.
}
38. / Eventos do PickerView...
/
39. end
@
Compilando a aplicao
Na tela principal do Xcode (Figura 18), clique no boto Build,
conforme apresentado na Figura 30.
Caso ocorra algum erro na compilao do projeto as mensagens de erro sero exibidas na parte de baixo da janela.
Concluses
Neste artigo pudemos perceber que o iPhone possui um SDK
bastante completo. A IDE Xcode em conjunto com o Interface Builder torna o desenvolvimento de aplicaes para o iPhone em algo
bastante intuitivo e simples. Acreditamos que tambm foi possvel
perceber que a linguagem Objective-C bastante extica e requer
algum tempo para aprendizado. Sendo assim, basta agora voc ter a
sua idia e transformar ela em uma aplicao para este celular, pois
as ferramentas voc sabe onde as encontrar e como us-las.
D seu feedback sobre esta edio!
54
A Web Mobile tem que ser feita ao seu gosto. Para isso, precisamos saber
o que voc, leitor, acha da revista!
D seu voto sobre este artigo, atravs do link:
www.devmedia.com.br/webmobile/feedback
WebMobile Magazine - Introduo ao desenvolvimento de aplicaes para o iPhone com o iPhone SDK
Resumo do DevMan
J pensou em como o YouTube foi desenvolvido? Neste artigo vamos utilizar recursos do WPF para criar um site semelhante a ele, que permita a incluso de vdeos e
sua visualizao. O WPF traz para o .NET Framework recursos que simplicam a criao de aplicaes que exigem contedo multimdia. Veremos tambm como utilizar
o Linq To Entities para manter a base de dados de vdeos.
Para que possamos desenvolver nosso exemplo Mini YouTube, precisamos de algumas ferramentas instaladas em nosso
ambiente de desenvolvimento. Basicamente o que precisamos
para desenvolver utilizando o XBAP, :
Microsoft Visual Studio 2008 Service Pack 1: O Microsoft Visual
Studio 2008 Service Pack 1 pode ser encontrado no link msdn.
microsoft.com/pt-br/vstudio/default.aspx. importante lembrar
55
Nota do DevMan
A Microsoft no esforo de permitir a seus desenvolvedores a criao de aplicaes com
interfaces ricas, incluiu o WPF em seu .NET Framework. Uma das novidades trazidas a
introduo de scripts em XML para definio das caractersticas da interface. Esse formato
XML envolvido sofreu algumas personalizaes por parte da Microsoft e foi renomeado para
XAML (leia-se zmel). O XAML oferece um forma independente de linguagem de programao de construo de interfaces, permitindo realmente que designers que nunca programaram possam criar uma tima experincia visual sem interferir no cdigo do programa.
Nota
Todas as ferramentas Express da Microsoft podem ser encontradas no link www.microsoft.com/
express.Voc pode baixar o banco de dados Microsoft SQL Server 2008 Express Edition para utilizar
no exemplo, porm no possvel utilizar a verso Express do Visual Studio 2008 porque nela no
est disponvel o recurso de XBAP. Contudo, pode-se baixar a verso Trial do Visual Studio 2008.
56
ASP. NET
Para criar um novo banco de dados, expanda o item DataBases e em seguida clique com o direito nele. Escolha a opo
New DataBase e d o nome de MyVideosShare. Para criarmos
a tabela basta expandirmos o nosso banco de dados criado
e clicar com o direito em Tables selecionando New Table. Em
seguida uma janela ser aberta e agora precisaremos apenas
incluir os campos e seus atributos necessrios. Vamos criar
junto tabela de Vdeos.
Nas propriedades da tabela, em Name, digite o nome da
tabela, Videos, como pode ser visto na Figura 3.
Nota do DevMan
Um dos principais mtodos de desenvolvimento de aplicaes Web garantindo uma
total interao com o ambiente atual e visualmente mais parecido com janelas Windows foi o: Windows Forms. H diversos programadores que gostam ou ainda preferem usar-se dessa tecnologia.
A bem da verdade o Windows Forms no chamou muito a ateno do pblico por
isso tem sido deixado de lado h anos. Basicamente, Windows Forms so janelas bem
semelhantes as do prprio Windows. Podemos fazer exatamente todo tipo de aplicao utilizando esse conceito.
57
Nota do DevMan
O XAML (pronuncia-se zemel) a nova linguagem de marcao usada para criar
interfaces de usurio de forma simples e rpida. equivalente, porm muito mais poderosa que sua antecessora o HTML.
,
O XAML no uma linguagem em si. Ela exatamente como o XML, que no contm
nenhuma tag especfica, mas apenas as regras para crias suas prprias tags. O XAML
tambm a forma de marcao para acessar o modelo de objetos do novo Windows
Presentation Foundation e voc pode ainda criar seus prprios objetos e acess-los
atravs do XAML.
<Page x:Class=MyVideosShare.Page1
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
Title=Page1>
<Grid>
</Grid>
</Page>
58
ASP. NET
Nota do DevMan
O Windows Presentation Foundation (ou WPF), anteriormente sob o nome de cdigo
Avalon, um subsistema grfico .net Framework 3.0 (anteriormente chamada WinFX),
e est diretamente relacionado ao XAML. WPF est includo com o Windows Vista e
Windows Server 2008, e tambm est disponvel para Windows XP Service Pack 2 ou
superior, e Windows Server 2003. Ele oferece um modelo de programao coerente para
a construo de aplicaes e fornece uma clara separao entre a interface do usurio e
da lgica comercial (regras de negcios).
A WPF pode ser implantado na rea de trabalho ou hospedado em um navegador Web.
Por outro lado, permite controlar o desenvolvimento dos aspectos visuais de programas do
Windows. Ela visa unificar uma srie de servios de aplicao: interface de usurio, desenho
2D e 3D, documentos, tipografia avanada, grficos vetoriais, udio e vdeo. Embora Windows Forms continuar a ser largamente utilizada, e a Microsoft criou apenas algumas aplicaes WPF, a empresa promove WPF para a linha de aplicativos corporativos.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=112 />
<RowDefinition Height=* />
<RowDefinition Height=30 />
</Grid.RowDefinitions>
Nota
Antes de comear a codificao da tela temos que entender que o WPF no se utiliza uma
medida especfica de tamanho como por exemplo, o pixel. Utiliza-se uma medida varivel
que depende da densidade de pixels na tela, ou seja, vamos supor que deixemos o nosso
monitor configurado para 800x600 e definimos um boto de 100x100, este boto ir ocupar
certa proporo da tela. Ento aumentamos a nossa resoluo para 1024x768. Veremos o
mesmo boto ocupando 100x100 de forma proporcional. Se nossa medida de tamanho
fosse em pixels, no importaria a resoluo, o boto teria sempre o mesmo tamanho, porm
como nossa medida em relao a densidade de pixels, vamos perceber que este boto ir
aumentar ou diminuir dependendo da resoluo, ocupando proporcionalmente sempre o
mesmo espao na tela.
59
Veja que na definio da largura das colunas no foi especificado nenhum tamanho, apenas informamos o asterisco. Ao
executar a aplicao o Framework quando se deparar com esse
cdigo ir entender que para dividir a largura das colunas
em partes iguais.
Agora vamos adicionar o objeto MediaElement, dando a ele o
nome de mePlayer e ajustando sua margem para 10. Tambm
vamos adicionar um ListBox que ficar localizado na segunda
coluna do grid e vamos definir seu nome como lstVideos.O
cdigo de tudo isso est na Listagem 4.
Listagem 4. Dividindo o grid ao meio
01 <TabItem Header=Inicio Name=tabInicio>
02
<Grid>
03
<Grid.ColumnDefinitions>
04
<ColumnDefinition Width=* />
05
<ColumnDefinition Width=* />
06
</Grid.ColumnDefinitions>
07
<MediaElement Margin=10 Name=mePlayer />
08
<ListBox Grid.Column=1 HorizontalAlignment=Stretch
09
Margin=10 Name=lstVideos Width=Auto />
10
</Grid>
11 </TabItem>
Nota do DevMan
O WPF por ser uma evoluo no desenvolvimento de interfaces, favorece o uso de controles layouts para a organizao e disposio de qualquer controle a ser inserido em uma
janela ou pgina. A vantagem em se utilizar esses controles est no fato de garantirem a
boa esttica da interface por no estarem presos posies fixas em pixels.Dessa forma no
importa com qual resoluo o monitor do cliente vai estar, o visual da sua aplicao sempre
estar organizado. Existem os seguintes controles:
DockPanel Permite ancorar os controles inseridos nele;
StackPanel Ao inserir controles em um StackPanel, os mesmos so empilhados, seja na
vertical ou horizontal;
WrapPanel Realiza uma quebra automtica do controles de acordo com o tamanho disponvel do WrapPanel onde esto inseridos, podendo organiz-los de forma automtica;
Grid Disponibiliza uma organizao de layout no formato tabular, linhas e colunas;
Canvas Utiliza posies fixas, em pixels, para o posicionamento dos controles, similar ao
que existe no windowsforms.
60
ASP. NET
exemplo que nele j possvel utilizar o conceito de Herana. Ento para que possamos trabalhar com o Linq To Entities
vamos adicionar ao nosso projeto um arquivo .edmx que o
arquivo de mapeamento da nossa base de dados para o Linq,
Clique com o boto direito do mouse sobre o projeto e selecione
a opo Add>New Item, conforme Figura 8.
61
62
ASP. NET
o objeto de tipo Vdeo, que foi gerado pelo Linq. Ento passamos
para esse objeto os valores digitados pelo usurio.
Como pode ser visto temos a chamada de um mtodo chamado UploadVideo() que tem a responsabilidade de carregar o
arquivo para nossa pgina no servidor. Mas antes de mostrar
como ele funciona, temos que criar, definir onde este arquivo
ser gravado no servidor. Neste exemplo estou utilizando
o seguinte caminho, C:\DevMedia\MyVideosShare\Videos,
lembrando que esta pasta dever ter permisso de gravao.
Agora vamos adicionar este caminho como uma configurao
do nosso projeto, clicando com o boto direito no seu projeto
e selecionando Properties. Na guia Settings adicione esta configurao da seguinte forma:
Name = PathOnServer;
Type = string;
Scope = Application;
Value = C:\DevMedia\MyVideosShare\Videos;
Como mostrado na Figura 14.
As configuraes de projeto permitem que possamos armazenar
e recuperar informaes necessrias para o programa de forma
dinmica. Ao determinar que o escopo de visualizao dessa configurao Application isso a torna visvel por todo o projeto.
Voltando agora para o nosso mtodo de upload, temos a
Listagem 6.
Criamos uma instncia da classe WebClient, que disponibiliza mtodos para o evio e recebimento de dados de qualquer
recurso que esteja local, em uma intranet ou na internet. A
seguir criamos o nome do arquivo que ser salvo no servidor
baseando-se na hora atual, isso para evitar que um vdeo
possa sobrescrever outro. Depois verificamos a permisso de
escrita na pasta especificada na configurao do sistema. Para
verificarmos as permisses de acesso a uma pasta utilizamos
return fileName;
63
System.Windows.Forms. Feito isso, o normal seria referencila tambm na seo using, contudo se fizermos isso alguns
conflitos surgem com com outros namespaces do WPF. D um
duplo clique no boto adicionar e ser criado o evento Click,
nele adicionamos o cdigo da Listagem 7.
Nota
Poderamos utilizar tambm o UploadFileAsync() que tem a mesma funo do UploadFile(),
porm funciona de uma forma assncrona, ou seja no necessrio esperar a execuo desse
mtodo para continuar o processo, ele executado em segundo plano.
Listagem 8. DataTemplate
64
01 <Page.Resources>
02
<DataTemplate x:Key=tmpListas>
03
<StackPanel>
04
<Label>
05
<Label.Content>
06
<WrapPanel HorizontalAlignment=Stretch>
07
<TextBlock>Ttulo: </TextBlock>
08
<TextBlock Text={Binding
TituloVideo} />
09
</WrapPanel>
10
</Label.Content>
11
</Label>
12
<Label>
13
<Label.Content>
14
<WrapPanel HorizontalAlignment=Stretch>
15
<TextBlock>Postado por: </TextBlock>
16
<TextBlock Text={Binding PostadoPor} />
17
</WrapPanel>
18
</Label.Content>
19
</Label>
20
<Label>
21
<Label.Content>
22
<WrapPanel HorizontalAlignment=Stretch>
23
<TextBlock>Postado em: </TextBlock>
24
<TextBlock Text={Binding DataPost} />
25
</WrapPanel>
26
</Label.Content>
27
</Label>
28
</StackPanel>
29
</DataTemplate>
30
</Page.Resources>
ASP. NET
Listagem 9. SelectionChanged
Concluso
Como podemos ver, trabalhar com vdeos em WPF muito
simples, no requerendo muita codificao. Dependendo da
forma que ser apresentado o vdeo talvez no seja preciso
nenhuma linha de cdigo, porm trabalhamos com este objeto
de uma forma bem superficial, temos dentro dele recursos
para criar os botes de Play, Pause, Stop. Podemos controlar a
velocidade de execuo do vdeo, volume do udio e muitas
outras propriedades.
Aqui vimos tambm como simples o processo para realizar
um upload de arquivos para o servidor e por fim vimos um
pouco de Linq To Entities, que um recurso muito interessante
de se utilizar.
D seu feedback sobre esta edio!
A Web Mobile tem que ser feita ao seu gosto. Para isso, precisamos saber
o que voc, leitor, acha da revista!
D seu voto sobre este artigo, atravs do link:
www.devmedia.com.br/webmobile/feedback
65
Maximize a qualidade
do seu cdigo
Como medir o quanto o seu teste
unitrio cobre do cdigo
66
Resumo do DevMan
Desenvolver um sistema perfeito o ideal de todo programador e o sonho de cada
cliente. Neste artigo vamos ver como aproximar seu desenvolvimento de um cdigo
ideal atravs de uma anlise baseada em exemplos e testes.
Usaremos NUnit e NCover para efetuar os testes e verificar o quo simples utilizar-se de testes unitrios.
ASP. NET
Mo na massa!
Vamos supor o seguinte cenrio: estamos fazendo um sistema
corporativo. Somos os responsveis pela camada cliente contida neste sistema. Este objeto o responsvel por representar
todos os clientes da corporao. Para este desenvolvimento,
utilizei o Visual Studio 2005 com VB.NET. Outras verses poderiam ser utilizadas.
Abra ento o Visual Studio e crie um projeto de classe. Na
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
m_sEndereco = value
End Set
End Property
Private m_sNumero As String
Public Property Numero() As String
Get
Return m_sNumero
End Get
Set(ByVal value As String)
m_sNumero = value
End Set
End Property
Private m_sCEP As String
Public Property CEP() As String
Get
Return m_sCEP
End Get
Set(ByVal value As String)
m_sCEP = value
End Set
End Property
Private m_iPaisID As Integer
Public Property PaisID() As Integer
Get
Return m_iPaisID
End Get
Set(ByVal value As Integer)
m_iPaisID = value
End Set
End Property
Private m_iCidadeID As Integer
Public Property CidadeID() As Integer
Get
Return m_iCidadeID
End Get
Set(ByVal value As Integer)
m_iCidadeID = value
End Set
End Property
Private m_bAtivo As Boolean
...
67
68
ASP. NET
69
70
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
oCliente.Ativo = bAtivo
oCliente.CidadeID = iCidadeID
oCliente.PaisID = iPaisID
oCliente.CEP = sCEP
oCliente.Numero = sNumero
oCliente.Endereco = sEndereco
oCliente.CNPJ = sCNPJ
oCliente.Nome = sNome
oCliente.InvestimentoMensal = dInvestimentoMensal
oCliente.RetornoMensal = dRetornoMensal
ASP. NET
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
End Sub
<summary>
Mtodo que verifica testa a validao do e-mail.
</summary>
<remarks></remarks>
<Test(description:=Mtodo que teste a validao do e-mail)> _
Public Sub verificarValidacaoEmail()
Dim oCliente As New Cliente
Dim bResultado As Boolean
Teste de quado no for email vlido
bResultado = oCliente.validarEmail(NaoEmail)
Assert.AreNotEqual(True, bResultado)
Teste de quado for email vlido
bResultado = oCliente.validarEmail(thomas.semple@t4w.com.br)
Assert.AreEqual(True, bResultado)
End Sub
1
2
3
4
5
6
7
Um pouco de filosofia
Por que ento utilizar teste unitrio e verificar se ele cobre 100%
do cdigo se mesmo assim no garantia de um sistema perfeito?
Esta uma excelente pergunta. Muitos dizem que desenvolver
software uma arte. Outros dizem que uma cincia. Eu prefiro
acreditar que o software existe para facilitar a vida de outras
pessoas, para impulsionar negcios ou para reduzir custos. Ns
programadores investimos horas e horas para que outras pessoas
economizem, para que elas possam fazer operaes mais fceis,
e dedicar-se no que realmente so boas em fazer.
71
72
ASP. NET
Concluso
<project default=code-coverage>
<property value=.\NCover\Resultado.xsl name=ncover.
stylesheet/>
<property value=C:\Arquivos de programas\NCover\ncover.
console.exe name=ncover.executable/>
<property value=.\NUnit\nunit-console.exe name=nunit.
console/>
<property value=C:\MeusProjetos\Solucoes name=projects.
output.dir/>
<target name=code-coverage>
<foreach property=test.assembly.folder item=Folder>
<in>
<items>
<include name=${projects.output.dir}\*Test/>
</items>
</in>
<do>
<regex input=${test.assembly.folder}
pattern=^.*(\\/)(?asmregex.*)$>
<property value=${asmregex} name=assembly.test.
name/>
<property value=${string::replace(asmregex,.
Test,)}name=assembly.under.test.name/>
<property value=${projects.output.dir}\${assembly.
test.name}\bin\Debug\${assembly.test.name}.dll
//l Reports\Coverage.Log //a ${assembly.under.
test.name} name=ncover.path.arg/>
<exec commandline=${nunit.console} ${ncover.path.
arg} program=${ncover.executable}/>
<style style={ncover.stylesheet}
out=Reports\${assembly.under.test.name}-Coverage.html
in=Coverage.xml$>
</do>
</foreach>
</target>
</project>
73
Manipulao de dados
atravs do Silverlight
com Astoria
Criao de proxy para o ADO.NET
Data Services com IUpdatable para
Silverlight
Resumo do DevMan
De que se trata o artigo
Implementao da interface IUpdatable;
Criao de servios ADO.NET (Web Service REST);
Criao de um proxy para manipulao de servios ADO.NET;
Como consumir e manipular informaes atravs do Silverlight de forma assncrona.
Para que serve
Manipular informaes atravs do Silverlight com servios ADO.NET de forma assncrona.
Em que situao o tema til
Em projetos j em produo que no utilizam o Entity Framework e que
precisam consumir informaes atravs de web service.
74
asp.net
www.devmedia.com.br/webmobile
Acesse agora mesmo o portal do assinante WebMobile e veja uma vdeo aula de Rodrigo Sendin que mostra
como instalar e criar um modelo objeto-relacional utilizado o Entity Framework.
http://www.devmedia.com.br/articles/viewcomp.asp?comp=9472
Nota do DevMan
O JSON, ou JavaScript Object Notation, um formato leve para troca de informaes. Ele fcil de ser compreendido sem o auxlio de sistemas especficos. Baseado
em um subconjunto do JavaScript, sua estrutura fcil de ser analisada pelos mais
diversos sistemas e tecnologias como Java, Ruby, .NET e Delphi. Isso porque constitudo de texto simples, que completamente ignorante s linguagens de desenvolvimento. Por isso uma forma ideal de realizar intercmbio de informaes entre
sistemas distintos onde seria impossvel uma troca direta.
Mos obra
Para criar um sistema utilizando o Astoria necessrio instalar o .net 3.5 SP1 do .NET Framework e do Visual Studio 2008. Para
efetuar o download procure por Download .net 3.5 sp1 no seu
mecanismo de busca favorito, ou acesse o site da Microsoft.
Abra o Visual Studio e crie uma nova soluo em branco,
utilizando o Framework 3.5, conforme a Figura 1.
Adicione um novo Web Site na soluo, conforme Figura 2.
Tambm utilize o Framework 3.5 e a linguagem VB.NET. Se
quiser desenvolver em C# fique a vontade. Nomeie o Web Site
de ChatSLWS. Adicione agora mesma soluo o projeto chamado SL, conforme Figura 3.
Observe que selecionamos um projeto do tipo Silverlight. Na
prxima tela, deixe do modo padro, de forma a vincular a
aplicao Silverlight ao Web Site.
Para continuar o desenvolvimento, necessrio verificar se
todas as referncias s bibliotecas externas esto corretas. Na
Figura 4, exibo todas as referncias necessrias para o Website.
Caso alguma esteja faltando ao seu projeto, adicione-a clicando com o boto direito em cima do projeto, e selecionando
a opo Add Reference.
75
76
asp.net
dcMensagens.AutoIncrementStep = 1
dcMensagens.Unique = True
m_dtMensagens.Columns.Add(dcMensagens)
dcMensagens = New Data.DataColumn(System.String)
dcMensagens.ColumnName = Mensagem
m_dtMensagens.Columns.Add(dcMensagens)
dcMensagens = New Data.DataColumn(System.DateTime)
dcMensagens.ColumnName = DataHora
m_dtMensagens.Columns.Add(dcMensagens)
dcMensagens = New Data.DataColumn(System.Int32)
dcMensagens.ColumnName = UsuarioID
m_dtMensagens.Columns.Add(dcMensagens)
drMensagem = m_dtMensagens.NewRow
drMensagem(ID) = m_dtMensagens.Rows.Count + 1
drMensagem(Mensagem) = Ol, seja bem vindo ao chat!
drMensagem(DataHora) = Date.Now
drMensagem(UsuarioID) = 1 sistema
m_dtMensagens.Rows.Add(drMensagem)
If Not Arquivo.Exists(m_sArquivoXSD) Then
m_dtMensagens.WriteXmlSchema(m_sArquivoXSD)
End If
If Not Arquivo.Exists(m_sArquivoXML) Then
m_dtMensagens.WriteXml(m_sArquivoXML)
End If
End Sub
Public Sub carregarMensagens()
For Each dr As Data.DataRow In m_dtMensagens.Rows
Dim oMensagem As New Conversa
oMensagem.ID = CType(dr(ID), Integer)
oMensagem.DataHora = CType(dr(DataHora), DateTime)
oMensagem.Mensagem = Convert.ToString(dr(Mensagem))
oMensagem.UsuarioID = CType(dr(UsuarioID), Integer)
m_cMensagens.Add(oMensagem)
Next
End Sub
#End Region
77
78
End Function
Public Sub SaveChanges() Implements
System.Data.Services.IUpdatable.SaveChanges
Dim drMensagem As Data.DataRow
Dim bAdicionar As Boolean = False
For Each oConversa As Conversa In Mensagens
bAdicionar = True
For Each drConversaSalva As Data.DataRow In
m_dtMensagens.Rows
If drConversaSalva(ID) = oConversa.ID Then
bAdicionar = False
Exit For
End If
Next
If bAdicionar Then
drMensagem = m_dtMensagens.NewRow
drMensagem(ID) = m_dtMensagens.Rows.Count + 1
drMensagem(DataHora) = oConversa.DataHora
drMensagem(Mensagem) = oConversa.Mensagem
drMensagem(UsuarioID) = oConversa.UsuarioID
m_dtMensagens.Rows.Add(drMensagem)
End If
Next
m_dtMensagens.WriteXml(m_sArquivoXML)
End Sub
Public Sub SetReference(ByVal targetResource As Object, ByVal
propertyName As String, ByVal propertyValue As Object) Implements
System.Data.Services.IUpdatable.SetReference
Throw New NotImplementedException()
End Sub
Public Sub AddReferenceToCollection(ByVal targetResource As
Object,
ByVal propertyName As String, ByVal resourceToBeAdded As Object)
Implements System.Data.Services.IUpdatable.
AddReferenceToCollection
Throw New NotImplementedException()
End Sub
Public Sub ClearChanges() Implements
System.Data.Services.IUpdatable.ClearChanges
Throw New NotImplementedException()
End Sub
Public Sub RemoveReferenceFromCollection(ByVal targetResource
As
Object, ByVal propertyName As String, ByVal resourceToBeRemoved
As
Object) Implements
System.Data.Services.IUpdatable.RemoveReferenceFromCollection
Throw New NotImplementedException()
End Sub
Public Function ResetResource(ByVal resource As Object) As
Object
Implements System.Data.Services.IUpdatable.ResetResource
Throw New NotImplementedException()
End Function
#End Region
End Class
asp.net
79
Nota
Observe que no endereo da pgina existe um nmero de porta, definido logo aps a palavra
localhost. Esse nmero aleatrio e obtido automaticamente pelo Visual Studio quando a
aplicao roda a partir dele. Tambm, para visualizar o XML contendo as mensagens, pode ser
necessrio desabilitar o leitor de feeds automtico de Internet Explorer.
Nota do DevMan
O Proxy na verdade um padro de projeto que oferece uma referncia a um
objeto que possui a real implementao. Ele encapsula o objeto real no expondo
toda sua complexidade. Neste exemplo temos a classe Mensagem que atua como um
Proxy. Ela est encapsulando o acesso aos servios do Astoria.
Acesse agora mesmo o portal do assinante WebMobile e veja uma vdeo aula de Euclides Loureno Chuma que
mostra como criar uma aplicao Silverlight utilizando o Microsoft Expression Blend.
http://www.devmedia.com.br/articles/viewcomp.asp?comp=6589
80
asp.net
Deixei sem tipo de forma proposital, para dar uma breve introduo em tipos annimos. Esse recurso foi introduzido recentemente
na plataforma .Net e possibilita que, embora no tenha sido declarado o tipo da varivel durante a declarao, ela no seja tratada
como um objeto e sim uma String, ou outro tipo, de acordo com
o que for atribudo a ela. Neste caso ento a varivel ser tratada
como String. O prximo mtodo a ser criado o construtor da
classe. O Mtodo New(), apenas define a varivel m_cConversa
como uma nova ObservableCollection de Conversa.
O mtodo responsvel por atualizar as mensagens o atualizarMensagens(). Ele utiliza-se de uma consulta Linq, selecionando todas as mensagens com o ID maior que zero. Fiz esta
pesquisa apenas por fins didticos, mostrando como voc pode
<LinearGradientBrush EndPoint=0.5,1
StartPoint=0.5,0>
<GradientStop Color=#FF565353/>
<GradientStop Color=#FFD7D4D4 Offset=0.513/>
<GradientStop Color=#FF565555 Offset=1/>
</LinearGradientBrush>
</ListBox.Background>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation=Horizontal Margin=5>
<TextBlock FontSize=12 Text={Binding ID}
Foreground=#FF000000/>
<TextBlock Text=>> />
<TextBlock FontSize=12 Text={Binding
Mensagem}/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Height=21 Margin=28,8,42,0
VerticalAlignment=Top
Text=Proxy com Astoria e Silverlight com
IUpdatable
TextWrapping=Wrap Foreground=#FFF40000
FontWeight=Bold FontFamily=Portable User
Interface
FontSize=12/>
</Grid>
</UserControl>
filtrar uma informao de modo simples. Por de baixo dos panos o que ocorre que esta consulta do Linq transformada em
uma pesquisa pela prpria URL, seguindo os padres de filtro
do Astoria. Este filtro possvel graas interface IQueryable
utilizada na Listagem 2, que absorve todo o trabalho rduo
que seria implementar o filtro com tecnologias anteriores.
Como toda chamada no Silverlight ao servidor feita de
forma assncrona, torna-se necessrio criar o mtodo atualizarCallBack(), que recebe como parmetro a varivel iar do tipo
IAsyncResult. Nele criada uma varivel de query que recebe o
resultado a operao assncrona, que ento atribuda lista
de mensagens. Essa lista ento exibida na ListBox atravs
do comando LBMensagens.DataContext = m_cConversa. Um
81
82
Concluso
Com este artigo vimos como implementar a classe IUpdatable
e como criar um proxy para consumir o servio Astoria utilizando uma aplicao Silverlight. O importante, muito mais do
que a aplicao neste artigo, o conceito que est por trs. A
tecnologia REST permite integrao de sistemas de diferentes
plataformas de modo simples, pois utiliza somente o http e
seus mtodos nativos. Como dica de estudo fica a criao de
modelos utilizando Entity Framework sendo disponibilizados
pelo Astoria. O Silverlight certamente abre aos desenvolvedores uma nova forma de programao web. Com certeza as
funcionalidades atuais so apenas o comeo desta promissora
tecnologia. Forte abrao e at o prximo artigo.
D seu feedback sobre esta edio!
A Web Mobile tem que ser feita ao seu gosto. Para isso, precisamos saber
o que voc, leitor, acha da revista!
D seu voto sobre este artigo, atravs do link:
www.devmedia.com.br/webmobile/feedback
asp.net
83
84