Você está na página 1de 164

Mdulo 5

Desenvolvimento de Aplicaes Mveis

Lio 1
Introduo

Verso 1.0 - Set/2007


JEDITM

Autor Necessidades para os Exerccios


A. Oliver de Guzman Sistemas Operacionais Suportados
NetBeans IDE 5.5 para os seguintes sistemas operacionais:
Microsoft Windows XP Profissional SP2 ou superior
Mac OS X 10.4.5 ou superior
Equipe Red Hat Fedora Core 3
Rommel Feria Solaris 10 Operating System (SPARC e x86/x64 Platform Edition)
John Paul Petines NetBeans Enterprise Pack, poder ser executado nas seguintes plataformas:
Microsoft Windows 2000 Profissional SP4
Solaris 8 OS (SPARC e x86/x64 Platform Edition) e Solaris 9 OS (SPARC e
x86/x64 Platform Edition)
Vrias outras distribuies Linux

Configurao Mnima de Hardware


Nota: IDE NetBeans com resoluo de tela em 1024x768 pixel
Sistema Operacional Processador Memria HD Livre
Microsoft Windows 500 MHz Intel Pentium III 512 MB 850 MB
workstation ou equivalente
Linux 500 MHz Intel Pentium III 512 MB 450 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC II 450 MHz 512 MB 450 MB
Solaris OS (x86/x64 AMD Opteron 100 Srie 1.8 GHz 512 MB 450 MB
Platform Edition)
Mac OS X PowerPC G4 512 MB 450 MB

Configurao Recomendada de Hardware

Sistema Operacional Processador Memria HD Livre


Microsoft Windows 1.4 GHz Intel Pentium III 1 GB 1 GB
workstation ou equivalente
Linux 1.4 GHz Intel Pentium III 1 GB 850 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC IIIi 1 GHz 1 GB 850 MB
Solaris OS (x86/x64 AMD Opteron 100 Series 1.8 GHz 1 GB 850 MB
Platform Edition)
Mac OS X PowerPC G5 1 GB 850 MB

Requerimentos de Software
NetBeans Enterprise Pack 5.5 executando sobre Java 2 Platform Standard Edition
Development Kit 5.0 ou superior (JDK 5.0, verso 1.5.0_01 ou superior), contemplando
a Java Runtime Environment, ferramentas de desenvolvimento para compilar, depurar,
e executar aplicaes escritas em linguagem Java. Sun Java System Application Server
Platform Edition 9.
Para Solaris, Windows, e Linux, os arquivos da JDK podem ser obtidos para
sua plataforma em http://java.sun.com/j2se/1.5.0/download.html
Para Mac OS X, Java 2 Plataform Standard Edition (J2SE) 5.0 Release 4, pode
ser obtida diretamente da Apple's Developer Connection, no endereo: http://
developer.apple.com/java ( necessrio registrar o download da JDK).

Para mais informaes: http://www.netbeans.org/community/releases/55/relnotes.html

Desenvolvimento de Aplicaes Mveis 2


JEDITM

Colaboradores que auxiliaram no processo de traduo e reviso


Acio Jnior Fbio Bombonato Luiz Fernandes de Oliveira Junior
Alexandre Mori Fabrcio Ribeiro Brigago Marco Aurlio Martins Bessa
Alexis da Rocha Silva Francisco das Chagas Maria Carolina Ferreira da Silva
Allan Souza Nunes Frederico Dubiel Massimiliano Giroldi
Allan Wojcik da Silva Herivelto Gabriel dos Santos Mauro Cardoso Mortoni
Anderson Moreira Paiva Jacqueline Susann Barbosa Paulo Afonso Corra
Andre Neves de Amorim Joo Vianney Barrozo Costa Paulo Oliveira Sampaio Reis
Angelo de Oliveira Kefreen Ryenz Batista Lacerda Pedro Henrique Pereira de Andrade
Antonio Jose R. Alves Ramos Kleberth Bezerra G. dos Santos Ronie Dotzlaw
Aurlio Soares Neto Leandro Silva de Morais Seire Pareja
Bruno da Silva Bonfim Leonardo Ribas Segala Sergio Terzella
Carlos Fernando Gonalves Lucas Vincius Bibiano Thom Vanessa dos Santos Almeida
Denis Mitsuo Nakasaki Luciana Rocha de Oliveira Robson Alves Macdo

Auxiliadores especiais

Reviso Geral do texto para os seguintes Pases:


Brasil Tiago Flach
Guin Bissau Alfredo C, Bunene Sisse e Buon Olossato Quebi ONG Asas de Socorro

Coordenao do DFJUG

Daniel deOliveira JUGLeader responsvel pelos acordos de parcerias


Luci Campos - Idealizadora do DFJUG responsvel pelo apoio social
Fernando Anselmo - Coordenador responsvel pelo processo de traduo e reviso,
disponibilizao dos materiais e insero de novos mdulos
Rodrigo Nunes - Coordenador responsvel pela parte multimdia
Srgio Gomes Veloso - Coordenador responsvel pelo ambiente JEDITM (Moodle)

Agradecimento Especial
John Paul Petines Criador da Iniciativa JEDITM
Rommel Feria Criador da Iniciativa JEDITM

Desenvolvimento de Aplicaes Mveis 3


JEDITM

1. Objetivos
Nesta lio, discutiremos as caractersticas dos dispositivos mveis e a forma de iniciar o
desenvolvimento de aplicaes para estes dispositivos. Realizaremos uma introduo Java
Platform, Micro Edition (Java ME) incluindo a importncia das configuraes e perfis.

Ao final desta lio, o estudante ser capaz de:


Identificar as caractersticas dos dispositivos mveis
Descrever a arquitetura JME
Conhecer a personalizao das configuraes e perfis (CLDC e CDC)
Identificar as bibliotecas fornecidas pelo MIDP
Descrever o ciclo de vida de um MIDlet

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. Dispositivos Mveis
Dispositivos mveis podem variar em tamanho, projeto e layout, mas eles possuem algumas
caractersticas em comum que so totalmente diferentes de sistemas desktop.
Pequenos em tamanho
Dispositivos mveis so pequenos em tamanho. Consumidores desejam dispositivos pequenos
pela mobilidade e convenincia.

Memria Limitada
Dispositivos mveis tambm possuem pouca memria, tanto primria (RAM) quanto
secundria (disco). Esta limitao um dos fatores que afetam a escrita de classes para estes
tipos de dispositivos. Com quantidade limitada de memria, devemos fazer consideraes
especiais acerca da conservao no uso de recursos preciosos.

Poder de processamento limitado


Sistemas mveis no so poderosos como so os sistemas desktop quanto a sua organizao.
Tamanho, tecnologia e oramento so alguns dos fatores que influenciam a condio desses
recursos. Como o disco de armazenamento e RAM, apenas pequenos pacotes se adequam a
estes recursos.
Baixo consumo de energia
Dispositivos mveis possuem baixo consumo de energia em relao s mquinas desktop.
Estes dispositivos necessitam poupar o uso de energia, pois possuem um limitado
abastecimento atravs de baterias.
Robusto e confivel
Por serem dispositivos mveis provavelmente sero carregados. Precisam ser robustos o
suficiente para suportarem a fora de impacto, movimento e ocasionalmente quedas.
Conectividade limitada
Dispositivos mveis tm baixa largura de banda, alguns deles no suportam conexo. Outros
destes usam conexes de rede sem fio.
Curto tempo de inicializao
Estes dispositivos inicializam-se em segundos. Tomemos o caso de telefones mveis: eles se
iniciam em segundos e as pessoas no ficam com estes desligados mesmo noite. PDAs
inicializam no segundo em que pressionado o boto de ligar.

Desenvolvimento de Aplicaes Mveis 5


JEDITM

3. Viso sobre a Java ME


3.1. Plataforma Java

Java foi criado em 1991 por James Gosling, da Sun Microsystems. Inicialmente chamada de OAK,
em homenagem a rvore que ficava do lado de fora vista da janela de Gosling, este nome foi
modificado para Java porque j existia uma linguagem chamada OAK.

A motivao original para Java estava na necessidade para uma linguagem independente de
plataforma que fosse embarcada em vrios produtos eletrnicos de consumo como torradeiras e
refrigeradores. Um dos primeiros projetos desenvolvidos usando Java foi um controle remoto
pessoal chamado de Star 7.

Nessa mesma direo, e ao mesmo tempo, a World Wide Web e a Internet estavam ganhando
popularidade. Gosling tornava Java capaz de ser usada para a programao para Internet.

Com o lanamento da verso 1.2, a plataforma Java foi classificada em vrias plataformas: Java
Standard Edition (Java SE), Java Enterprise Edition (Java EE), Java Micro Edition (Java ME) e Java
Card API.

Java SE Java Platform, Standard Edition aplicaes desktop


Java EE Java Platform, Enterprise Edition aplicaes corporativas com nfase no modelo de
desenvolvimento server-side incluindo servlets, JSP,
EJB e XML
Java ME Java Platform, Micro Edition mveis e dispositivos de mo
JavaCard Cartes com chip

Servidores
Servers
Mquinas
desktop
Dispositivos
Pacotes
Opcionais
de alto
consumo Dispositivos
Pacotes
de baixo
Opcionais consumo

Cartes
com chip
Java EE Personal Profile
Java SE
Foundation Profile MIDP

Java
CDC CLDC
Card

Mquina Virtual Java KVM Card VM

Java Micro Edition (Java ME)

Figura 1: A plataforma Java

Desenvolvimento de Aplicaes Mveis 6


JEDITM

3.2 Viso Geral do JME

A Plataforma Java Micro Edition (Java ME) um conjunto de especificaes e tecnologias que tm
o foco em dispositivos pessoais. Estes dispositivos tm uma quantidade limitada de memria,
menor poder de processamento, pequenas telas e baixa velocidade de conexo.
Com a proliferao dos dispositivos pessoais, desde telefones, PDAs, videogames portteis a
aplicaes domsticas, Java fornece um nico ambiente porttil de desenvolvimento e execuo
destes dispositivos.
Classes JME, assim como todas as classes Java, so interpretadas. Elas so compiladas em byte
codes e interpretadas por uma Mquina Virtual Java (JVM). Isto significa que estas classes no
so afetadas pelas peculiaridades de cada dispositivo. O JME fornece uma interface consistente
com os dispositivos. As aplicaes no tm que ser recompiladas para poderem ser executadas
em diferentes aparelhos.
No ncleo do JME esto uma configurao e perfis. Uma configurao define um ambiente de
execuo bsico para um sistema JME. Isto define as caractersticas das bibliotecas principais, da
mquina virtual, segurana e comunicao em rede.

Aplicaes

Pacotes OEM
Perfis
Opcionais APIs
Bibliotecas
Configurao {
Mquina Virtual Java

Sistema Operacional do Dispositivo

Figura 2: Arquitetura do JME

Um perfil adiciona uma biblioteca para certas classes de dispositivos. Os perfis fornecem
bibliotecas da API de interface com o usurio, persistncia e mensagens, entre outras.
Um conjunto ou pacote opcional de bibliotecas que fornecem classes funcionais adicionais. A
incluso destes pacotes no JME pode variar porque depende da capacidade do dispositivo. Por
exemplo, alguns dispositivos MIDP no possuem Bluetooth, logo as APIs de Bluetooth no so
includas nestes dispositivos.

3.3 Configurao

Uma configurao define caractersticas mnimas de um ambiente de execuo Java completo.


Para garantir tima portabilidade e interoperabilidade entre vrios tipos de requisitos de recursos
de dispositivos (restries de memria, processador e conexo), as configuraes no contm as
mesmas caractersticas opcionais. Uma configurao JME define um complemento mnimo da
tecnologia Java. Ela baseia-se nos perfis para definir bibliotecas adicionais (opes possveis) para
uma determinada categoria de dispositivo.
Uma configurao define:
o subconjunto da linguagem de programao Java
a funcionalidade da Mquina Virtual Java (JVM)
bibliotecas do ncleo da plataforma
caractersticas de segurana e comunicao em rede

Desenvolvimento de Aplicaes Mveis 7


JEDITM

3.4 Perfis

Um perfil define um conjunto adicional de bibliotecas e caractersticas de empresas, de categoria,


de dispositivo ou de indstria. Enquanto uma configurao define uma base de bibliotecas, perfis
definem as bibliotecas que so importantes para construir aplicaes efetivas. Estas bibliotecas
incluem a interface com o usurio, comunicao em rede e classes de armazenamento.

Desenvolvimento de Aplicaes Mveis 8


JEDITM

4. CLDC
A Configurao de Dispositivos de Conexo Limitada (Connected Limited Device Configuration
CLDC) define e enderea as seguintes reas:
Caractersticas da linguagem Java e Mquina Virtual (JVM)
Bibliotecas de ncleo (java.lang.*, java.util.*)
Input/Output (java.io.*)
Segurana
Comunicao em rede
Internacionalizao

4.1. Caractersticas Removidas

Algumas caractersticas do JSE que foram removidas do CLDC:


finalizao de instncias de classes
excees assncronas
algumas classes de erros
carregadores de classes definidas pelo usurio
reflexo
Java Native Interface (JNI)
grupos de processos e processos daemon
Reflexo, Java Native Interface (JNI) e carregadores de classes definidas pelo usurio so
potenciais falhas de segurana. JNI exigem muita memria e pode no ser suportada por
dispositivos mveis de pouca memria.

4.2. Caractersticas dos Dispositivos CLDC

Os dispositivos atingidos pelo CLDC possuem estas caractersticas:


no mnimo 192kb de memria para a plataforma Java (160kb de memria no-voltil para
Mquina Virtual e bibliotecas e 32kb de memria voltil para execuo da Mquina Virtual)
processador de 16 ou 32 bits
baixo consumo de energia (normalmente os que utilizam baterias)
conexo limitada ou intermitente com velocidade tambm limitada (normalmente wireless)
A CLDC no define instalao da aplicao e ciclo de vida, interfaces com o usurio e tratamento
de eventos. Est para os perfis abaixo da CLDC definir estas reas. Em particular, a especificao
MIDP que define uma aplicao de MIDP (MIDlet) que possui um ciclo de vida, biblioteca Grfica
e controle de eventos (classes javax.microedition.lcdui.*).

4.3. Verificao de Classe

A especificao CLDC exige que todas as classes passem por um processo de verificao de duas
fases. A primeira verificao (pr-verificao) dever est terminada antes da instalao no
dispositivo. A segunda verificao ocorre no dispositivo durante a execuo, realizada pela
Mquina Virtual Java (JVM).

Desenvolvimento de Aplicaes Mveis 9


JEDITM

File.java
Instalao

compilar (javac) verificar


(execuo)

File.class

pr-verificar interpretar

File.class

Mquina de
Desenvolvimento Dispositivo

Figura 3: Processo de Verificao em duas fases

4.4. O Framework Genrico de Conexo (GCF)

O Framework Genrico de Conexo fornece as APIs bsicas para conexo em CLDC. Este
framework fornece uma base comum para conexes como HTTP, Sockets e Datagramas. O GCF
fornece um conjunto genrico e comum de APIs que abstraem todos os tipos de conexo. Note-se
que nem todos os tipos de conexes so exigidas para serem implementados em dispositivos
MIDP.
A hierarquia de interface extensvel do GCF torna a generalizao possvel. Novos tipos de
conexes podem ser adicionados neste framework atravs de extenses desta hierarquia.

Connection

StreamConnectionNotifier DatagramConnection

InputConnection OutputConnection

StreamConnection

ContentConnection

Figura 4: A Hierarquia de Conexo GCF

Desenvolvimento de Aplicaes Mveis 10


JEDITM

5. CDC
A Configurao de Dispositivo Conectada (CDC - Connected Device Configuration) um super-
conjunto da CLDC. Ela prov um ambiente de execuo Java mais amplo que o da CLDC e um
ambiente mais prximo do da JSE.

Figura 5: Viso da CDC

A Mquina Virtual Java CDC (ou CVM) uma Mquina Virtual Java completa. A CDC contm todas
as APIs da CLDC. Ela prov um subconjunto maior das classes da JSE.
Como a CLDC, a CDC no define nenhuma classe de interface com o usurio. As bibliotecas de
interface com o usurio so definidas pelos perfis desta configurao.
As classes includas na CDC vm dos seguintes pacotes:
java.io
java.lang
java.lang.ref
java.lang.math
java.net
java.security
java.security.cert
java.text
java.util
java.util.jar
java.util.zip
CDC tambm inclui o Framework de Conexo Genrica. Ela requer tipos de conexo adicionais
como suporte para arquivo e datagrama.

Desenvolvimento de Aplicaes Mveis 11


JEDITM

6. JWTI
A Tecnologia Java Para a Indstria Sem Fio (JWTI - Java Technology for the Wireless Industry)
especifica um conjunto de servios e especificaes padro. De acordo com a especificao JWTI,
seu principal objetivo "minimizar a fragmentao de APIs no mercado de telefones celulares, e
entregar uma especificao clara e previsvel para os fabricantes de dispositivos, operadores e
desenvolvedores de aplicao".
Por atenderem JWTI, as aplicaes rodaro em um conjunto maior de dispositivos. Os
fabricantes de dispositivos iro se beneficiar tambm porque um conjunto maior de aplicaes
estar disponveis para seus dispositivos.

MIDlets

WMA MMAPI Pacotes OEM


MIDP 2.0
1.1 1.1 Opcionais APIs

CLDC 1.0 or 1.1

Sistema Operacional do Dispositivo

Figura 6: Componentes JWTI

Desenvolvimento de Aplicaes Mveis 12


JEDITM

7. MIDP
O Perfil de Dispositivo de Informao Mvel (MIDP - Mobile Information Device Profile) contrudo
sobre a CLDC. No se deve escrever aplicaes mveis teis apenas usando as APIs CLDC. na
MIDP que as APIs de interface com o usurio so definidas.
A especificao MIDP, assim como a CLDC e outras APIs, foi definida atravs do Java Community
Process (JCP). Foi envolvido um grupo de profissionais de mais de 50 empresas, composta de
fabricantes de dispositivos mveis, operadoras e desenvolvedores de software. A MIDP est
continuamente evoluindo, com futuras verses passando pelo mesmo rigor do processo do JCP.
Verses futuras do MIDP tero compatibilidade com as verses anteriores, como no caso do
MIDP1 e MIDP 2.0.
A especificao MIDP define que um dispositivo MID deve ter as seguintes caractersticas, no
mnimo:
Visor:
Tamanho da Tela: 96x54
Profundidade do Visor: 1-bit
Pixel aspect ratio: aproximadamente 1:1

Entrada:
Um ou mais dos seguintes mecanismos de entrada: teclado de uma mo, teclado de duas
mos ou tela de toque

Memria:
256 kilobytes de memria no voltil para a implementao MIDP, mais o que for requerido
pela CLDC
8 kilobytes de memria no voltil para os dados persistentes criados pela aplicao
128 kilobytes de memria voltil para o ambiente Java (ex. Java heap)

Rede:
Sem fio, duas vias, possivelmente intermitente, com largura de banda ilimitada

Som:
A habilidade de tocar sons, via hardware dedicado ou via software
MIDP define o modelo de aplicao, a API de interface com o usurio, o armazenamento
persistente e a rede, API de mdia e jogos, polticas de segurana, entrega da aplicao e
provisionamento over-the-air.

Desenvolvimento de Aplicaes Mveis 13


JEDITM

8. MIDlet
Uma aplicao MIDP chamada de MIDlet. O software de gerenciamento da aplicao (AMS -
Application Management Software) do dispositivo interage diretamente com o MIDlet com os
mtodos de criar, iniciar, pausar e destruir o MIDlet.
O MIDlet parte do pacote javax.microedition.midlet. Necessita estender a classe MIDlet. E pode
requisitar parmetros do AMS conforme definido no descritor da aplicao (JAD Java Application
Descriptor).
Um MIDlet no utiliza o mtodo public static void main(String[] args). Caso possua, este no ser
reconhecido pelo AMS como o ponto de incio do programa.

8.1. Ciclo de Vida do MIDlet

A vida de um MIDlet comea quando ele instanciado pelo AMS. Ele inicialmente entra no estado
pausado aps ser criado com comando new. O AMS chama o construtor pblico sem argumento
do MIDlet. Se uma exceo ocorrer no construtor, o MIDlet colocado no estado destrudo e
descartado imediatamente.
O MIDlet entra no estado ativo depois de se chamar o mtodo startApp() pelo AMS.
O MIDlet entra no estado destrudo quando o AMS chama o mtodo destroyApp(). Este estado
tambm atingido quando o mtodo notifyDestroyed() retorna com sucesso para a aplicao.
Observe que o MIDlet entra no estado destrudo somente uma vez no seu tempo de vida.

new

destroyApp()

startApp() Pausado

Destrudo
Ativo pauseApp()

destroyApp()

Figura 7: Ciclo de Vida do MIDlet

8.2 MIDlet Suites


As aplicaes de MIDP so empacotadas e entregues aos dispositivos como MIDlet suites. Um
MIDlet suite consiste em um Arquivo Java (JAR) e, opcionalmente, um descritor de aplicao Java
(JAD).
Um arquivo JAD um arquivo texto contendo um conjunto de atributos, alguns dos quais so
requeridos.

Desenvolvimento de Aplicaes Mveis 14


JEDITM

9. Exerccios
9.1. Quais so as vantagens do uso de Java como plataforma de
desenvolvimento e execuo para os dispositivos mveis?

aplicaes altamente portteis


interfaces ricas, bem definidas para o dispositivo
espao de memria baixa (KVM)
ambiente execuo seguro
aplicaes dinmicas (podem carregar aplicaes para um dispositivo)

9.2. O que o motivaria para escrever para programas para os


dispositivos mveis?

o desafio de escrever aplicaes otimizadas


novos conhecimentos
fator diverso

Desenvolvimento de Aplicaes Mveis 15


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 2
Como Comear

Verso 1.0 - Set/2007


JEDITM

1. Objetivos
Nesta lio, escreveremos e construiremos aplicaes Java ME utilizando o emulador e
empacotador de aplicaes. A IDE que utilizaremos ser o NetBeans 5.5 (www.netbeans.org) com
o pacote adicional denominado NetBeans Mobility Pack 5.5 (pode ser obtido no mesmo site).
Uma IDE (Integrated Development Environment) um ambiente de programao com um
construtor de GUI, um editor de cdigo ou texto, um compilador e/ou um interpretador e um
depurador. No nosso caso, o NetBeans vem tambm com um emulador de dispositivos. Isto
permite ver como o programa parecer num dispositivo real.

Ao final desta lio, o estudante ser capaz de:


Entender a estrutura de um MIDlet
Criar um projeto Mobile no NetBeans
Criar e executar um MIDlet no NetBeans

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. "Hello, world!" MIDlet


Vimos na lio anterior o ciclo de vida de um MIDlet. A vida de um MIDlet inicia quando ele
criado pelo Application Management System (AMS) do dispositivo. Inicialmente, ele fica no estado
"pausado".

new

destroyApp()

startApp() Pausado

Destrudo
Ativo pauseApp()

destroyApp()

Figura 1: Ciclo de Vida do MIDlet

Para ser capaz de criar um MIDlet, devemos criar uma subclasse da classe MIDlet do pacote
javax.microedition.midlet. Deve-se sobrescrever ou implementar os mtodos: startApp(),
destroyApp() e pauseApp(). Estes so os mtodos esperados pelo AMS para se executar e
controlar o MIDlet.
Diferentemente de um programa Java tpico onde o mtodo main() executado automaticamente
somente uma nica vez na vida de um programa, o mtodo startApp() pode ser chamado mais de
uma vez durante o ciclo de vida do MIDlet. Ento, no se deve colocar cdigos de inicializao
nica no mtodo startApp(). Para isso, deve ser criado um construtor para o MIDlet e as
inicializaes devem ser feitas nele.
Eis o cdigo de nosso primeiro programa MIDP:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class HelloMidlet extends MIDlet implements CommandListener {


Display display;
Command exitCommand = new Command("Exit", Command.EXIT, 1);
Alert helloAlert;

public HelloMidlet(){
helloAlert = new Alert(
"Hello MIDlet", "Hello, world!",
null, AlertType.INFO
);
helloAlert.setTimeout(Alert.FOREVER);
helloAlert.addCommand(exitCommand);
helloAlert.setCommandListener(this);
}
public void startApp() {
if (display == null){
display = Display.getDisplay(this);
}
display.setCurrent(helloAlert);

Desenvolvimento de Aplicaes Mveis 5


JEDITM

}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void commandAction(Command c, Displayable d){
if (c == exitCommand){
destroyApp(true);
notifyDestroyed(); // Exit
}
}
}

A seguir, dissecaremos o primeiro MIDlet, focando em cada linha de cdigo:


public class HelloMidlet extends MIDlet implements CommandListener {

Como dito anteriormente, criada uma subclasse de MIDlet para criar nosso programa MIDP.
Nessa linha, foi criada uma subclasse de MIDlet estendendo-a e dando o nome HelloMidlet. Alm
disso, implementaremos a interface CommandListener. Veremos sua funo mais a frente.
Display display;
Command exitCommand = new Command("Exit", Command.EXIT, 1);
Alert helloAlert;

Estes so os atributos do MIDlet. O objeto Display (existe somente um display associado por
MIDlet) ser utilizado para desenhar na tela do aparelho. O objeto exitCommand um comando
que poderemos inserir na aplicao, por exemplo, para que possamos finalizar o programa. Se
no fosse colocado qualquer comando de sada, no haveria forma de finalizar um MIDlet de
forma normal. Este ser montado da seguinte forma:
public HelloMidlet(){
helloAlert = new Alert(
"Hello MIDlet", "Hello, world!",
null, AlertType.INFO
);
helloAlert.setTimeout(Alert.FOREVER);
helloAlert.addCommand(exitCommand);
helloAlert.setCommandListener(this);
}

O construtor inicializa o objeto Alert. A classe Alert ser discutida nas prximas lies. O mtodo
addCommand() do objeto Alert mostra um comando "Exit" na tela. O mtodo
setCommandListener() avisa o sistema para passar todos os eventos de comando para o MIDlet.
public class HelloMidlet extends MIDlet implements CommandListener {

O cdigo "implements CommandListener" serve para controlar o pressionamento das teclas e


comandos, de forma que o programa seja capaz de manipular eventos de "command". Se a classe
implementar a interface CommandListener, deve ser criado o mtodo commandAction(), como se
segue:
public void commandAction(Command c, Displayable d){
if (c == exitCommand){
destroyApp(true);
notifyDestroyed(); // Exit
}
}

Usamos o commandAction() somente para as requisies de sada. Finalizamos a nossa classe


utilizando o mtodo notifyDestroyed() se o comando Exit for enviado.
public void startApp() {
if (display == null){
display = Display.getDisplay(this);
}
display.setCurrent(helloAlert);

Desenvolvimento de Aplicaes Mveis 6


JEDITM

Este o ponto de entrada da nossa classe, uma vez que est pronta para ser iniciada pelo AMS.
Lembre-se que o mtodo startApp() pode ser includo mais de uma vez no ciclo de vida do
MIDlet. Se um MIDlet pausado (paused), por exemplo, quando ocorre uma chamada telefnica,
neste momento entramos em estado de pausa (pauseApp). Aps a chamada o AMS pode retornar
o nosso programa e executar novamente o mtodo startApp(). O mtodo esttico setCurrent(), da
classe Display, informa ao sistema que queremos que o objeto alerta seja mostrado na tela.
Podemos iniciar o objeto da exibio chamando o mtodo esttico getDisplay() da mesma classe.
O Netbeans cria automaticamente um Java Application Descriptor (JAD) para o nosso projeto. E
insere o arquivo JAD na pasta "dist" localizada na pasta do projeto. Este um exemplo de arquivo
JAD criado pelo Netbeans:
MIDlet-1: HelloMidlet, , HelloMidlet
MIDlet-Jar-Size: 1415
MIDlet-Jar-URL: ProjectHello.jar
MIDlet-Name: ProjectHello
MIDlet-Vendor: Vendor
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.1
MicroEdition-Profile: MIDP-2.0

Agora estamos prontos para compilar e rodar o nosso primeiro MIDlet.

Desenvolvimento de Aplicaes Mveis 7


JEDITM

3. Utilizando Netbeans e o Mobility Pack


O pr-requisito para esta lio, o Netbeans 5.5 e o Mobility Pack que devem ser instalados em
seu computador. Ambos so arquivos executveis bastando ao aluno seguir as telas guias para
efetuar corretamente a instalao.
Passo 1: Iniciar criando um novo Projeto (Opo File | New Project...).

Figura 2: Menu File do NetBeans

Passo 2: Selecionar a Categoria "Mobile"

Figura 3: Janela New Project Selecionando a categoria

Desenvolvimento de Aplicaes Mveis 8


JEDITM

Passo 3: Selecionar "Mobile Application" e pressionar o boto Next

Figura 4: Janela New Project Selecionando o tipo de projeto

Passo 4:Nomear o projeto e especificar sua localizao


Desmarcar a opo "Create Hello MIDlet", criaremos nosso MIDlet em prximas lies

Figura 5: Janela New Project Selecionando o nome e localizao do projeto

Desenvolvimento de Aplicaes Mveis 9


JEDITM

Passo 5: Selecionar a configurao do projeto (opcional)

Figura 6: Janela New Project Selecionando a configurao do projeto

Etapa 6: Criar um novo MIDlet

Figura 7: Menu File do NetBeans

Desenvolvimento de Aplicaes Mveis 10


JEDITM

Etapa 7: Selecionar na opo Categories a opo MIDP e em File Types a opo MIDlet

Figura 8: Janela New File Selecionando o tipo do arquivo

Etapa 8: Informar o nome do MIDlet (HelloMidlet) e pressionar o boto Finish

Figura 9: Janela New Project Selecionando o nome e localizao do projeto

Desenvolvimento de Aplicaes Mveis 11


JEDITM

Passo 9: Modificar o cdigo do programa conforme descrito anteriormente

Figura 10: Janela New Project Selecionando o nome e localizao do projeto

Passo 10: Compilar e Executar o MIDlet de maneira idntica vista nos projetos anteriores

Figura 11: Janela New Project Selecionando o nome e localizao do projeto

Desenvolvimento de Aplicaes Mveis 12


JEDITM

Passo 11: Testar o MIDlet no Emulador

Figura 12: Janelas do Emulador da Aplicao

Desenvolvimento de Aplicaes Mveis 13


JEDITM

4. Exerccios
4.1. Mltiplos MIDlets em uma suite MIDlet
Adicionar um novo MIDlet ao projeto ProjectHello. Observar que o Netbeans adiciona
automaticamente um novo MIDlet no arquivo de aplicaes JAD quando utilizado o auxlio "New
File..."

Desenvolvimento de Aplicaes Mveis 14


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 3
Interface de Alto Nvel para o Usurio

Verso 1.0 - Set/2007


JEDITM

1. Objetivos
A interface de usurio MIDP foi desenhada para aparelhos portteis. Aplicaes MIDP so
mostradas no limite de rea da tela. Dispositivos de memria o fator pelo qual os aparelhos
portteis possuem pouca memria.
Com os diferentes tipos de aparelhos mveis, dos mais variados modelos de telefones mveis aos
PDAs, a interfase de usurio MIDP foi desenhada para ser flexvel o bastante para ser utilizvel
em todos estes aparelhos.
Ao final desta lio, o estudante ser capaz de:
Conhecer as vantagens e desvantagens de se utilizar interfaces grficas em alto e baixo
nvel
Projetar MIDlets usando componentes de interface grfica de alto nvel
Identificar as diferentes subclasses de tela
Saber que diferentes itens podem ser utilizados na forma de objeto

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. Interface de usurio MIDP


MIDP possui classes que podem prover interfaces de usurio com altos e baixos nveis de funes.
Interfaces grficas de alto nvel so desenhadas para serem flexveis. A aparncia desses
componentes no est definida nas especificaes. A aparncia varia de aparelho para aparelho,
mas o programador pode ficar seguro de que o comportamento de alto nvel dos componentes
ser o mesmo em todas as especificaes e implementaes.

Interfaces Grficas de Alto Nvel Interfaces Grficas de Baixo Nvel


Altamente porttil entre aparelhos Pode ser especfico do dispositivo
Aparncia a mesma nos aparelhos Aplicao com aparncia especfica
Navegao do tipo "rolagem" encapsulada Tem que implementar suas prprias formas
de navegao
No podem definir a aparncia real Definem a aparncia em nvel de pixel
No so acessadas por aparelhos com O acesso ao baixo nvel de entrada por
caractersticas especficas intermdio do pressionamento de teclas
Figura 1: Comparao entre alto nvel e baixo nvel

2.1. Display
A principal parte da interface de usurio MIDP a classe Display. Existe uma e apenas uma
instncia do Display para cada MIDlet. MIDlet pode pegar a referncia do objeto Display utilizando
o mtodo esttico getDisplay() da classe Display, e enviar a referncia de um objeto do MIDlet.
MIDlet garante que o objeto Display no ser modificado enquanto existir uma instncia de
MIDlet. Isso significa que o objeto retornado ao executamos o mtodo getDisplay() o mesmo
no importando se essa chamada foi realizada nos mtodos startApp() ou destroyApp() (veja
mais sobre o ciclo de vida do Midlet).

2.2. Displayable
Apenas um componente Displayable pode ser mostrado de cada vez. Por padro, Displayable no
mostrado no visor. Pode ser visvel por intermdio da chamada do mtodo setCurrent(). Este
mtodo pode ser chamado quando a aplicao se inicia, caso contrrio, uma tela escura ser
mostrada ou a aplicao no se iniciar.

new

destroyApp()

startApp() Pausado

Destrudo
Ativo pauseApp()

destroyApp()

Figura 2: Ciclo de Vida do MIDlet

Desenvolvimento de Aplicaes Mveis 5


JEDITM

O mtodo startApp() da classe MIDlet o local onde possvel inserir a chamada do mtodo
setCurrent(). Entretanto necessrio levar em considerao que o mtodo startApp() pode ser
chamado mais de uma vez durante a existncia do MIDlet. Quando um MIDLet entra em pausa
por intermdio do mtodo pauseApp(), pode ser que tenha ocorrido uma chamada telefnica para
atender. O mtodo startApp() pode ser chamado novamente (aps o finalizao da chamada
telefnica), assim como pela chamada do mtodo setCurrent() dentro do mtodo startApp().
Iremos obscurecer a tela que estava sendo mostrada antes do aplicativo entrar em pausa (ou
seja, antes da chamada telefnica).
O componente Displayable pode ter um ttulo, um conjunto de comandos, um commandListener e
um Relgio.

Figura 3: Propriedades de Displayable

2.3. Title
O componente Displayable possui um ttulo associado. A posio e aparncia deste ttulo
especfica para cada tipo de aparelho e s pode ser determinada quando a aplicao estiver
rodando. O ttulo associado ao Displayable por intermdio da chamada do mtodo setTitle().
Chamando este mtodo, o ttulo do componente Displayable poder mudar imediatamente. Se
um Displayable est sendo apresentado na tela corrente, a especificao de estado do MIDP e o
ttulo devem ser alterados pela implementao to logo quanto seja permitido faz-la.
Passando um parmetro nulo (null) para o mtodo setTitle() remove-se o ttulo do componente
Displayable. Mudando ou removendo o ttulo, pode-se afetar o tamanho da rea disponvel. Se a
troca na rea do visor ocorrer, o MIDlet pode ser modificada por intermdio do mtodo
sizeChanged().

2.4. Comando
Devido ao limite do tamanho da tela, MIDP no define uma barra de menu dedicada. No lugar da
barra de menu MIDlets possuem comandos. Comandos so usualmente implementados pelo MIDP
que podem ser chaves rpidas ou itens de menu. O objeto da classe Command contm
informaes somente sobre as aes que foram capturadas quando ativado, e no cdigos que
sero executados quando for selecionado.
A propriedade commandListener do componente Displayable contm as aes que sero
executadas na ativao dos comandos. A commandListener a interface que especifica um
mtodo simples:
public void commandAction(Command comando, Displayable mostravel)

O mapeamento dos comandos no aparelho depende do nmero de botes rpidos ou botes


programveis disponveis no aparelho. Se o nmero de comandos no se ajustar ao nmero de
botes rpidos (softbuttons), o aparelho pode colocar alguns ou todos os comandos dentro do
menu e mapear este menu para os botes rpidos com o ttulo.

Desenvolvimento de Aplicaes Mveis 6


JEDITM

Command exitCommand = new Command("Exit", Command.EXIT, 1);


Command newCommand = new Command("New Item", Command.OK, 1);
Command renameCommand = new Command("Rename Item", Command.OK, 1);
Command deleteCommand = new Command("Delete Item", Command.OK, 1);
...
list.addCommand(exitCommand);
list.addCommand(newCommand);
list.addCommand(renameCommand);
list.addCommand(deleteCommand);

Figura 4: Amostra de mapeamento para mltiplos comandos

Um Command possui um label curto, um label longo e opcional, um tipo e uma prioridade.

2.4.1. Label
O tamanho reduzido da tela dos dispositivos sempre um fator relevante quando se desenvolvem
aplicaes MIDP. Para os labels de comando, essa suposio tambm aplicvel. Os labels devem
ser curtos, porm descritivos, para tanto devem caber na tela e serem compreensveis para o
usurio final.
Quando um label longo for especificado, dever ser apresentado toda vez que o sistema
considerar apropriado. No existe uma chamada de API que especifique qual label dever ser
mostrado. perfeitamente possvel que alguns comandos apresentem um label curto enquanto
que outros apresentem um longo.

2.4.2. Tipo de Comando


A maneira pela qual um comando apresentado depende do dispositivo utilizado. Um
programador pode especificar o tipo para este comando. Este tipo servir como um auxlio para
saber onde o comando dever ser colocado. No existe nenhuma forma de definir perfeitamente
onde o comando deve ser apresentado na tela.
Os diferentes tipos de comandos so:
Command.OK, Command.BACK,
Command.CANCEL, Command.EXIT,
Command.HELP, Command.ITEM,
Command.SCREEN, Command.STOP

Desenvolvimento de Aplicaes Mveis 7


JEDITM

Figura 5: A apresentao dos comandos diferente em cada aparelho.

2.4.3. Prioridade de Comandos


A aplicao pode especificar a importncia dos comandos na propriedade priority (prioridade).
Esta uma propriedade com um argumento do tipo Integer e quanto menor o nmero, maior a
prioridade. Esta propriedade tambm uma dica para ajudar a saber como o comando dever ser
posicionado. Casualmente a implementao determina a posio dos comandos pelo seu tipo. Se
existir mais de um comando do mesmo tipo, a prioridade normalmente considerada no
posicionamento dos comandos.

2.5. CommandListener
O CommandListener uma interface que possui um nico mtodo:
void commandAction(Command command, Displayable displayable)

O mtodo commandAction() chamado quando um comando selecionado. A varivel do


comando uma referncia para o comando que foi selecionado. Displayable onde o comando
est localizado e onde a ao selecionada acontece.
O mtodo commandAction dever retornar imediatamente, caso contrrio a execuo da aplicao
poder ser bloqueada. Isto se deve pelo fato das especificaes do MIDP no requisitarem
implementaes para a criar uma tarefa separada para cada evento entregue.

2.6. Ticker
O Ticker uma contnua linha de rolagem de texto que acompanha a tela. O mtodo construtor
do Ticker aceita uma String para ser exibida. Ele s possui dois outros mtodos, o padro get e
set para este texto: String getString() e void setString(String texto). No existe possibilidade da
aplicao controlar a velocidade e a direo do texto. A rolagem no pode ser pausada ou
interrompida.
Se uma quebra de linha for embutida no texto, est no ser apresentada na tela. Todas as linhas
de texto devero ser exibidas como uma nica linha de texto rolante.
Um objeto Ticker anexado a um dispositivo de exibio chamando-se o mtodo setTicker().
Caso j exista um objeto Ticker anexado ao dispositivo, este ser substitudo pelo novo objeto
passado como parmetro.
Passando-se um parmetro null para o mtodo setTicker() ocorre a remoo qualquer objeto
Ticker anexado do dispositivo. A remoo de um objeto Ticker do dispositivo pode afetar o
tamanho de rea vlido para o contedo a ser exibido. Se uma mudana no tamanho da rea de

Desenvolvimento de Aplicaes Mveis 8


JEDITM

exibio ocorrer, o MIDlet dever ser notificado pelo mtodo sizeChanged().


Os objetos Displayable podem compartilhar uma instncia do objeto Ticker.

2.7. Screen
A classe Screen a principal classe abstrata utilizada para aplicaes grficas de alto nvel
enquanto que a classe Canvas a principal classe abstrata para aplicaes grficas de baixo nvel.
Existem quatro subclasses da classe abstrata Screen: Form, TextBox, List e Alert.

Figura 6: Hierarquia de classes

2.8. Item
Componentes do tipo Item podem ser colocados em um componente do tipo container, como um
Form ou um Alert. Um item pode possuir as seguintes propriedades:

Propriedade Valor Padro


Label Especificado no construtor da subclasse
Commands nenhum
defaultCommand nulo
ItemCommandListener nulo
Layout directive LAYOUT_DEFAULT
Preferncias de altura e largura -1 (destravado)

Figura 7: Hierarquia de Classe Item

Desenvolvimento de Aplicaes Mveis 9


JEDITM

A diretiva Layout especifica o formato de um item dentro de um objeto do tipo Form. A diretiva
Layout pode ser combinada usando o operador de comparao binria OR (|). Todavia, diretivas
de mesma orientao so mutuamente exclusiva.
Estas so as diretivas de alinhamento horizontal mutuamente exclusivas:
LAYOUT_LEFT
LAYOUT_RIGHT
LAYOUT_CENTER

Estas so as diretivas de alinhamento vertical mutuamente exclusivas:


LAYOUT_TOP
LAYOUT_BOTTOM
LAYOUT_VCENTER

Outras diretivas de layout no mutuamente exclusiva so:


LAYOUT_NEWLINE_BEFORE
LAYOUT_NEWLINE_AFTER
LAYOUT_SHRINK
LAYOUT_VSHRINK
LAYOUT_EXPAND
LAYOUT_VEXPAND
LAYOUT_2

Desenvolvimento de Aplicaes Mveis 10


JEDITM

3. Alert
A classe Alert gera uma tela na qual possvel exibir um texto e uma imagem. um componente
para exibir erro, aviso, texto e imagem informativa ou trazer uma tela de confirmao para o
usurio.
exibido por um determinado perodo de tempo. Este tempo pode ser fixado utilizando-se o
mtodo setTimeout() e especificado em milissegundos. Pode ser construdo para ser exibido at
que o usurio ative um comando Done dentro do intervalo de tempo de espera especificado pela
contstante Alert.FOREVER.
O Alert pode tambm exibir um componente do tipo Gauge como um indicador. Quando um Alert
conter um texto esse no ajustar a tela inteira e dever ser rolado. Alert fixado
automaticamente para modal (tempo de espera fixado para Alert.FOREVER).
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class AlertMidlet extends MIDlet implements CommandListener {


Display display;
Form mainForm;
Command exitCommand = new Command("Exit", Command.EXIT, 0);
Command okCommand = new Command("Ok", Command.OK, 0);
Gauge gauge = new Gauge(null, false, 5, 0);
Command[] commands = {
new Command("Alarm", Command.OK, 0),
new Command("Confirmation", Command.OK, 0),
new Command("Info", Command.OK, 0),
new Command("Warning", Command.OK, 0),
new Command("Error", Command.OK, 0),
new Command("Modal", Command.OK, 0)
};

Alert[] alerts = {
new Alert("Alarm Alert",
"Example of an Alarm type of Alert",
null, AlertType.ALARM),
new Alert("Confirmation Alert",
"Example of an CONFIRMATION type of Alert",
null, AlertType.CONFIRMATION),
new Alert("Info Alert",
"Example of an INFO type of Alert",
null, AlertType.INFO),
new Alert("Warning Alert",
"Example of an WARNING type of Alert, w/ gauge indicator",
null, AlertType.WARNING),
new Alert("Error Alert",
"Example of an ERROR type of Alert, w/ an 'OK' Command",
null, AlertType.ERROR),
new Alert("Modal Alert",
"Example of an modal Alert: timeout = FOREVER",
null, AlertType.ERROR),
};
public AlertMidlet(){
mainForm = new Form("JEDI: Alert Example");

mainForm.addCommand(exitCommand);
for (int i=0; i< commands.length; i++){
mainForm.addCommand(commands[i]);
}
mainForm.setCommandListener(this);
// Adiciona um objeto Gauge e envia o tempo limite
alerts[3].setIndicator(gauge);
alerts[3].setTimeout(5000);
// Adiciona um comando para este Alert

Desenvolvimento de Aplicaes Mveis 11


JEDITM

alerts[4].addCommand(okCommand);
// Define o Alert como Modal
alerts[5].setTimeout(Alert.FOREVER);
}

public void startApp() {


if (display == null){
display = Display.getDisplay(this);
display.setCurrent(mainForm);
}
}

public void pauseApp() {}

public void destroyApp(boolean unconditional) {}

public void commandAction(Command c, Displayable d){


if (c == exitCommand){
destroyApp(true);
notifyDestroyed(); // Exit
}
for (int i=0; i<commands.length; i++){
if (c == commands[i]){
display.setCurrent(alerts[i]);
}
}
}
}

INFO Alert Alert Modal Alert com o indicador gauge


Figura 8: Diferentes tipos de Alert

Desenvolvimento de Aplicaes Mveis 12


JEDITM

4. List
A classe List uma subclasse de Screen e fornece uma lista de escolhas. Este objeto pode
assumir trs modelos: IMPLICIT, EXCLUSIVE ou MULTIPLE.
List IMPLICIT e o usurio executar o boto "select", o mtodo commandAction() da classe List
ser chamada. O comando padro List.SELECT_COMMAND. O comando commandListener pode
ser chamado atravs do comando padro List.SELECT_COMMAND.
O mtodo getSelectedIndex() retorna o ndice do elemento atualmente selecionado para os tipos
IMPLICIT e EXCLUSIVE. Para o tipo MULTIPLE, o mtodo getSelectedFlags() retorna um atributo
do tipo boolean contendo o estado dos elementos. O mtodo isSelected(int index) retorna o
estado do elemento na posio de ndice dada.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ListMidlet extends MIDlet implements CommandListener {


Display display;
List list;
Command exitCommand = new Command("Exit", Command.EXIT, 1);
Command newCommand = new Command("New Item", Command.OK, 1);
Command renameCommand = new Command("Rename Item", Command.OK, 1);
Command deleteCommand = new Command("Delete Item", Command.OK, 1);
Ticker ticker = new Ticker(
"JEDI - Java Education and Development Initiative");

public ListMidlet(){
list = new List("JEDI: List Example", List.IMPLICIT);
list.append("List Item #1", null);
list.append("List Item #2", null);
list.append("List Item #3", null);
list.setTicker(ticker);
list.addCommand(exitCommand);
list.addCommand(newCommand);
list.addCommand(renameCommand);
list.addCommand(deleteCommand);
list.setCommandListener(this);
}

public void startApp() {


if (display == null){
display = Display.getDisplay(this);
display.setCurrent(list);
}
}

public void pauseApp() {


}

public void destroyApp(boolean unconditional) {


}

public void commandAction(Command c, Displayable d){


if (c == exitCommand){
destroyApp(true);
notifyDestroyed(); // Exit
}
if (c == List.SELECT_COMMAND){
int index = list.getSelectedIndex();
String currentItem = list.getString(index);
// realiza algo
}
}
}

Desenvolvimento de Aplicaes Mveis 13


JEDITM

Lista IMPLICIT Lista EXCLUSIVE Lista MULTIPLE


Figura 9: Tipos de lista

Desenvolvimento de Aplicaes Mveis 14


JEDITM

5. TextBox
A classe TextBox a subclasse de Screen que pode ser usada para se obter a entrada de texto do
usurio. Permite que o usurio incorpore e edite o texto. similar classe TextField (ver o item
sobre TextField) pois permite a entrada de constraints e de modalidades. Sua diferena em
relao a classe TextField que o usurio pode inserir uma nova linha (quando a constraint da
entrada informada).
O texto digitado no objeto TextBox pode ser recuperado utilizando o mtodo getString().

Figura 10: TextBox com mltiplas linhas

Figura 11: TextBox com o PASSWORD modificado

Desenvolvimento de Aplicaes Mveis 15


JEDITM

6. Form
A classe Form uma subclasse da Screen. um continer para itens das subclasses, tais como os
objetos das classes TextField, StringItem, ImageItem, DateField e ChoiceGroup. Controla a
disposio dos componentes e a transversal entre os componentes e o desdobramento da tela.
Itens so adicionados e inseridos a um objeto do tipo Form usando os mtodos append() e
insert(), respectivamente. Itens so eliminados usando o mtodo delete(). Itens podem ser
substitudos usando o mtodo set(). Itens so referenciados usando o ndice de base zero.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MidletPrinc extends MIDlet implements CommandListener {

private Command exitCmd = new Command("Exit", Command.EXIT, 0);


private ScreenForm form;
private Display display;

public void startApp() {


if (display == null) {
form = new ScreenForm("Test Form");
display = Display.getDisplay(this);
}
display.setCurrent(form);
}
public void commandAction(Command command, Displayable displayable) {
if (command == exitCmd) {
try {
destroyApp(true);
} catch (MIDletStateChangeException ex) {
ex.printStackTrace();
}
notifyDestroyed();
}
}
protected void pauseApp() {
}
protected void destroyApp(boolean b) throws MIDletStateChangeException {
}
class ScreenForm extends Form {
public ScreenForm(String title) {
super(title);
addCommand(exitCmd);
setCommandListener(MidletPrinc.this);

// Instrues para o Form


}
}
}

Neste MIDlet observe o comentrio Instrues para o Form. Este servir como ponto de entrada
para os prximos exemplos, que devero serem inseridos exatamente a partir deste ponto.

Desenvolvimento de Aplicaes Mveis 16


JEDITM

7. ChoiceGroup
Um componente ChoiceGroup representa grupos de escolhas selecionadas. A escolha pode conter
um texto, uma imagem ou ambas.
As escolhas podem ser EXCLUSIVE (somente uma opo pode ser selecionada) ou MULTIPLE
(vrias opes podem ser selecionadas de uma vez). Caso um objeto do tipo ChoiceGroup seja
um tipo de POPUP, somente uma opo poder ser selecionada. Uma seleo de popup ser
exibida quando este item for selecionado. Cabe ao usurio efetuar uma nica escolha. A opo
exibida sempre a seleo escolhida.
O mtodo getSelectedIndex() retorna o ndice do elemento selecionado de um ChoiceGroup. O
mtodo getSelectedFlags() retorna um grupo de atributos do tipo boolean que corresponde ao
estado de cada um dos elementos. O mtodo isSelected(int index) retorna o estado de um
elemento a partir da posio informada no atributo index.
// Insira estas instrues no Form
ChoiceGroup choiceExclusive = new ChoiceGroup("Exclusive", Choice.EXCLUSIVE);
choiceExclusive.append("Male", null);
choiceExclusive.append("Female", null);
append(choiceExclusive);

ChoiceGroup choiceMultiple = new ChoiceGroup("Multiple", Choice.MULTIPLE);


choiceMultiple.append("Apple", null);
choiceMultiple.append("Orange", null);
choiceMultiple.append("Grapes", null);
append(choiceMultiple);

ChoiceGroup choicePopup = new ChoiceGroup("Popup", Choice.POPUP);


choicePopup.append("Asia", null);
choicePopup.append("Europe", null);
choicePopup.append("Americas", null);
append(choicePopup);

Figura 12: Modelos de Grupos de Escolha

Desenvolvimento de Aplicaes Mveis 17


JEDITM

8. DateField
O componente DateField utilizado para as entradas de data e hora. Pode conter uma entrada de
data (modo DATE), uma entrada de hora (modo TIME) ou ambas (modo DATE_TIME).
O mtodo getDate() retorna o valor atual de um item e retornar null caso este item no seja
inicializado. Caso o modo do DataField seja DATE, a hora do componente ir retornar zero. Se o
modo for TIME, a data do componente definido para "Janeiro 1, 1970".
// Insira estas instrues no Form
DateField dateonly = new DateField("Birthday (DATE)", DateField.DATE);
DateField timeonly = new DateField("Set Alarm (TIME)", DateField.TIME);
DateField datetime =
new DateField("Departure (DATE_TIME)", DateField.DATE_TIME);

append(dateonly);
append(timeonly);
append(datetime);

Entrada de DateField Selecionando Datas Selecionando Horas


Figura 13: Modelos de DateField e telas de entrada

Desenvolvimento de Aplicaes Mveis 18


JEDITM

9. StringItem
Um componente StringItem um componente somente de leitura. Sendo composto de um label e
um texto.
Um objeto do tipo StringItem, opcionalmente, permite um argumento que representa a
aparncia. O modo de aparncia pode ser definido atravs das constantes Item.PLAIN,
Item.HYPERLINK ou Item.BUTTON.
Caso o modo da aparncia seja do tipo HYPERLINK ou BUTTON, o comando padro e o
ItemCommandListener precisam ser definidos no item.
// Insira estas instrues no Form
StringItem plain = new StringItem("Plain", "Plain Text", Item.PLAIN);
StringItem hyperlink =
new StringItem("Hyperlink", "http://www.sun.com", Item.HYPERLINK);
hyperlink.setDefaultCommand(new Command("Set", Command.ITEM, 0));
StringItem button = new StringItem("Button", "Click me", Item.BUTTON);
button.setDefaultCommand(new Command("Set", Command.ITEM, 0));
append(plain);
append(hyperlink);
append(button);

Figura 14: StringItem

Desenvolvimento de Aplicaes Mveis 19


JEDITM

10. ImageItem
O componente ImageItem uma imagem grfica que pode ser colocada em um componente, tal
como um Form. O objeto ImageItem permite um objeto do tipo layout como parmetro (veja
mais na seo sobre Item):
public ImageItem(
String label,
Image img,
int layout,
String altText)

Outro construtor aceita uma modalidade de aparncia, podendo ser um dos seguintes atributos
definidos: Item.PLAIN, Item.HYPERLINK ou Item.BUTTON (ver mais na seo sobre StringItem):
public ImageItem(String label,
Image image,
int layout,
String altText,
int appearanceMode)

O arquivo "jedi.png" importado para o projeto usando-se a operao de gerenciamento de


arquivos do sistema e inserido no diretrio do projeto sobre o subdiretrio "src". O projeto
atualizado pelo clique com boto direito do mouse sobre o nome do projeto e seleo de "Refresh
Folders".
// Insira estas instrues no Form
try {
Image img = Image.createImage("/jedi.png");
ImageItem image = new ImageItem("JEDI", img, Item.LAYOUT_CENTER, "JEDI Logo");
append(image);
} catch (Exception e){
e.printStackTrace();
}

Figura 15: ImageItem

Desenvolvimento de Aplicaes Mveis 20


JEDITM

11. TextField
Um componente TextField um item onde o usurio pode codificar a entrada. Diversas regras de
entrada, mutuamente exclusivas, podem ser ajustadas:
TextField.ANY TextField.EMAILADDR
TextField.NUMERIC TextField.PHONENUMBER
TextField.URL TextField.DECIMAL

A entrada pode tambm ter estes modificadores:

TextField.PASSWORD TextField.UNEDITABLE
TextField.SENSITIVE TextField.NON_PREDICTIVE
TextField.INITIAL_CAPS_WORD TextField.INITIAL_CAPS_SENTENCE

Estes modificadores podem ser atribudos usando-se o operador de comparao binria OR (|) (ou
pelo uso do operador de comparao binria: XOR ^) sobre as regras de entrada.
Consequentemente, modificadores podem ser derivados do valor do retorno do mtodo
getConstraints() ao operador de comparao binria AND (&).
J que os modificadores so retornados pelo mtodo getConstraints(), a entrada principal pode
ser extrada pelo uso do operador de comparao binria com TextBox.CONSTAINT_MASK e o
retorno do valor do mtodo getConstaints().
O mtodo getString() retorna o contedo do TextField como um valor do tipo caractere.
// Insira estas instrues no Form
TextField ANY = new TextField("ANY", "", 64, TextField.ANY);
TextField EMAILADDR = new TextField("EMAILADDR", "", 64, TextField.EMAILADDR);
TextField NUMERIC = new TextField("NUMERIC", "", 64, TextField.NUMERIC);
TextField PHONENUMBER =
new TextField("PHONENUMBER", "", 64, TextField.PHONENUMBER);
TextField URL = new TextField("URL", "", 64, TextField.URL);
TextField DECIMAL = new TextField("DECIMAL", "", 64, TextField.DECIMAL);

append(ANY);
append(EMAILADDR);
append(NUMERIC);
append(PHONENUMBER);
append(URL);
append(DECIMAL);

Figura 16: TextField Items

Desenvolvimento de Aplicaes Mveis 21


JEDITM

12. Exerccios
12.1. Lista dinmica
Criar um MIDlet com uma List do tipo IMPLICIT na tela principal. Anexar trs comandos para esta
List "Add Item", "Remove Item" e "Exit". O comando "Add Item" alertar o usurio para uma
entrada a lista usando um TextBox, ento adicionar este antes do item selecionado na lista.
"Remove Item" remover o item selecionado da lista (dica, veja o mtodo getSelectedIndex). O
Comando "Exit" finalizar o Midlet.

Desenvolvimento de Aplicaes Mveis 22


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 4
Interface de Baixo Nvel para o Usurio

Verso 1.0 - Set/2007


JEDITM

1. Objetivos
Nas lies anteriores dissertamos sobre como construir interfaces do usurio tais como listas,
formulrios e dados de entrada. Aquelas eram interfaces de alto nvel e o programador no tinha
que se preocupar sobre como desenhar a tela ou posicionar o texto na tela. Todo programa tem
que especificar apenas o tipo de componentes e o nomes dos elementos. O sistema encarrega-se
de manusear o desenho, a rolagem e o layout da tela.
Uma desvantagem de se utilizar somente componentes de alto nvel que o programa no tem
controle total sobre a tela. H ocasies em que queremos desenhar linhas, animar imagens e ter
controle sobre cada ponto da tela.
Nesta lio trabalharemos diretamente com o desenho da tela. Estudaremos a classe Canvas, que
deve ser o fundo de nosso desenho. Trabalharemos tambm com a classe Graphics que tem
mtodos para desenho de linhas, retngulos, arcos e texto. Tambm falaremos sobre fontes, cores
e imagens.
Ao final desta lio, o estudante ser capaz de:
Compreender os eventos de baixo nvel manuseados em MIDP
Desenhar e exibir texto, imagens, linhas, retngulos e arcos
Especificar cor, fonte e movimento para operaes de desenho
Compreender e utilizar as classes Canvas e Graphics

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. Canvas
A classe Canvas uma subclasse de Displayable. Uma classe abstrata que deve ser instanciada
antes que uma aplicao possa fazer uso de suas funcionalidades.

Figura 1: Hierarquia de classes.

Pode ser implementada com a subclasse Screen de exibio. O programa pode alternar para
Canvas e Screen. Define mtodos vazios de manuseio. As aplicaes devem implement-los para
manusear os eventos.
A classe define um mtodo abstrato chamado paint(). Aplicaes que utilizam esta classe devem
providenciar a implementao deste mtodo.

2.1. O sistema de Coordenadas

O sistema de coordenadas da classe Canvas baseado no (0,0)


increasing x value
ponto de coordenada zero, ou seja, as coordenadas x e y
iniciam com o valor zero. O canto esquerdo superior a
coordenada (0,0). A coordenada x incrementada da
esquerda para a direita, enquanto a coordenada y
incrementada de cima para baixo. Os mtodos getWidth() e
increasingy value

getHeight() retornam a largura e a altura do Canvas,


respectivamente.
O canto inferior direito da tela tem as coordenadas nas
posies getWidht()-1 e getHeight()-1. Quaisquer
alteraes no tamanho de desenho do Canvas registrado
para a aplicao pelo mtodo sizeChange(). O tamanho
disponvel do Canvas pode mudar se acontecer uma troca
entre os modos normal e tela cheia ou a adio ou remoo
de componentes tais como Comandos.
(getwidth()-1,getHeight()-1)

Figura 2: O sistema Coordinate

2.2. "Hello, world!"


import javax.microedition.midlet.*;

Desenvolvimento de Aplicaes Mveis 5


JEDITM

import javax.microedition.lcdui.*;

public class HelloCanvasMIDlet extends MIDlet {


private Display display;
HelloCanvas canvas;
Command exitCommand = new Command("Exit", Command.EXIT, 0);

public void startApp() {


if (display == null){
canvas = new HelloCanvas(this, "Hello, world!");
display = Display.getDisplay(this);
}
display.setCurrent(canvas);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
protected void Quit(){
destroyApp(true);
notifyDestroyed();
}
}

class HelloCanvas extends Canvas implements CommandListener {


private Command exitCommand = new Command("Exit", Command.EXIT, 0);
private HelloCanvasMIDlet midlet;
private String text;
public HelloCanvas(HelloCanvasMIDlet midlet, String text) {
this.midlet = midlet;
this.text = text;

addCommand(exitCommand);
setCommandListener(this);
}
protected void paint(Graphics g) {
// Limpa a janela
g.setColor(255, 255, 255 );
g.fillRect(0, 0, getWidth(), getHeight());
// Define a cor como preta
g.setColor(0, 0, 0);
// E escreve o texto
g.drawString(text,
getWidth()/2, getHeight()/2,
Graphics.TOP | Graphics.HCENTER);
}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand){
midlet.Quit();
}
}
}

Desenvolvimento de Aplicaes Mveis 6


JEDITM

Figura 3: Hello Word utilizando Canvas

Com o midlet Hello, world! definimos a classe que estende a classe Canvas
class HelloCanvas extends Canvas implements CommandListener {

Adicionamos um comando Exit (sada) e o colocamos como listener do comando


addCommand(exitCommand);
setCommandListener(this);

Criamos um comando de listener atravs da implementao de uma classe CommandListener.


Isto significa criar uma classe que tenha um mtodo commandAction.
class HelloCanvas extends Canvas implements CommandListener {
public void commandAction(Command c, Displayable d) {
...
}
}

O ponto central deste programa o mtodo paint(). A primeira chamada deste mtodo limpa a
tela:
g.setColor(255, 255, 255 );
g.fillRect(0, 0, getWidth(), getHeight());

E os mtodos grficos de baixo nvel desenham a mensagem Hello, world! na tela:


g.setColor(0, 0, 0);
g.drawString(text, getWidth()/2, getHeight()/2,
Graphics.TOP | Graphics.HCENTER);

2.3. Comandos

Assim como as classes List, TextBox e Form, a classe Canvas pode possuir Commands anexados e
pode escutar por eventos de comando. Os passos para adicionar um comando a um Canvas so
os mesmos:
1. Criar um objeto da classe Command
private Command exitCommand = new Command("Exit", Command.EXIT, 0);

2. Utilizar o mtodo addCommand() para anexar o comando ao objeto da classe Canvas (Form,
List ou TextBox)
addCommand(exitCommand);

3. Utilizar o mtodo setCommandListener() para registrar qual classe obtm os eventos de


comando neste Displayable

Desenvolvimento de Aplicaes Mveis 7


JEDITM

setCommandListener(this);

4. Criar um commandListener para implementar a classe CommandListener e providenciar o


mtodo commandAction()
class HelloCanvas extends Canvas implements CommandListener {
...
public void commandAction(Command c, Displayable d) {
if (c == exitCommand){
// do something
}
}
}

2.4. Eventos de Teclado

A classe Canvas pode ter uma interface listener para eventos de teclado que podem implementar
os seguintes mtodos:
keyPressed(int keyCode) Quando uma tecla pressionada
keyRepeated(int keyCode) Quando uma tecla repetida (quando mantida pressionada)
keyReleased(int keyCode) Quando uma tecla liberada

A classe Canvas define os seguintes cdigos de teclado: KEY_NUM0, KEY_NUM1, KEY_NUM2,


KEY_NUM3, KEY_NUM4, KEY_NUM5, KEY_NUM6, KEY_NUM7, KEY_NUM8, KEY_NUM9, KEY_STAR,
e KEY_POUND.
Para recuperar o nome da tecla deve-se utilizar o mtodo getKeyName(int keyCode).

2.5. Aes de Jogo

Cada cdigo de tecla pode ser mapeada para uma ao de jogo. A classe Canvas define estas
aes: UP, DOWN, LEFT, RIGHT, FIRE, GAME_A, GAME_B, GAME_C, GAME_D. O programa pode
traduzir um cdigo de tecla em uma ao de jogo utilizando o mtodo getGameAction(int
keyCode).
O mtodo getKeyCode(int gameAction) retorna o cdigo de tecla associado com uma ao de
jogo. Uma ao de jogo pode ter mais de um cdigo de teclado associado. Se houver mais de um
cdigo de tecla associado com uma ao de jogo retornado apenas um nico cdigo.
Uma aplicao deve utilizar o mtodo getGameAction(int keyCode) ao invs de usar diretamente
os cdigos de teclado. Normalmente, se um programa precisa esperar por uma tecla UP, ele
deveria utilizar o atributo KEY_NUM2 ou o cdigo especfico para o boto UP. No entanto,
programas que utilizam este mtodo no so portveis em aparelhos que possam ter diferentes
formatos para o cdigo da tecla do boto UP. O KEY_NUM2 pode ser a tecla UP para um
aparelho, entretanto, pode ser a tecla LEFT em outro aparelho. O mtodo getGameAction() deve
sempre retornar UP, independente de qual tecla foi pressionada j que esta que est no
contexto do aparelho.

2.6. Eventos de apontador

Apesar dos eventos de teclado, programas MIDP tambm podem conter eventos de apontador.
Isto verdade se o aparelho possuir um apontador e estiver implementado no sistema Java do
aparelho
O mtodo hasPointerEvents() retorna true se o aparelho suportar eventos de presso e liberar
um apontador. O mtodo hasPointerMotionEvents() retorna true se o aparelho suportar eventos
de movimentao de apontador.
public boolean hasPointerEvents()
public boolean hasPointerMotionEvents()

Os eventos que so gerados por atividade de ponto so definidos pela implementao dos

Desenvolvimento de Aplicaes Mveis 8


JEDITM

mtodos: pointerPressed, pointerReleased e pointerDragged. Uma aplicao precisa implementar


estes mtodos para ser notificada quando ocorrerem. As coordenadas x e y do evento (onde o
apontador foi pressionado, solto ou arrastado) so especificadas como parmetros nas assinaturas
dos seguintes mtodos:
protected void pointerPressed(int x, int y)
protected void pointerReleased(int x, int y)
protected void pointerDragged(int x, int y)

Desenvolvimento de Aplicaes Mveis 9


JEDITM

3. Grficos
A classe Graphics a principal classe para desenhar textos, imagens, linhas, retngulos e arcos.
Possui mtodos para especificar cor, fonte e estilo.

3.1. Cores

A classe Display possui mtodos para determinar se o aparelho possui suporte a cor e o nmero
de cores ou tons de cinza suportados por ele.
public boolean isColor() Retorna true se a tela suportar cor, retorna false se no
public int numColors() Retorna o nmero de cores (ou tons de cinza se o
aparelho no suportar cores) suportados pelo aparelho

Para definir a cor que ser utilizada para os prximos mtodos, utilize o mtodo setColor(). Pode
ser utilizado de duas maneiras:
public void setColor(int red, int green, int blue)
public void setColor(int RGB)

Na primeira forma, especifica-se os componentes em padro RGB, intensidade das cores vermelho
(Red), verde (Green) e azul (Blue) que podem variar de 0 a 255. Na segunda forma, aos
componentes da cor so especificados na forma de 0x00RRGGBB. As chamadas para inteiros no
mtodo setColor seguem o cdigo da mesma maneira:
int red, green, blue;
...
setColor(red, green, blue);
setColor( (red<<16) | (green<<8) | blue );

Outro mtodos de manipulao de cores so:


public int getColor() retornar um inteiro da cor atual do formulrio no
formato 0x00RRGGBB
public int getRedComponent() retornar o valor da cor vermelho do componente atual
public int getGreenComponent() retornar o valor da cor verde do componente atual
public int getBlueComponent() retornar o valor da cor azul do componente atual
public int getGrayScale() retornar o valor da escala de cinza da cor atual
public void setGrayScale( definir o valor da escala de cinza para uma prxima
int value) instruo

3.2. Fontes

Um objeto do tipo Font possui trs atributos: face, style e size. As fontes no so criadas pela
aplicao. Ao invs disso, a aplicao pergunta ao sistema por determinados atributos da fonte e
o sistema retorna uma fonte com estes atributos. O sistema no garante que ir retornar uma
fonte com todos os atributos requeridos. Se o sistema no tem uma fonte igual a que requerida,
retornar uma fonte prxima sem respeitar todos os atributos requeridos.
Font uma classe separada. Como comentado anteriormente, a aplicao no cria um objeto
padro. Ao invs disso os mtodos estticos getFont() e getDefaultFont() so utilizados para obter
uma fonte padro para o sistema.
public static Font getFont( retornar um objeto do tipo Font do sistema com
int face, int style, int size) os atributos definidos
public static Font getDefaultFont() retornar a fonte padro utilizada pelo sistema
public static Font retornar a fonte utilizada por um componente
getFont(int fontSpecifier) grfico de auto nvel. O atributo fontSpecifier

Desenvolvimento de Aplicaes Mveis 10


JEDITM

pode ser:
FONT_INPUT_TEXT ou FONT_STATIC_TEXT

O formato da fonte especificado pelo parmetro face que pode assumir uma das seguintes
constantes padro: FACE_SYSTEM, FACE_MONOSPACE ou FACE_PROPORTIONAL.
O estilo da fonte especificado pelo parmetro style que pode assumir uma das seguintes
constantes padro: STYLE_PLAIN (padro) ou a combinao de STYLE_BOLD (negrito),
STYLE_ITALIC (itlico) e STYLE_UNDERLINED (sublinhado). Estilos podem ser combinados
utilizando o operador OR (|). O estilo de uma fonte tipo negrito e itlico declarado como:
STYLE_BOLD| STYLE_ITALIC

O tamanho da fonte especificado pelo parmetro size que pode assumir uma das seguintes
constantes padro: SIZE_SMALL, SIZE_MEDIUM ou SIZE_LARGE.
Estes mtodos retornam os atributos especficos da fonte:
public int getStyle()
public int getFace()
public int getSize()
public boolean isPlain()
public boolean isBold()
public boolean isItalic()
public boolean isUnderlined()

3.3. Estilo do Trao

O mtodo setStrokeStyle(int style) especifica o estilo do cursor que dever ser usado para
desenhar linhas, arcos e retngulos com cantos arredondados. O Estilo do cursor no afeta o
texto, as imagens ou os preenchimentos.
public void setStrokeStyle( definir o estilo do cursor que dever ser usado para desenhar
int style) linhas, arcos e retngulos com cantos arredondados
public int getStrokeStyle() retornar o estilo atual do cursor

Os valores vlidos para o parmetro style so uma das seguintes constantes padro: SOLID ou
DOTTED.

3.4. Clipping

Clipping uma rea retangular em um objeto grfico. Qualquer operao grfica dever afetar
apenas os pontos contidos na rea de corte. Pontos fora da rea de corte no sero afetados por
qualquer operao grfica.
public void setClip( definir a rea de corte para o retngulo
int x, int y, int width, int height) especificado pelas coordenadas
public int getClipX() retornar o valor X da rea de corte atual,
relativo origem deste contexto grfico
public int getClipY() retornar o Y da rea de corte atual, relativo
origem deste contexto grfico
public int getClipWidth() retornar a largura da rea de corte atual
public int getClipHeight() retornar a altura da rea de corte atual

3.5. Pontos ncora

Textos so desenhados por um ponto inicial. O mtodo drawString() espera as coordenadas


localizada nos parmetros x e y que so relativos aos pontos iniciais.

Desenvolvimento de Aplicaes Mveis 11


JEDITM

public void drawString(String str, int x, int y, int anchor)

O ponto deve ser uma combinao da constante horizontal (LEFT, HCENTER ou RIGHT) e a
constante vertical (TOP, BASELINE ou BOTTOM). As constantes horizontal e vertical devem ser
combinadas utilizando o operador OU (|), por exemplo para desenhar o texto pela base horizontal
do centro, ser necessrio um valor inicial de BASELINE | HCENTER.

TOP | HCENTER

TOP | LEFT TOP | RIGHT

BASELINE | LEFT BASELINE | RIGHT

BOTTOM | LEFT BOTTOM | RIGHT

BOTTOM | HCENTER

BASELINE | HCENTER

Figura 4: Texto dos pontos iniciais

3.6. Desenhando Textos

Os mtodos para desenhar texto e caracteres so:


public void drawString( desenhar o texto definido pelo parmetro str
String str, utilizando a cor e fonte atual. Os parmetros x e y
int x, int y, so as coordenadas do ponto inicial
int anchor)
public void drawSubstring( desenhar de maneira semelhante ao mtodo
String str, drawString, exceto pelos parmetros offset que limita
int offset, a base-zero e len que responsvel pelo tamanho
int len,
int x, int y,
int anchor)
public void drawChar( desenhar o caractere usando a cor da fonte atual
char character,
int x,
int y,
int anchor)
public void drawChars( desenhar os caracteres contidos no parmetro data,
char[] data, iniciando pelo ndice definido no parmetro offset
int offset, com o tamanho especificado em length
int length,
int x, int y,
int anchor)

Aqui esto alguns mtodos da classe Font que so teis para o desenho de texto:
public int getHeight() retornar a altura do texto desta fonte. O tamanho
retornado inclui os espaamentos extras. Isto assegura
que o desenho de dois textos com esta distncia a
partir de um ponto de ncora para outro ponto de

Desenvolvimento de Aplicaes Mveis 12


JEDITM

ncora conter espao suficiente entre as duas linhas


de texto
public int stringWidth(String str) retornar a largura total em pixels do espao ocupado
pelo parmetro str se for escrito utilizando-se esta
fonte
public int charWidth(char ch) retornar a largura total em pixels do espao ocupado
pelo parmetro ch se for escrito utilizando-se esta fonte
public int getBaselinePosition() retornar a distncia em pixels entre o TOPO e a BASE
do texto, baseado nesta fonte

g.setColor(255, 0, 0); // vermelho


g.drawString("JEDI",
getWidth()/2, getHeight()/2,
Graphics.TOP | Graphics.HCENTER);
g.setColor(0, 0, 255); // azul
Font font = g.getFont();
g.drawString("Java Education & Development Initiative",
getWidth()/2, getHeight()/2+font.getHeight(),
Graphics.TOP | Graphics.HCENTER);

Figura 5: Sada de operaes de drawString()

3.7. Desenhando Linhas

O nico mtodo da classe Graphics utilizado para desenhar linhas definido como:
public void drawLine(int x1, int y1, int x2, int y2)

Este mtodo desenha uma linha utilizando a cor e estilo corrente entre a coordenada inicial
indicada nos parmetros x1 e y1 e a coordenada final indicada nos parmetros x2 e y2.
g.setColor(255, 0, 0); // vermelho
// linha do canto superior esquerdo para o canto inferior direito da tela
g.drawLine(0, 0, getWidth()-1, getHeight()-1);

g.setColor(0, 255, 0); // verde


// linha horizontal no meio da tela
g.drawLine(0, getHeight()/2, getWidth()-1, getHeight()/2);

g.setColor(0, 0, 255); // azul


// linha horizontal na parte inferior da tela
g.drawLine(0, getHeight()-1, getWidth()-1, getHeight()-1);

g.setColor(0, 0, 0); // preta

Desenvolvimento de Aplicaes Mveis 13


JEDITM

// linha do canto inferior esquerdo para o canto superior direito da tela


g.drawLine(0, getHeight()-1, getWidth()-1, 0);

Figura 6: Sada de chamadas a mtodos de drawLine()

3.8. Desenhando Retngulos

Os mtodos da classe Graphics para desenhar retngulos so:


public void drawRect(int x, int y, int width, int height)
public void drawRoundRect(int x, int y,
int width, int height,
int arcWidth, int arcHeight)
public void fillRect(int x, int y, int width, int height)
public void fillRoundRect(int x, int y,
int width, int height,
int arcWidth, int arcHeight)

O mtodo drawRect desenha um retngulo com o canto superior esquerdo nas coordenadas
definidas pelos parmetros x e y e com rea definida em width+1 e height+1. Os mesmos
parmetros esto no mtodo drawRoundRect. Os parmetros adicionais arcWidth e arcHeight so
os dimetros horizontal e vertical do arco dos quatro cantos.
Note que a definio dos mtodos drawRect e drawRoundRect especificam que o tamanho do
retngulo desenhado na tela width+1 e a altura height+1. Isto no muito intuitivo,
entretanto desta forma que estes mtodos foram definidos para as especificaes de MIDP.
Para agravar esta inconsistncia de adicionar 1 ao tamanho real, os mtodos fillRect e
fillRoundRect preenchem um retngulo de rea especificada por width e height. Devido a esta
inconsistncia pode-se colocar os mesmos parmetros para os mtodos drawRect, fillRect,
drawRoundRect e fillRoundRect. As bordas da direita e da parte inferior do retngulo desenhado
pelo mtodo drawRect estaro alm da rea preenchida por fillRect.
// use tinta preta para drawRect
g.setColor(0, 0, 0);
g.drawRect(8, 8, 64, 32);

// use tinta amarela para fillRect


// para mostrar a diferena entre drawRect e fillRect
g.setColor(255, 255, 0);
g.fillRect(8, 8, 64, 32);

Desenvolvimento de Aplicaes Mveis 14


JEDITM

Figura 7: Sada usando os mesmos parmetros para drawRect e fillRect

// Define a cor da caneta para preto


g.setColor(0, 0, 0);

// Desenha um retngulo na posio inicial 4 e 8 com largura 88 e altura 44


// o retngulo superior esquerdo
g.drawRect(4,8,88,44);

// Desenha um retngulo arredondado no canto superior direito


g.drawRoundRect(108,8,88,44,18,18);

// Desenha um retngulo no canto inferior esquerdo


g.fillRect(4,58,88,44);

// Desenha um retngulo no canto inferior direito


g.fillRoundRect(108,58,88,44,18,18);

Figura 8: drawRect(), fillRect(), drawRoundRect() e fillRoundRect()

3.9. Desenhando Arcos

Os mtodos para desenhar arcos circulares ou elpticos so:

Desenvolvimento de Aplicaes Mveis 15


JEDITM

public void drawArc( desenhar um arco com centro em (x,y) e


int x, int y, dimenses (largura+1 x altura+1). O arco
int largura, desenhado inicia-se em anguloInic e se estende
int altura,
int anguloInic, por anguloArco graus. 0 (zero) grau est na
int anguloArco) posio 3 horas
public void fillArc( desenhar um um arco circular ou elptico com
int x, int y, toda a sua rea coberta com a cor atual
int largura,
int altura,
int anguloInic,
int anguloArco)

g.setColor(255, 0, 0);
g.drawArc(18, 18, 50, 50, 0, 360); // desenha um crculo
g.setColor(0, 255, 0);
g.drawArc(40, 40, 100, 120, 0, 180);
g.setColor(0, 0, 255);
g.fillArc(100, 200, 80, 100, 0, 90);

Figura 9: Sada da chamada aos mtodos drawArc e fillArc

3.10. Desenhando imagens

Imagens so desenhadas usando o mtodo drawImage() que possui a seguinte assinatura:


public void drawImage(Image img, int x, int y, int anchor)

Ateno: No NetBeans as imagens devem ser colocadas na pasta src do projeto.


Do mesmo modo que no mtodo drawString(), os parmetros x e y so as coordenadas do ponto
de ncora. A diferena que a constante vertical da ncora VCENTER em vez de BASELINE.
A ncora deve ser uma combinao de uma constante horizontal (LEFT, HCENTER ou RIGHT) e de
uma vertical (TOP, VCENTER ou BOTTOM). As constantes horizontal e vertical devem ser
combinadas usando o operador de bit OR (|). Isto significa que desenhar texto relativo ao centro
vertical e ao centro horizontal da imagem requer uma ncora de valor VCENTER | HCENTER.

Desenvolvimento de Aplicaes Mveis 16


JEDITM

TOP | HCENTER

TOP | LEFT TOP | RIGHT

VCENTER | LEFT VCENTER | RIGHT

BOTTOM | LEFT BOTTOM | RIGHT

VCENTER | HCENTER BOTTOM | HCENTER

Figura 10: Pontos de ncora da imagem

try {
Image image = Image.createImage("/jedi.png");
g.drawImage(image,
getWidth()/2, getHeight()/2,
Graphics.VCENTER | Graphics.HCENTER);
} catch (Exception e){}

Figura 11: Sada do mtodo drawImage()

3.11. Programa Final

Iremos combinar as idias aprendidas nesta lio para obtermos o logo do JEDI na tela do celular.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class LogoMidlet extends MIDlet {


private Display display;
private LogoJedi canvas;

Desenvolvimento de Aplicaes Mveis 17


JEDITM

public void startApp() {


if (display == null){
canvas = new LogoJedi(this);
display = Display.getDisplay(this);
}
display.setCurrent(canvas);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
protected void Quit(){
destroyApp(true);
notifyDestroyed();
}
}
class LogoJedi extends Canvas implements CommandListener {
private Command exitCommand = new Command("Exit", Command.EXIT, 0);
private LogoMidlet midlet;
private String text;
public LogoJedi(LogoMidlet midlet) {
this.midlet = midlet;
addCommand(exitCommand);
setCommandListener(this);
}
protected void paint(Graphics g) {
// Limpa a janela
g.setColor(255, 255, 255 );
g.fillRect(0, 0, getWidth(), getHeight());
// Imagem
try {
Image image = Image.createImage("/jedi.png");
g.drawImage(image,
getWidth()/2, 80,
Graphics.VCENTER | Graphics.HCENTER);
} catch (Exception e){ }
// Texto
g.setColor(255, 0, 0); // vermelho
Font f =
Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE);
g.setFont(f);
g.drawString("JEDI", getWidth()/2, getHeight()/2,
Graphics.TOP | Graphics.HCENTER);
int tamFont = f.getHeight();

g.setColor(0, 0, 255); // azul


g.drawLine(20, getHeight()/2+tamFont, getWidth()-20, getHeight()/2+tamFont);
f = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL);
g.setFont(f);
g.drawString("Java Education & Development Initiative",
getWidth()/2, getHeight()/2+tamFont+3,
Graphics.TOP | Graphics.HCENTER);
}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand){
midlet.Quit();
}
}
}

Desenvolvimento de Aplicaes Mveis 18


JEDITM

4. Exerccios
4.1. Cdigos de Teclas

Criar um MIDlet que mostre o cdigo e o nome da tecla que foi pressionada pelo usurio. Utilizar
um Canvas para mostrar este cdigo e o nome no centro da tela.

Desenvolvimento de Aplicaes Mveis 19


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 5
Sistema de Gerenciamento de Registro

Verso 1.0 - Set/2007


JEDITM

1. Objetivos
MIDP fornece uma biblioteca de componentes onde os programas podem salvar os dados da
aplicao no dispositivo de modo fsico. O Sistema de Gerenciamento de Registro do MIDP o
meio pelo qual as MIDlets podem armazenar dados atravs de chamadas MIDlet. Os dados so
armazenados na memria no-voltil do dispositivo, ou seja, no sero perdidos mesmo que o
programa seja finalizado ou o aparelho seja desligado.
O Sistema de Gerenciamento de Registro um sistema de banco de dados orientados a registro
para dispositivos MIDP. Um registro neste banco de dados simplesmente um array de bytes com
um ndice.

Ao final desta lio, o estudante ser capaz de:


Entender o conceito de RecordStore
Criar ou abrir um RecordStore
Adicionar, recuperar, atualizar e excluir registros
Fechar um RecordStore
Enumerar registros utilizando um RecordEnumerator
Criar um RecordComparator
Criar um RecordFilter

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. RecordStore
Record Store uma coleo de registros, a classe encontrada no pacote javax.microedition.rms.
Identificadores de registro (Record ID) em um banco de dados so nicos. Esses identificadores
so automaticamente alocados no momento da criao do registro e funcionam como um ndice
ou chave primria. So atribudos sequencialmente, sendo que o primeiro ID de cada banco de
dados possui o valor igual a 1 (um).
Quando um registro excludo, seu identificador no ser reutilizado. Se criarmos quatro
registros e excluirmos o quarto, o prximo identificador que o sistema atribuir ser igual a 5 (ver
Figura).

Record ID Array de bytes


1 Dado do registro #1
2 Dado do registro #2
3 Dado do registro #3
5 Dado do registro #5

Aplicativos MIDlets podem criar mais de um objeto RecordStore. O nome do RecordStore deve ser
nico dentro de uma suite MIDlet. So sensveis ao contexto (maisculas diferentes de
minsculas) e devem possuir um tamanho mximo de 32 caracteres.
Quando uma aplicao MIDlet eliminada de um dispositivo, todos os RecordStore associados a
esta aplicao tambm sero eliminados.

2.1. Criando ou Abrindo um RecordStore

Os mtodos listados abaixo criam ou abrem para uso um RecordStore:


static RecordStore openRecordStore(
String recordStoreName,
boolean createIfNecessary)
static RecordStore openRecordStore(
String recordStoreName,
boolean createIfNecessary,
int authmode,
boolean writable)
static RecordStore openRecordStore(
String recordStoreName,
String vendorName,
String suiteName)

Caso o parmetro createIfNecessary possuir o valor true e o RecordStore no existir, este ser
automaticamente criado. Se o parmetro possuir o valor false e o RecordStore no existir, uma
exceo do tipo RecordStoreNotFoundException ser lanada.
O parmetro authmod poder assumir um dos seguintes atributos constantes existentes:
RecordStore.AUTHMODE_PRIVATE ou RecordStore.AUTHMODE_ANY. Utilizando o primeiro atributo
o RecordStore ser acessvel apenas pela aplicao MIDlet que o criou. Utilizando o segundo
atributo o RecordStore ser acessvel por qualquer aplicao MIDlet. O modo de acesso
especificado pelo parmetro lgico writable. Para permitir que outros MIDlets (fora do aplicativo
que o criou) armazenem ou leiam dados neste Record Store, este parmetro dever ser informado
com o valor true.
Utilizando a primeira forma do mtodo openReacordStore() o resultado obtido que o
RecordStore ser acessvel somente aos MIDlets da mesma aplicao (o valor do atributo
authmode ter o mesmo valor da constante AUTHMODE_PRIVATE).
Para abrir um RecordStore existente a partir de uma aplicao MIDlet diferente, a terceira forma
do mtodo openRecordStore utilizada. Os parmetros vendorName e suiteName devero ser

Desenvolvimento de Aplicaes Mveis 5


JEDITM

especificados contendo o nome do desenvolvedor e o nome do aplicativo.


Se o RecordStore j estiver aberto, estes mtodos iro retornar sua referncia deste. O sistema
mantm armazenado quantas vezes foram abertos os RecordStore. obrigatrio que RecordStore
seja fechado o mesmo nmero de vezes que tenha sido aberto.

2.2. Adicionando Registros

O seguinte mtodo responsvel pelas adies de novos registros em um RecordStore:


int addRecord(byte[] data, int offset, int numBytes)

O mtodo addRecord criar um novo registro no banco de dados e retornar o seu identificador
(Record ID). As informaes recebidas como parmetro neste mtodo so:
1. Um array de bytes contendo os dados a serem armazenados
2. Um atributo inteiro contendo a posio inicial do array enviado
3. A quantidade total de elementos do array

2.3. Recuperando Registros

Os seguintes mtodos so responsveis pelas buscas de dados em um Record Store:


byte[] getRecord(
int recordId)
int getRecord(
int recordId, byte[] buffer, int offset)
int getRecordSize(
int recordId)

A primeira forma do mtodo getRecord devolve uma cpia dos dados armazenados no registro
com a Record ID especificada pelo parmetro. A segunda forma copiar os dados no parmetro
(array de bytes) fornecido Ao utilizar esta forma, o array de bytes precisa estar previamente
alocado. Caso o tamanho do registro seja maior que o tamanho do parmetro uma exceo
ArrayIndexOutOfBoundsException ser lanada. O mtodo getRecordSize utilizado de modo a
obter o tamanho do registro que ser lido.

2.4. Modificando Registros

No se pode modificar somente uma parte do registro. Para modificar um registro necessrio:
1. Ler o registro utilizando o mtodo getRecord
2. Modificar o registro na memria
3. Chamar o mtodo setRecord para modificar os dados do registro

O mtodo setRecord possui a seguinte assinatura:

void setRecord(
int recordId, byte[] newData, int offset, int numBytes)

2.5. Eliminando Registros

O seguinte mtodo responsvel pelas eliminaes dos dados em um RecordStore:


void deleteRecord(
int recordId)

Quando um registro eliminado, o ID deste registro no ser reutilizado para as prximas


incluses. Isto significa que podem ocorrer buracos entre os registros. Deste modo no
aconselhvel utilizar um incrementador para listar todos os registros de um Record Store. Um

Desenvolvimento de Aplicaes Mveis 6


JEDITM

RecordEnumerator deve ser utilizado para percorrer a lista de registros guardados.

2.6. Fechando um RecordStore

O seguinte mtodo responsvel pelo fechamento de um RecordStore:


void closeRecordStore()

Ao chamar o mtodo closeRecordStore(), o RecordStore no ser fechado at que seu valor seja
idntico ao nmero de chamadas do mtodo openRecordStore(). O sistema armazena o nmero
de vezes que um Record Store foi aberto. Caso o nmero de chamadas ao mtodo
closeRecordStore() sejam superiores ao nmero de chamadas ao mtodo openRecordStore(), ser
disparada uma exceo do tipo RecordStoreNotOpenException.
Este trecho de cdigo mostra um exemplo de um MIDlet simples que exemplifica a criar, adio e
localizao de dados em um RecordStore:
// Abre ou Cria um RecordStore com o nome "RmsExample1"
recStore = RecordStore.openRecordStore("RmsExample1", true);

// L o contedo do RecordStore
for (int recId=1; recId <= recStore.getNumRecords(); recId++){
// O mtodo getRecord returna o tamanho do registro
recLength = recStore.getRecord(recId, data, 0);

// Converte para String um array de bytes


String item = new String(data, 0, recLength);
...
}

// Este ser o dado a ser guardado


String newItem = "Record #" + recStore.getNextRecordID();

// Converte a String para o array de bytes


byte[] bytes = newItem.getBytes();

// Grava o dado no RecordStore


recStore.addRecord(bytes, 0, bytes.length);

Dicas de Programao:

1. O Registro comea com o valor de ID igual a 1, e no 0. Deve-se tomar cuidado ao se utilizar


laos.
2. melhor utilizar um RecordEnumerator do que um ndice incrementado (como neste
exemplo). Registros eliminados ainda sero lidos por este exemplo e causar uma exceo do
tipo InvalidRecordIDException.

2.7. Obtendo uma Lista de RecordStore de uma aplicao MIDlet

O seguinte mtodo responsvel pela obteno de uma lista de RecordStore existente:


static String [] listRecordStores()

O mtodo retorna um conjunto de nomes de RecordStore que foram criados pela aplicao
MIDlet. Se a aplicao no possuir nenhum RecordStore retornado o valor null.
String[] storeNames = RecordStore.listRecordStores();
System.out.println("RecordStore for this MIDlet suite:");

for (int i=0; storeNames != null && i < storeNames.length; i++) {


System.out.println(storeNames[i]);
}

Este um exemplo de sada:

Desenvolvimento de Aplicaes Mveis 7


JEDITM

Record Stores for this MIDlet suite:


Prefs
RmsExample1
RmsExample2

A ordem dos nomes retornados no est definida e dependente da implementao. Ento, ao se


desejar exibir os nomes ordenados alfabeticamente, primeiro deve-se realizar uma ordenao
deste array.

2.8. Guardando Tipos Primitivos de Java

At o momento, os dados que temos gravados e lidos no RecordStore so Strings. CLDC inclui as
classes padres para manipulao de tipos primitivos. Estas classes so da biblioteca padro da
Plataforma Java Standard Edition (Java SE).
Pode-se gravar tipos primitivos combinando as classes ByteArrayOutputStream e
DataOutputStream. Para ler tipos primitivos (int, long, short, char, boolean, etc) pode-se tambm
utilizar as classes ByteArrayInputStream e DataInputStream.
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dOut = new DataOutputStream(out);

// Armazenando um inteiro
dOut.writeInt(recStore.getNextRecordID() * recStore.getNextRecordID());

// Armazenando uma String


dOut.writeUTF("Record #" + recStore.getNextRecordID());

// Transformando para um array de bytes


byte[] bytes = out.toByteArray();

// Armazenando os dados no Record Store


recStore.addRecord(bytes, 0, bytes.length);
...

// Obtendo o prximo registro


byte[] recBytes = enumerator.nextRecord();

// Para resgatar os valores


ByteArrayInputStream in = new ByteArrayInputStream(recBytes);
DataInputStream dIn = new DataInputStream(in);
int count = dIn.readInt();
String item = dIn.readUTF();

2.9. Outros mtodos para um RecordStore

Os seguintes mtodos podem ser utilizados para obter dados de um RecordStore:


long getLastModified()
int getVersion()

O sistema armazena a informao de quando um Record Store foi modificado pela ltima vez.
Este valor pode ser obtido atravs do mtodo getLastModified() e retorna um valor do tipo long,
que poder ser utilizado pelo mtodo System.currentTimeMillis().
O RecordStore mantm a informao da verso que pode ser obtida atravs do mtodo
getVersion(). Toda vez em que um registro modificado, seu nmero de verso atualizado.
Utilizando-se qualquer um dos mtodos addRecord, setRecord e deleteRecord o nmero de verso
do objeto ser incrementado.
Outros mtodos que podem ser utilizados so:
static void deleteRecordStore( Eliminar a RecordStore que contenha o nome fornecido
String nomeRecordStore)
String getName() Retornar o nome do RecordStore

Desenvolvimento de Aplicaes Mveis 8


JEDITM

int getNextRecordID() Retornar o recordId do prximo registro a ser adicionado ao objeto


RecordStore
int getNumRecords() Retornar o nmero de registros atualmente no RecordStore
int getSize() Retornar a quantidade de bytes ocupados em um RecordStore
int getSizeAvailable() Retornar a quantidade de bytes disponveis em um RecordStore
void setMode( Modificar o modo de acesso de um RecordStore
int authmode,
boolean writable)

Desenvolvimento de Aplicaes Mveis 9


JEDITM

3. Enumerao de Registro
Percorrer registros incrementando um ndice uma forma ineficiente de agir. O RecordStore pode
ter seus registros eliminados que geram buracos no RecordId.
A utilizao de um RecordEnumeration resolve este problema sem ter de tratar os registros
excludos. possvel tambm ordenar um objeto do tipo RecordEnumeration utilizando-se o
mtodo comparator(). Utilizando-se o mtodo filter(), pode-se saltar os registros que no so
importantes para o resultado.
RecordEnumeration enumerateRecords(
RecordFilter filter,
RecordComparator comparator,
boolean keepUpdated)

O mtodo enumerateRecords de um RecordStore retornar um objeto do tipo RecordEnumeration,


no qual permitido obter todos os registros de um RecordStore. Essa a maneira recomendada
para percorrer todos os registros armazenados. Iremos discutir os objetos filter e comparator nas
prximas sees.
O modo mais simples para utilizar esse mtodo informar o valor null para os parmetros filter e
comparator. Obteremos como retorno da execuo deste mtodo um objeto do tipo
RecordEnumeration de todos os registros do Record Store ordenados de uma maneira indefinida.
// Abrir ou criar um Record Store com o nome "RmsExample2"
recStore = RecordStore.openRecordStore("RmsExample2", true);

// Carregar o contedo do Record Store


RecordEnumeration enumerator = recStore.enumerateRecords(null, null, false);
while (enumerator.hasNextElement()){
// Obter o prximo registro e converter um array de byte em String
String item = new String(enumerator.nextRecord());

// Realiza qualquer instruo com o dado


...
}

Desenvolvimento de Aplicaes Mveis 10


JEDITM

4. Comparador de Registros
A ordenao de um objeto do tipo RecordEnumeration pode ser definida utilizando-se um
RecordComparator. Um RecordComparator passado para o mtodo enumerateRecords. Caso
seja necessrio ordenar um objeto do tipo RecordEnumeration, isso pode ser feito definindo-se
um objeto do tipo RecordComparator e enviando-o como o segundo parmetro para o mtodo
enumerateRecords.
int compare(byte[] reg1, byte[] reg2)

Para criar um RecordComparator, preciso primeiro implementar a interface RecordComparator.


Essa interface define um nico mtodo compare(byte[] reg1, byte[] reg2). Esse mtodo precisa
retornar RecordComparator.FOLLOWS ou RecordComparator.PRECEDES se reg1 procede ou
antecede reg2 na ordem, respectivamente. RecordComparator.EQUIVALENT pode ser retornado se
reg1 for igual a reg2 na ordem.
// Criar uma enumeration, ordenada alfabeticamente
RecordEnumeration enumerator = recStore.enumerateRecords(
null, new AlphaOrder(), false);

// Classe que ordena alfabeticamente


class AlphaOrder implements RecordComparator {
public int compare(byte[] reg1, byte[] reg2){
String registro1 = new String(reg1).toUpperCase();
String registro2 = new String(reg2).toUpperCase();
if (registro1.compareTo(registro2) < 0){
return(RecordComparator.PRECEDES);
} else {
if (registro1.compareTo(registro2) > 0){
return(RecordComparator.FOLLOWS);
} else {
return(RecordComparator.EQUIVALENT);
}
}
}
}

Desenvolvimento de Aplicaes Mveis 11


JEDITM

5. Filtro de Registros
Os exemplos que vimos at o momento somente percorrem e lem todos registros de um Record
Store. Entretanto, podemos utilizar um filter para obtermos somente os registros que so
necessrios.
A classe necessita implementar o mtodo match() para selecionar somente os registros vlidos
em um determinado contexto.
boolean matches(byte[] candidate)

O retorno um atributo do tipo lgico que deve conter o valor true caso o registro seja compatvel
com o critrio definido. Caso contrrio retornado false.
public boolean matches(byte[] candidate){
boolean resultado = false;
try {
ByteArrayInputStream bin = new ByteArrayInputStream(candidate);
DataInputStream dIn = new DataInputStream(bin);
int count = dIn.readInt();
String item = dIn.readUTF();

// Retornar somente registros com o contedo terminado com 0


resultado = item.endsWith("0");
} catch (Exception e) {
}
return(resultado);
}

Desenvolvimento de Aplicaes Mveis 12


JEDITM

6. Consumo de Combustvel
Iremos ajuntar algumas idias aprendidas at o momento e montar um aplicativo prtico para
controlar o consumo de combustvel do nosso carro.
Ao pensarmos em aplicativos para aparelhos mveis devemos ter em mente as seguintes regras:
1. Praticidade
2. Facilidade
O usurio estar no posto abastecendo o carro. Ao acessar o aplicativo precisamos obter duas
informaes: a quilometragem atual do veculo e a quantidade de combustvel inserida. Neste
primeiro registro ainda no teremos dados suficientes para o clculo do consumo, entretanto, a
partir do segundo registro j poderemos calcular o consumo, obtido pela frmula:
(quilometragem atual quilometragem anterior) / quantidade combustvel

Uma outra idia interessante guardar somente as ltimas 11 entradas, deste modo
mostraremos as 10 ltimas mdias de consumo. Antes de verificar as classes descritas abaixo,
tente resolver este aplicativo.
A primeira classe chamada PrincipalMidlet. Conforme vimos anteriormente, o mtodo startApp()
far a chamada a um objeto do tipo Canvas.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class PrincipalMidlet extends MIDlet {


private MenuCanvas canvas;
public Display display;

public void startApp() {


if (display == null) {
canvas = new MenuCanvas(this);
display = Display.getDisplay(this);
}
display.setCurrent(canvas);
}
protected void pauseApp() {
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}
}

A segunda classe, chamada MenuCanvas, do tipo Canvas, conter toda a regra de negcio.
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDletStateChangeException;
import javax.microedition.rms.*;

public class MenuCanvas extends Canvas implements CommandListener {

private PrincipalMidlet pai;


private InsertForm form;
private byte opc = 0;
private Command exitCmd = new Command("Exit", Command.EXIT, 0);
private Command insertCmd = new Command("Insert", Command.OK, 1);
private Command reportCmd = new Command("Report", Command.OK, 1);
// Comandos para o Form
private Command backCmd = new Command("Back", Command.BACK, 2);
private Command saveCmd = new Command("Save", Command.OK, 1);
// Atributos para o Registro
private String regGas;
private RecordStore rsGas;

public MenuCanvas(PrincipalMidlet pai) {

Desenvolvimento de Aplicaes Mveis 13


JEDITM

// Cria ou abre o registro


try {
rsGas = RecordStore.openRecordStore("Gasolina", true);
} catch (RecordStoreException ex) {
ex.printStackTrace();
}
this.pai = pai;
setCommandListener(this);
addCommand(exitCmd);
addCommand(insertCmd);
addCommand(reportCmd);
}
public void paint(Graphics g) {
g.setColor(255, 255, 255);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(0, 64, 128);
switch (opc) {
case 0:
g.drawString("Principal Menu", 0, 0,
Graphics.TOP | Graphics.LEFT);
g.setColor(0, 114, 168);
g.drawString("Use this program for the control", 0, 24,
Graphics.TOP | Graphics.LEFT);
g.drawString("the consumption of gasoline in your car", 0, 36,
Graphics.TOP | Graphics.LEFT);
g.drawString("Options:", 0, 64, Graphics.TOP | Graphics.LEFT);
g.drawString("INSERT - Use for add record Km/Lt", 0, 76,
Graphics.TOP | Graphics.LEFT);
g.drawString("REPORT - Use for list the 10 last consumer", 0, 88,
Graphics.TOP | Graphics.LEFT);
g.drawString("Fernando Anselmo", 0, 112, Graphics.TOP | Graphics.LEFT);
break;
case 1:
int lin = 0;
g.drawString("Report Option", 0, lin, Graphics.TOP | Graphics.LEFT);
lin += 14;
g.drawString("Your 10 last consumes is...", 0, lin,
Graphics.TOP | Graphics.LEFT);
lin += 12;
int od1 = 0;
int od2 = 0;
double gas = 0.0;
g.setColor(0, 114, 168);
try {
if (rsGas.getNumRecords() > 1) {
for (int recId = 1; recId < rsGas.getNumRecords(); recId++) {
regGas = new String(rsGas.getRecord(recId));
od1 = Integer.parseInt(regGas.substring(0, regGas.indexOf("|")));
gas = Double.parseDouble(regGas.substring(
regGas.indexOf("|") + 1));
regGas = new String(rsGas.getRecord(recId + 1));
od2 = Integer.parseInt(regGas.substring(0, regGas.indexOf("|")));
lin += 15;
g.drawString(recId + ") " + ((od2 - od1) / gas) +
" Km/Lt", 0, lin, Graphics.TOP | Graphics.LEFT);
}
}
} catch (RecordStoreException ex) {
ex.printStackTrace();
}
break;
}
}
public void commandAction(Command command, Displayable displayable) {
if (command == exitCmd) {
try {
rsGas.closeRecordStore();

Desenvolvimento de Aplicaes Mveis 14


JEDITM

pai.destroyApp(true);
pai.notifyDestroyed();
} catch (RecordStoreException ex) {
ex.printStackTrace();
} catch (MIDletStateChangeException ex) {
ex.printStackTrace();
}
} else if (command == insertCmd) {
repaint();
form = new InsertForm("Insert Option");
pai.display.setCurrent(form);
} else if (command == reportCmd) {
opc = 1;
repaint();
} else if (command == backCmd) {
pai.display.setCurrent(this);
opc = 0;
repaint();
} else if (command == saveCmd) {
regGas = form.getRegGas();
byte[] data;
try {
if (rsGas.getNumRecords() == 11) {
for (int recId = 1; recId < rsGas.getNumRecords(); recId++) {
data = rsGas.getRecord(recId + 1);
rsGas.setRecord(recId, data, 0, data.length);
}
data = regGas.getBytes();
rsGas.setRecord(11, data, 0, data.length);
} else {
data = regGas.getBytes();
rsGas.addRecord(data, 0, data.length);
}
} catch (RecordStoreException ex) {
ex.printStackTrace();
}
pai.display.setCurrent(this);
opc = 0;
repaint();
}
}
class InsertForm extends Form {
private TextField QTDGAS;
private TextField ODOMETER;

public InsertForm(String title) {


super(title);
addCommand(backCmd);
addCommand(saveCmd);
setCommandListener(MenuCanvas.this);
ODOMETER = new TextField("Odometer (Kilometer):", "", 64,
TextField.NUMERIC);
QTDGAS = new TextField("Gasoline (Liter):", "", 64, TextField.DECIMAL);
this.append(new StringItem("Inform your consumption", ""));
this.append(ODOMETER);
this.append(QTDGAS);
}
public String getRegGas() {
return ODOMETER.getString() + "|" + QTDGAS.getString();
}
}
}

Comearemos pelo construtor que montar a janela principal. Observe que o atributo opc do tipo
byte possuir o controle sobre qual viso da aplicao temos. O construtor tambm inicializa o
objeto do tipo RecordStore (chamado rsGas). Logo em seguida o mtodo paint ser chamado e

Desenvolvimento de Aplicaes Mveis 15


JEDITM

mostrar a seguinte janela:

Figura 1: Janela do Menu Principal

Caso o comando seja Insert, passaremos para o mtodo commandAction. Neste momento
montaremos um objeto da classe Form e a definiremos como principal. Montaremos com este
formulrio a seguinte janela:

Figura 2: Janela da Opo de Incluso

O usurio entrar com a informao da quantidade de quilmetros percorridos pelo carro at o


momento e a quantidade de litros abastecidos. Pode-se escolher a opo Save para salvar o
registro, ou Back para retornar ao menu principal.
Caso seja selecionada a opo Save, realizaremos a verificao se j foram inseridos 11
registros. Em caso afirmativo, movimentaremos o registro que ocupa a segunda posio para a
primeira, o que ocupa a terceira posio para a segunda e deste modo sucessivamente at que se
libere a dcima primeira posio, onde guardaremos este novo registro. Em caso negativo,
simplesmente inserimos mais um registro ao RecordStore.
No menu principal, caso o comando seja Report, passaremos para o mtodo commandAction,

Desenvolvimento de Aplicaes Mveis 16


JEDITM

mudando o atributo opc e montamos agora a seguinte janela:

Figura 3: Janela da Opo de Relatrio

Agora fica por conta do mtodo paint localizar os registros informados e realizar o clculo
conforme vimos, lembrando que o mtodo indexOf(String) localiza uma determinada posio
dentro de um objeto String e o mtodo substring(int1, int2) localiza uma determinada posio e
retorna todos os caracteres a partir desta enquanto a posio seja menor que o segundo valor.
Note que este projeto est bem compacto e ainda permite diversas melhorias, tais como:
Imagens
Opes para o usurio selecionar quantos registro deseja armazenar
Um grfico para mostrar o consumo ao invs de informao textual
Ento, utilize-o como aplicativo base para praticar.

Desenvolvimento de Aplicaes Mveis 17


JEDITM

7. Exerccios
7.1. Armazenar Preferncias

Criar um aplicativo MIDlet que possa armazenar as preferncias de um programa. Este aplicativo
ir armazenar as preferncias em um objeto do tipo RecordStore. Cada registro ir conter o nome
de uma varivel e seu valor. Cada conjunto varivel e valor ser armazenado em um nico
registro.
Dica: Pode-se implementar os mtodos:
public String ler(RecordStore recStore, String nome, String valorPadrao);
public void escrever(RecordStore recStore, String nome, String valor);

Desenvolvimento de Aplicaes Mveis 18


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 6
Redes

Verso 1.0 - Set/2007


JEDITM

1. Objetivos
Nesta lio, iremos estudar como acessar redes utilizando MIDlets.

Ao final desta lio, o estudante ser capaz de:


Descrever o Framework Genrico de Conexo e como pode ser usado para suportar
diferentes mtodos de conexo
Especificar argumentos de conexo usando o formato de endereo URL do GCF
Criar conexes HTTP/HTTPS
Criar MIDlets usando soquetes TCP e datagramas UDP

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. Framework Genrico de Conexo


O Framework Genrico de Conexo suporta as conexes baseadas em pacotes (atravs de
Soquetes) e baseadas em stream (atravs de Datagramas). Como o nome diz, este framework
prov uma API bsica para conexes em CLDC. Determina uma base comum para conexes como
HTTP, soquetes e datagramas. Mesmo bluetooth e serial I/O tem um lugar neste framework.
Fornece um conjunto genrico e comum da API que abstrai todos os tipos de conexes. Deve-se
notar que nem todos os tipos de conexo devem ser requeridos para ser implementados pelos
dispositivos MIDP.

2.1. Hierarquia da Interface GCF

A hierarquia extensvel da interface do GCF torna possvel a generalizao. Um novo tipo de


conexo pode ser adicionado a este framework atravs da extenso desta hierarquia.

Figura 1: Hierarquia da Interface GCF

2.2. A URL de Conexo GCF

Argumentos de conexo so especificados usando o formato de endereamento:


scheme://username:password@host:port/path;parameters

1. scheme (esquema) o protocolo ou mtodo de conexo. Exemplos de esquemas so: http, ftp
e https
2. username (nome do usurio) opcional, entretanto, caso seja especificado, um @ deve
preceder o host
3. password (senha do usurio) opcional e pode ser especificada somente se o username
estiver presente. Se a password estiver presente, deve estar separada do username por dois
pontos (:)

Desenvolvimento de Aplicaes Mveis 5


JEDITM

4. host (domnio) este argumento obrigatrio. Pode ser um hostname, um nome completo no
domnio (FQDN) ou o endereo IP do host alvo.
5. port (porta) este argumento opcional. Caso no seja especificado, a porta padro para o
esquema ser utilizada.
6. path (caminho)
7. parameters (argumentos) este opcional, mas deve estar precedido por ponto e vrgula
quando presente
Se utilizarmos colchetes para definir os argumentos opcionais neste formato de endereamento,
poderemos expressar da seguinte forma:
scheme://[username[:password]@]host[:port]/path[;parameters]

O Uniform Resource Indicator (URI) est definido no RFC 2396, que a base para este formato de
endereamento. No MIDP 2.0, somente os esquemas "http" e "https" devem ser implementados
por estes dispositivos.

Desenvolvimento de Aplicaes Mveis 6


JEDITM

3. Conexo HTTP
3.1. O Protocolo HTTP

HTTP significa Protocolo de Transporte de Hiper Texto. Este o protocolo utilizado para transferir
pginas da WEB de seus servidores (ex. www.sun.com) para os WEB Browsers. O cliente (WEB
Browser) requisita uma pgina, especificando o seu caminho com os modelos do tipo "GET" ou
"POST".
Para o modelo "GET", argumentos so especificados e embutidos na URL. Por exemplo, para
passar um atributo com o nome "id" e valor 100 a pgina "index.jsp", a URL especificada da
seguinte forma: "http://hostname/index.jsp?id=100". Argumentos adicionais so separados pelo
simbolo &, por exemplo: "http://hostname/index.jsp?id=100&page=2".
Quando o modelo "POST" utilizado, argumentos no fazem parte da URL, mas so enviados em
linhas diferentes aps o comando POST.
Cliente / Navegador WEB Servidor HTTP
GET /index.jsp?id=100 HTTP/1.1 HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Date: Wed, 18 Jun 2005 14:09:31 GMT
Connection: close

<html>
<head>
<title>Test Page</title>
</head>
<body>
<h1 align="center">Test Page</h1>
</body>
</html>
Figura 2: Exemplo de Transao HTTP GET

Cliente / Navegador WEB Servidor HTTP


GET /non-existent.html HTTP/1.0 HTTP/1.1 404 /non-existent.html
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 983
Date: Mon, 11 Jul 2005 13:21:01 GMT
Connection: close

<html><head><title>Apache Tomcat/5.5.7 - Error


report</title><style>...
<body><h1>HTTP Status 404</h1>
...
The requested resource (non-existent.html) is
not available.
...
</body></html>
Figura 3: Exemplo de transao HTTP GET com um response erro

3.2. Criando uma conexo HTTP

Podemos abrir uma conexo HTTP usando o mtodo Connector.open() e fazer um casting com
uma das seguintes interfaces: StreamConnection, ContentConnection ou HTTPConnection.
Entretanto, com as interfaces StreamConnection e ContentConnection podemos especificar e
derivar parmetros especficos do HTTP resultante.
Quando se utiliza a StreamConnection, o tamanho da resposta no pode ser determinado
previamente. Com a interface ContentConnection ou HTTPConnection existe a possibilidade de se
determinar o tamanho da resposta. Porm, o tamanho no est sempre disponvel, ento o

Desenvolvimento de Aplicaes Mveis 7


JEDITM

programa dever que ser capaz de recorrer a outros meios para obter a resposta sem o
conhecimento prvio do tamanho.
HttpConnection connection = null;
InputStream iStream = null;
byte[] data = null;

try {
connection = (HttpConnection) Connector.open("http://www.sun.com/");
int code = connection.getResponseCode();
switch (code) {
case HttpConnection.HTTP_OK:
iStream = connection.openInputStream();
int length = (int) connection.getLength();
if (length > 0){
data = new byte[length];
int totalBytes = 0;
int bytesRead = 0;
while ((totalBytes < length) && (bytesRead > 0)) {
bytesRead = iStream.read(
data, totalBytes, length - totalBytes);
if (bytesRead > 0){
totalBytes += bytesRead;
}
}
} else {
// Tamanho no conhecido, ler por caracter
...
}
break;
default:
break;
}
...

3.3. Controlando Redirecionamentos HTTP

Algumas vezes o servidor redireciona o navegador do cliente para outras pginas WEB atravs de
uma resposta que pode ser atravs de uma HTTP_MOVED_PERM (301), HTTP_MOVED_TEMP
(302), HTTP_SEE_OTHER (303) ou HTTP_TEMP_REDIRECT (307) ao invs da resposta comum
HTTP_OK. O programa ter de ser capaz de detectar isso utilizando o mtodo getResponseCode(),
obter a nova URI do cabealho utilizando o mtodo getHeaderField("Localizao") e recuperar
esse documento na nova localizao.
int code = connection.getResponseCode();
switch(code){
case HttpConnection.HTTP_MOVED_PERM:
case HttpConnection.HTTP_MOVED_TEMP:
case HttpConnection.HTTP_SEE_OTHER:
case HttpConnection.HTTP_TEMP_REDIRECT:
String newUrl = conn.getHeaderField("Location");
...

Desenvolvimento de Aplicaes Mveis 8


JEDITM

4. Conexes HTTPS
HTTPS um modelo HTTP sobre uma conexo segura de transporte. A abertura de uma conexo
do tipo HTTPS realizada de forma idntica a abrir uma conexo do tipo HTTP. A nica diferena
que a URL passada para Connector.open() e o resultado moldado para uma varivel da classe
HttpsConnection.
Um tipo adicional de exceo pode ser lanada por um mtodo Connector.open() ao invs das
excees comuns IllegalArgumentException, ConnectionNotFoundException, java.io.IOException e
SecurityException. Uma exceo do tipo CertificateException pode ser disparada por causa de
falhas no certificado.
import javax.microedition.io.*;

HttpsConnection connection = null;


InputStream iStream = null;
byte[] data = null;
try {
connection = (HttpsConnection) Connector.open("https://www.sun.com/");
int code = connection.getResponseCode();
...
} catch (CertificateException ce){
switch (ce.getReason()){
case CertificateException.EXPIRED:
...
}
}

Todos as constantes listadas a seguir foram retiradas da especificao MIDP 2.0 JSR 118 e so
do tipo byte estticas.
BAD_EXTENSIONS Indicar que um certificado possui extenses crticas desconhecidas
BROKEN_CHAIN Indicar que um certificado numa cadeia no foi gerado pela prxima
autoridade na cadeia
CERTIFICATE_CHAIN_TOO_LONG Indicar que o tamanho da cadeia de servidores certificados excedeu o
tamanho permitido pela poltica do emissor
EXPIRED Indicar que um certificado expirou
INAPPROPRIATE_KEY_USAGE Indicar que a chave pblica do certificado foi usada de maneira
considerada inapropriada pelo emissor
MISSING_SIGNATURE Indicar que um objeto certificado no contm uma assinatura
NOT_YET_VALID Indicar que um certificado ainda no vlido
ROOT_CA_EXPIRED Indicar que a chave pblica da autoridade certificadora raiz (root CA)
expirou
SITENAME_MISMATCH Indicar que um certificado no contm o nome correto do site
UNAUTHORIZED_INTERMEDIATE_CA Indicar que um certificado intermedirio na cadeia no possui a
permisso para ser uma autoridade certificadora intermediria
UNRECOGNIZED_ISSUER Indicar que um certificado foi emitido por uma entidade desconhecida
UNSUPPORTED_PUBLIC_KEY_TYPE Indicar que o tipo da chave pblica no certificado no suportado pelo
dispositivo
UNSUPPORTED_SIGALG Indicar que um certificado foi assinado utilizando um algoritmo no
suportado
VERIFICATION_FAILED Indicar uma verificao falha de certificado
Figura 4: Razes para uma exceo CertificateException

Desenvolvimento de Aplicaes Mveis 9


JEDITM

5. Sockets TCP
A maior parte das implementaes de HTTP funcionam no topo da camada TCP. Ao enviar dados
usando a camada TCP, estes podem ser divididos em pedaos menores chamado pacotes. A
camada TCP garante que todos os pacotes enviados pelo transmissor sero recebidos pelo
receptor na mesma ordem que eles foram enviados. Se um pacote no for recebido pelo receptor,
ele ser reenviado. Isso significa que quando uma mensagem enviada, podemos ter certeza que
ela ser entregue para o receptor no mesmo formato na qual foi enviada, sem omisses ou
inseres (exceto em circunstncias extremas como o receptor sendo desconectado da rede).
A camada TCP o responsvel pela remontagem dos pacotes e retransmisso de forma
transparente. Por exemplo, o protocolo HTTP no se preocupa com a montagem e desmontagem
de pacotes porque isso deve ser tratados pela camada TCP.
Algumas vezes, o tamanho da mensagem muito pequeno e torna-se muito ineficiente para ser
enviado atravs de um nico pacote (a sobrecarga do pacote muito grande se comparada aos
dados a serem enviado). Imagine muitos pacotes percorrendo a rede com apenas um byte de
dados e muitos bytes de sobrecarga (digamos 16 bytes). Isso poderia fazer a rede ser muito
ineficiente, muitos pacotes inundariam a rede com alguns poucos bytes de dados.
Nesses casos, a implementao do TCP deve aguardar mensagens subsequentes para serem
enviadas. Ento, poder empacotar vrias mensagens antes de enviar o pacote. Se isso ocorrer,
poder haver atraso ou latncia na conexo. Se sua aplicao requer que a latncia seja a menor
possvel, voc dever configurar a opo DELAY do socket para zero. Ou, se a aplicao pode
conviver com perdas de pacotes ou pacotes desordenados, voc pode querer testar uma conexo
UDP ou Datagrama. Conexes UDP tambm possuem menos sobrecarga de pacotes.

5.1. Parte Cliente

Iremos na primeira parte do projeto construir as classes de comunicao do lado cliente para
proceder comunicao via sockets.
Classe ClientSocketMidlet.java:
package socket;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ClientSocketMidlet extends MIDlet {

private static Display display;


private boolean isPaused;

public void startApp() {


isPaused = false;
display = Display.getDisplay(this);
Client client = new Client(this);
client.start();
}
public static Display getDisplay() {
return display;
}
public boolean isPaused() {
return isPaused;
}
public void pauseApp() {
isPaused = true;
}
public void destroyApp(boolean unconditional) {
}
}

Classe Client.java:

Desenvolvimento de Aplicaes Mveis 10


JEDITM

package socket;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

public class Client implements Runnable, CommandListener {


private ClientSocketMidlet parent;
private Display display;
private Form f;
private StringItem si;
private TextField tf;
private boolean stop;
private Command sendCommand = new Command("Send", Command.ITEM, 1);
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
InputStream is;
OutputStream os;
SocketConnection sc;
Sender sender;

public Client(ClientSocketMidlet m) {
parent = m;
display = Display.getDisplay(parent);
f = new Form("Socket Client");
si = new StringItem("Status:", " ");
tf = new TextField("Send:", "", 30, TextField.ANY);
f.append(si);
f.append(tf);
f.addCommand(exitCommand);
f.addCommand(sendCommand);
f.setCommandListener(this);
display.setCurrent(f);
}
public void start() {
Thread t = new Thread(this);
t.start();
}
public void run() {
try {
sc = (SocketConnection) Connector.open("socket://localhost:5000");
si.setText("Connected to server");
is = sc.openInputStream();
os = sc.openOutputStream();
sender = new Sender(os);
while (true) {
StringBuffer sb = new StringBuffer();
int c = 0;
while (((c = is.read()) != '\n') && (c != -1)) {
sb.append((char) c);
}
if (c == -1) {
break;
}
si.setText("Message received - " + sb.toString());
}
stop();
si.setText("Connection closed");
f.removeCommand(sendCommand);
} catch (ConnectionNotFoundException cnfe) {
Alert a = new Alert("Client",
"Please run Server MIDlet first", null, AlertType.ERROR);
a.setTimeout(Alert.FOREVER);
a.setCommandListener(this);
display.setCurrent(a);
} catch (IOException ioe) {
if (!stop) {

Desenvolvimento de Aplicaes Mveis 11


JEDITM

ioe.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void commandAction(Command c, Displayable s) {
if ((c == sendCommand) && !parent.isPaused()) {
sender.send(tf.getString());
}
if ((c == Alert.DISMISS_COMMAND) || (c == exitCommand)) {
parent.notifyDestroyed();
parent.destroyApp(true);
}
}
public void stop() {
try {
stop = true;
if (sender != null) {
sender.stop();
}
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
if (sc != null) {
sc.close();
}
} catch (IOException ioe) {
}
}
}

Classe Sender.java:
package socket;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

public class Sender extends Thread {


private OutputStream os;
private String message;

public Sender(OutputStream os) {


this.os = os;
start();
}
public synchronized void send(String msg) {
message = msg;
notify();
}
public synchronized void run() {
while (true) {
if (message == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
if (message == null) {
break;
}

Desenvolvimento de Aplicaes Mveis 12


JEDITM

try {
os.write(message.getBytes());
os.write("\r\n".getBytes());
} catch (IOException ioe) {
ioe.printStackTrace();
}
message = null;
}
}
public synchronized void stop() {
message = null;
notify();
}
}

Desenvolvimento de Aplicaes Mveis 13


JEDITM

6. Server Sockets
No modelo cliente-servidor, o servidor continuamente espera pela conexo de um cliente que
dever conhecer o nmero da porta deste. Devemos utilizar o mtodo Connector.open() para criar
uma conexo do tipo socket. A URL passada para o mtodo possui um formato semelhante ao um
Socket TCP, com um hostname passado em branco (isto , socket://:5000).

6.1. Parte Servidora

Iremos agora complementar as classes de comunicao via socket criando as classes que
resolvero a parte do servidor.
Classe ServerSocketMidlet.java:
package socket;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ServerSocketMidlet extends MIDlet {


private static Display display;
private boolean isPaused;

public void startApp() {


isPaused = false;
display = Display.getDisplay(this);
Server server = new Server(this);
server.start();
}
public static Display getDisplay() {
return display;
}
public boolean isPaused() {
return isPaused;
}
public void pauseApp() {
isPaused = true;
}
public void destroyApp(boolean unconditional) {
}
}

Classe Server.java:
package socket;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

public class Server implements Runnable, CommandListener {


private ServerSocketMidlet parent;
private Display display;
private Form f;
private StringItem si;
private TextField tf;
private boolean stop;
private Command sendCommand = new Command("Send", Command.ITEM, 1);
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
InputStream is;
OutputStream os;
SocketConnection sc;
ServerSocketConnection scn;
Sender sender;

Desenvolvimento de Aplicaes Mveis 14


JEDITM

public Server(ServerSocketMidlet m) {
parent = m;
display = Display.getDisplay(parent);
f = new Form("Socket Server");
si = new StringItem("Status:", " ");
tf = new TextField("Send:", "", 30, TextField.ANY);
f.append(si);
f.append(tf);
f.addCommand(exitCommand);
f.setCommandListener(this);
display.setCurrent(f);
}
public void start() {
Thread t = new Thread(this);
t.start();
}
public void run() {
try {
si.setText("Waiting for connection");
scn = (ServerSocketConnection) Connector.open("socket://:5000");
sc = (SocketConnection) scn.acceptAndOpen();
si.setText("Connection accepted");
is = sc.openInputStream();
os = sc.openOutputStream();
sender = new Sender(os);
f.addCommand(sendCommand);
while (true) {
StringBuffer sb = new StringBuffer();
int c = 0;
while (((c = is.read()) != '\n') && (c != -1)) {
sb.append((char) c);
}
if (c == -1) {
break;
}
si.setText("Message received - " + sb.toString());
}
stop();
si.setText("Connection is closed");
f.removeCommand(sendCommand);
} catch (IOException ioe) {
if (ioe.getMessage().equals("ServerSocket Open")) {
Alert a = new Alert("Server", "Port 5000 is already taken.", null,
AlertType.ERROR);
a.setTimeout(Alert.FOREVER);
a.setCommandListener(this);
display.setCurrent(a);
} else {
if (!stop) {
ioe.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void commandAction(Command c, Displayable s) {
if ((c == sendCommand) && !parent.isPaused()) {
sender.send(tf.getString());
}
if ((c == Alert.DISMISS_COMMAND) || (c == exitCommand)) {
parent.notifyDestroyed();
parent.destroyApp(true);
}
}
public void stop() {

Desenvolvimento de Aplicaes Mveis 15


JEDITM

try {
stop = true;
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
if (sc != null) {
sc.close();
}
if (scn != null) {
scn.close();
}
} catch (IOException ioe) {
}
}
}

Desenvolvimento de Aplicaes Mveis 16


JEDITM

7. Datagramas
Conexes por soquetes TCP so seguras. Ao contrrio, entregas de pacotes UDP no so
garantidas. No h garantias de que pacotes enviados utilizando conexes por datagramas sejam
recebidas por quem as solicitou. A ordem em que os pacotes so recebidos no segura. A ordem
em que os pacotes so enviados no a mesma ordem em que so recebidos.
Datagramas ou pacotes UDP so utilizados quando a aplicao pode se sustentar (continuar em
operao) mesmo quando um pacote est perdido ou quando no so entregues em ordem.

7.1. Parte Servidora

Iniciaremos o projeto de comunicao por datagramas atravs da parte servidora.


Classe ServerDatagramMidlet.java:
package datagram;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ServerDatagramMidlet extends MIDlet {


private static Display display;
private boolean isPaused;

public void startApp() {


isPaused = false;
display = Display.getDisplay(this);
Server server = new Server(this);
server.start();
}
public static Display getDisplay() {
return display;
}
public boolean isPaused() {
return isPaused;
}
public void pauseApp() {
isPaused = true;
}
public void destroyApp(boolean unconditional) {
}
}

Classe Server.java:
package datagram;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

public class Server implements Runnable, CommandListener {


private ServerDatagramMidlet parent;
private Display display;
private Form f;
private StringItem si;
private TextField tf;
private Command sendCommand = new Command("Send", Command.ITEM, 1);
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
private Sender sender;
private String address;

public Server(ServerDatagramMidlet m) {

Desenvolvimento de Aplicaes Mveis 17


JEDITM

parent = m;
display = Display.getDisplay(parent);
f = new Form("Datagram Server");
si = new StringItem("Status:", " ");
tf = new TextField("Send:", "", 30, TextField.ANY);
f.append(si);
f.append(tf);
f.addCommand(sendCommand);
f.addCommand(exitCommand);
f.setCommandListener(this);
display.setCurrent(f);
}
public void start() {
Thread t = new Thread(this);
t.start();
}
public void run() {
try {
si.setText("Waiting for connection");
DatagramConnection dc = (DatagramConnection)
Connector.open("datagram://:5555");
sender = new Sender(dc);
while (true) {
Datagram dg = dc.newDatagram(100);
dc.receive(dg);
address = dg.getAddress();
si.setText("Message received - " + new String(dg.getData(), 0,
dg.getLength()));
}
} catch (IOException ioe) {
Alert a = new Alert("Server", "Port 5000 is already taken.", null,
AlertType.ERROR);
a.setTimeout(Alert.FOREVER);
a.setCommandListener(this);
display.setCurrent(a);
} catch (Exception e) {
e.printStackTrace();
}
}
public void commandAction(Command c, Displayable s) {
if ((c == sendCommand) && !parent.isPaused()) {
if (address == null) {
si.setText("No destination address");
} else {
sender.send(address, tf.getString());
}
}
if ((c == Alert.DISMISS_COMMAND) || (c == exitCommand)) {
parent.destroyApp(true);
parent.notifyDestroyed();
}
}
}

7.2. Classe de Comunicao

Esta classe aproveitada tanto pelo lado servidor quanto pelo lado cliente para o controle do
envio das mensagens.
Classe Sender.java:
package datagram;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;

Desenvolvimento de Aplicaes Mveis 18


JEDITM

import javax.microedition.midlet.*;

public class Sender extends Thread {


private DatagramConnection dc;
private String address;
private String message;

public Sender(DatagramConnection dc) {


this.dc = dc;
start();
}
public synchronized void send(String addr, String msg) {
address = addr;
message = msg;
notify();
}
public synchronized void run() {
while (true) {
if (message == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
try {
byte[] bytes = message.getBytes();
Datagram dg = null;
if (address == null) {
dg = dc.newDatagram(bytes, bytes.length);
} else {
dg = dc.newDatagram(bytes, bytes.length, address);
}
dc.send(dg);
} catch (Exception ioe) {
ioe.printStackTrace();
}
message = null;
}
}
}

7.3. Parte Cliente

Complementaremos o projeto com as classes que definem a parte cliente.


Classe ClientDatagramMidlet.java
package datagram;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ClientDatagramMidlet extends MIDlet {


private static Display display;
private boolean isPaused;

public void startApp() {


isPaused = false;
display = Display.getDisplay(this);
Client client = new Client(this);
client.start();
}
public static Display getDisplay() {
return display;
}
public boolean isPaused() {

Desenvolvimento de Aplicaes Mveis 19


JEDITM

return isPaused;
}
public void pauseApp() {
isPaused = true;
}
public void destroyApp(boolean unconditional) {
}
}

Classe Client.java:
package datagram;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

public class Client implements Runnable, CommandListener {

private ClientDatagramMidlet parent;


private Display display;
private Form f;
private StringItem si;
private TextField tf;
private Command sendCommand = new Command("Send", Command.ITEM, 1);
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
private Sender sender;

public Client(ClientDatagramMidlet m) {
parent = m;
display = Display.getDisplay(parent);
f = new Form("Datagram Client");
si = new StringItem("Status:", " ");
tf = new TextField("Send:", "", 30, TextField.ANY);
f.append(si);
f.append(tf);
f.addCommand(sendCommand);
f.addCommand(exitCommand);
f.setCommandListener(this);
display.setCurrent(f);
}
public void start() {
Thread t = new Thread(this);
t.start();
}
public void run() {
try {
DatagramConnection dc = (DatagramConnection) Connector.open(
"datagram://localhost:5555");
si.setText("Connected to server");
sender = new Sender(dc);
while (true) {
Datagram dg = dc.newDatagram(100);
dc.receive(dg);
if (dg.getLength() > 0) {
si.setText("Message received - " + new String(dg.getData(), 0,
dg.getLength()));
}
}
} catch (ConnectionNotFoundException cnfe) {
Alert a = new Alert("Client", "Please run Server MIDlet first", null,
AlertType.ERROR);
a.setTimeout(Alert.FOREVER);
display.setCurrent(a);
} catch (IOException ioe) {
ioe.printStackTrace();

Desenvolvimento de Aplicaes Mveis 20


JEDITM

}
}
public void commandAction(Command c, Displayable s) {
if ((c == sendCommand) && !parent.isPaused()) {
sender.send(null, tf.getString());
}
if (c == exitCommand) {
parent.destroyApp(true);
parent.notifyDestroyed();
}
}
}

Desenvolvimento de Aplicaes Mveis 21


JEDITM

8. Exerccios
8.1. Buscar dados da URL

Criar um MIDlet que detalhe um endereo HTTP. Pesquisar a URL utilizando o mtodo GET e
mostrar as propriedades desta conexo (caso esteja disponvel), tais como: cdigo da resposta,
descrio da mensagem, tamanho, tipo, modo de codificao, se est finalizado e data da ltima
modificao.

Desenvolvimento de Aplicaes Mveis 22


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 7
Comunicao Corporativa

Verso 1.0 - Set/2007


JEDITM

Autor Necessidades para os Exerccios


A. Oliver de Guzman Sistemas Operacionais Suportados
NetBeans IDE 5.5 para os seguintes sistemas operacionais:
Microsoft Windows XP Profissional SP2 ou superior
Mac OS X 10.4.5 ou superior
Equipe Red Hat Fedora Core 3
Rommel Feria Solaris 10 Operating System (SPARC e x86/x64 Platform Edition)
John Paul Petines NetBeans Enterprise Pack, poder ser executado nas seguintes plataformas:
Microsoft Windows 2000 Profissional SP4
Solaris 8 OS (SPARC e x86/x64 Platform Edition) e Solaris 9 OS (SPARC e
x86/x64 Platform Edition)
Vrias outras distribuies Linux

Configurao Mnima de Hardware


Nota: IDE NetBeans com resoluo de tela em 1024x768 pixel
Sistema Operacional Processador Memria HD Livre
Microsoft Windows 500 MHz Intel Pentium III 512 MB 850 MB
workstation ou equivalente
Linux 500 MHz Intel Pentium III 512 MB 450 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC II 450 MHz 512 MB 450 MB
Solaris OS (x86/x64 AMD Opteron 100 Srie 1.8 GHz 512 MB 450 MB
Platform Edition)
Mac OS X PowerPC G4 512 MB 450 MB

Configurao Recomendada de Hardware

Sistema Operacional Processador Memria HD Livre


Microsoft Windows 1.4 GHz Intel Pentium III 1 GB 1 GB
workstation ou equivalente
Linux 1.4 GHz Intel Pentium III 1 GB 850 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC IIIi 1 GHz 1 GB 850 MB
Solaris OS (x86/x64 AMD Opteron 100 Series 1.8 GHz 1 GB 850 MB
Platform Edition)
Mac OS X PowerPC G5 1 GB 850 MB

Requerimentos de Software
NetBeans Enterprise Pack 5.5 executando sobre Java 2 Platform Standard Edition
Development Kit 5.0 ou superior (JDK 5.0, verso 1.5.0_01 ou superior), contemplando
a Java Runtime Environment, ferramentas de desenvolvimento para compilar, depurar,
e executar aplicaes escritas em linguagem Java. Sun Java System Application Server
Platform Edition 9.
Para Solaris, Windows, e Linux, os arquivos da JDK podem ser obtidos para
sua plataforma em http://java.sun.com/j2se/1.5.0/download.html
Para Mac OS X, Java 2 Plataform Standard Edition (J2SE) 5.0 Release 4, pode
ser obtida diretamente da Apple's Developer Connection, no endereo: http://
developer.apple.com/java ( necessrio registrar o download da JDK).

Para mais informaes: http://www.netbeans.org/community/releases/55/relnotes.html

Desenvolvimento de Aplicaes Mveis 2


JEDITM

Colaboradores que auxiliaram no processo de traduo e reviso


Acio Jnior Fbio Bombonato Luiz Fernandes de Oliveira Junior
Alexandre Mori Fabrcio Ribeiro Brigago Marco Aurlio Martins Bessa
Alexis da Rocha Silva Francisco das Chagas Maria Carolina Ferreira da Silva
Allan Souza Nunes Frederico Dubiel Massimiliano Giroldi
Allan Wojcik da Silva Herivelto Gabriel dos Santos Mauro Cardoso Mortoni
Anderson Moreira Paiva Jacqueline Susann Barbosa Paulo Afonso Corra
Andre Neves de Amorim Joo Vianney Barrozo Costa Paulo Oliveira Sampaio Reis
Angelo de Oliveira Kefreen Ryenz Batista Lacerda Pedro Henrique Pereira de Andrade
Antonio Jose R. Alves Ramos Kleberth Bezerra G. dos Santos Ronie Dotzlaw
Aurlio Soares Neto Leandro Silva de Morais Seire Pareja
Bruno da Silva Bonfim Leonardo Ribas Segala Sergio Terzella
Carlos Fernando Gonalves Lucas Vincius Bibiano Thom Vanessa dos Santos Almeida
Denis Mitsuo Nakasaki Luciana Rocha de Oliveira Robson Alves Macdo

Auxiliadores especiais

Reviso Geral do texto para os seguintes Pases:


Brasil Tiago Flach
Guin Bissau Alfredo C, Bunene Sisse e Buon Olossato Quebi ONG Asas de Socorro

Coordenao do DFJUG

Daniel deOliveira JUGLeader responsvel pelos acordos de parcerias


Luci Campos - Idealizadora do DFJUG responsvel pelo apoio social
Fernando Anselmo - Coordenador responsvel pelo processo de traduo e reviso,
disponibilizao dos materiais e insero de novos mdulos
Rodrigo Nunes - Coordenador responsvel pela parte multimdia
Srgio Gomes Veloso - Coordenador responsvel pelo ambiente JEDITM (Moodle)

Agradecimento Especial
John Paul Petines Criador da Iniciativa JEDITM
Rommel Feria Criador da Iniciativa JEDITM

Desenvolvimento de Aplicaes Mveis 3


JEDITM

1. Objetivos
Nesta lio, aprenderemos a escrever Servlets, utilizar pginas com JSP e JSTL, acessar um banco
de dados atravs de JDBC e a criar e ler documentos XML.

Ao final desta lio, o estudante ser capaz de:


Escrever Servlets simples
Escrever Java Server Pages (JSP) simples utilizando JSTL
Escrever cdigo JSTL utilizando Expression Language (EL)
Acessar banco de dados utilizando a tecnologia JDBC
Gerar XML
Ler um arquivo XML no cliente mvel

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. Servlets
Servlet uma classe Java que executada no servidor WEB para implementar transaes do tipo
requisio-resposta (request-response). Atravs dos servlet, a tecnologia Java fornece uma
alternativa melhor e mais portvel do que scripts CGI (Common Gateway Interface). Comparado
com scripts CGI (escritos em Perl, scripts sheel, ou outras linguagens de script), servlet fornece
uma tecnologia escalvel, independente de plataforma, para entregar contedo dinmico.
Um servlet tem dois mtodos para processar uma requisio, os mtodos doGet() e doPost().
Esses mtodos so chamados quando um cliente WEB (browser) envia um comando "GET" ou
"POST". Esses mtodos tm parmetros idnticos. Esses parmetros so normalmente entregues
para um mtodo comum. Portanto, tanto a requisio GET quanto a requisio POST so
manipuladas da mesma maneira.
protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// requisio de processamento ...
}

protected void doPost(


HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// requisio de processamento ...
}

A seguir teremos um servlet completo:


import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class SampleServlet extends HttpServlet {

protected void processRequest(


HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet SampleServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet SampleServlet at "
+ request.getContextPath () + "</h1>");
out.println("</body>");
out.println("</html>");
out.close();
}
protected void doGet(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/** Retorna uma breve descrio do servlet.
*/

Desenvolvimento de Aplicaes Mveis 5


JEDITM

public String getServletInfo() {


return "Short description";
}
}

Para criar um novo Projeto WEB (Web Project) no NetBeans, selecione a partir do menu principal
a opo File -> New Project...

Figura 1: Janela New Project do NetBeans

Na janela acima selecione em Categories a opo Web e em Projects selecione a opo Web
Application.

Desenvolvimento de Aplicaes Mveis 6


JEDITM

Figura 2: Janela New Web Application do NetBeans

Na janela acima informe o nome para o projeto e pressione o boto Finish. Aps o projeto criado
poderemos criar um novo arquivo tipo servlet. Para o mesmo. Para criar este arquivo selecione, a
partir do menu principal, a opo em File -> New File...

Figura 3: Janela New File do NetBeans

Na janela acima selecione em Categories a opo Web e em File Types selecione a opo Servlet.

Figura 4: Janela New Servlet do NetBeans

Na janela acima informe o nome para o servlet e pressione o boto Finish.

Desenvolvimento de Aplicaes Mveis 7


JEDITM

3. JSP e JSTL
O objetivo primrio das Java Server Pages (JSP) e Standard Tag Library (JSTL) ajudar aos
desenvolvedores simplificar a escrita das de pginas WEB. JSTL faz a ponte entre programadores
e autores (no programadores) fornecendo uma linguagem de expresso simples para a
construo de pginas JSP.
Alm do suporte s aes da linguagem de expresso e de fluxo de controle, JSTL fornece
tambm funcionalidade para acessar recursos baseados em URL, internacionalizao e formatao
de nmeros e datas, acesso de base de dados e processamento de XML.
JTSL composta de diversas bibliotecas de tags, agrupadas com base na rea funcional.

rea Prefixo URI Exemplo de cdigo


core c http://java.sun.com/jstl/core <c:out value="${var}"/>
I18N formatting fmt http://java.sun.com/jstl/fmt <fmt:formatNumber
XML processing x http://java.sun.com/jstl/xml <x:forEach ...
Database (SQL) sql http://java.sun.com/jstl/sql <sql:query var=...
Functions fn http://java.sun.com/jstl/functions <fn:

Nesta seo, abordaremos o uso da biblioteca core.

3.1. Configurao

Para usar as tags JSTL, a diretiva da taglib deve ser includa na pgina JSP, uma para cada rea
funcional que ser usada na pgina.
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

Figura 5: Cdigo JSP com a tag core

Deve-se incluir tambm o jstl.jar no diretrio de bibliotecas do projeto:


1. Pressionar o boto direito do mouse em cima do diretrio de bibliotecas do projeto e
selecionar "Add Library" no menu pop-up:

Figura 6: Adicionando uma biblioteca ao projeto

Desenvolvimento de Aplicaes Mveis 8


JEDITM

2. Selecionar "JSTL 1.1" e selecionar a opo "Add Library". "JSTL 1.1 standard.jar" e
"STL 1.1 jstl.jar" sero adicionados biblioteca do projeto.

Figura 7: Adicionando uma biblioteca ao projeto

3.2. Hello, world!

Uma pgina JSP, ao contrrio de um servlet, uma pgina HTML com tags que permitem a
programao Java. A seguir temos uma pgina JSP:
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<c:set var="mensagem" value="hello, world!"/>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><c:out value="${mensagem}"/></title>
</head>
<body>
<h1><c:out value="${mensagem}"/></h1>
</body>
</html>

Seguindo as mesmas instrues para gerar um servlet, entretanto selecione JSP e indique o nome
como hello.jsp. Para ver a sada desta pgina, pressionar o boto direito do mouse em cima do
nome do arquivo e selecionar a opo "Run File" mostrado o seguinte resultado no seu
navegador web:

Figura 8: Resultado da execuo da pgina JSP

Desenvolvimento de Aplicaes Mveis 9


JEDITM

3.3. Transferindo controle do Servlet para JSP


import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class SampleServlet2 extends HttpServlet {

protected void processRequest(


HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String[] days = {"Sunday", "Monday", "Tuesday", "Wednesday"};
request.setAttribute("days", days);
request.setAttribute("message", "hello, world!");
// Transfere o controle para a pgina JSP
RequestDispatcher dispatcher = request.
getRequestDispatcher("/hello.jsp");
if (dispatcher != null)
dispatcher.forward(request, response);
}
protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

processRequest(request, response);
}
public String getServletInfo() {
return "Short description";
}
}

Figura 9: Resultado da execuo do Servlet

Desenvolvimento de Aplicaes Mveis 10


JEDITM

3.4. Linguagem de Expresso

3.4.1. Acessando Atributos, Propriedades e Colees

Para acessar um atributo, a sintaxe : ${var}


Exemplo: sada do valor do atributo username
<c:out value="${username}"/>

JSTL unifica o acesso s propriedades do JavaBean e valores de coleo. A expresso varX.varY


equivalente para varX[varY] em JSTL. A expresso varX.varY (ou varX[varY]) ser avaliada,
dependendo do tipo de varX:
1. Se varX um JavaBean, varY ser convertido em cadeia de caractere. Se varY uma
propriedade de leitura de varX, ela pode retornar o resultado da chamada ao mtodo de
acesso: varX.getVarY()
2. Se varX uma coleo do tipo List: varY forada para int. Converter para: varX.get(varY)
3. Se varX uma coleo do tipo Vector: varY forada para int. Converter para:
Array.get(varX, varY)
4. Se varX uma coleo do tipo Map: Converter para: varX.get(varY)
Os atributos podem ter escopo de pgina, de requisio e da aplicao. O linguagem de expresso
procuraria pelo identificador nestes escopos. Se o identificador no for achado, retornado nulo.

3.4.2. Objetos Implcitos

JSTL inicializa automaticamente diversos atributos de mapeamento com valores de origens


diferentes. Estes atributos esto disponveis para as pginas JSP sem qualquer inicializao do
usurio. Por exemplo, o atributo param contm mapeamentos de nomes de parmetros e
valores de requisio. Estes nomes e valores (param) vm de formulrios HTML, atravs da de
submisso de mtodos HTTP GET ou POST.
Objeto Contedo
Implcito
Contm um mapeamento de nomes de atributos de escopo de pgina para seus
pageScope
valores
Contm um mapeamento de nomes de atributos de escopo de requisio para seus
requestScope
valores
Contm um mapeamento de nomes de atributos de escopo de sesso para seus
sessionScope
valores
Contm um mapeamento de nomes de atributos de escopo de aplicao para seus
applicationScope
valores
Contm um mapeamento de nomes de parmetros para seus valores de parmetros
param
(cadeia de caracteres). Equivalente a ServletRequest.getParameter(String)
Contm um mapeamento de nomes de cabealho para seus valores (cadeia de
header
caracteres). Equivalente a servletRequst.getHeader(String)
Contm contendo um mapeamento de nomes de "cookies" para seus valores.
cookie
Equivalente a HttpServletRequest.getCookie(String)

3.4.3. Operadores

A linguagem da expresso (EL) da JSTL suporta operadores relacionais, aritmticos e lgicos. Os


operadores relacionais suportados so:
== ou eq
!= ou ne
< ou lt

Desenvolvimento de Aplicaes Mveis 11


JEDITM

> ou gt
<= ou le
>= ou ge
Os operadores lgicos suportados so:
&& ou and
|| ou or
! ou not
E os operadores aritmticos suportados so:
+ (adio)
- (subtrao)
* (multiplicao)
/ (diviso)
% ou mod (resto da diviso ou mdulo)
O operador adicional empty muito til para testar valores nulos ou vazios.
<c:if test="${empty param.username}">No username</c:if>

3.4.4. Excees a Valores Padres (Bsicos)

Para simplificar pginas de JSP, os erros simples no geraro excees. Indicar um atributo com
um valor nulo indicar simplesmente (zero) em vez de gerar um NullPointerException.
Username: <input
type="text"
value="<c:out value="${param.username}"/>"
name="username" />

Qualquer atributo no definido que for utilizado em expresses ter seu valor padro como 0
(zero). Esta expresso retornaria o valor 1, se o parmetro start no fosse inicializado:
<c:out value="${param.start + 1}"/>

3.5. Biblioteca Core

3.5.1. Tag <c:out>

O tag <c:out> avalia uma expresso e retorna o seu resultado.


Sintaxe :
<c:out
value="value"
[escapeXml="{true|false}"]
[default="defaultValue"]
/>

Nome Dinmico Requisito Tipo Descrio


A expresso a ser avaliada
value sim sim Objeto
Se verdadeiro, os caracteres <, >, &, ' e " so
convertidos em seus cdigos da entidade do carter
escapeXml sim no boolean
(por exemplo: > conversos ao &gt;). O valor padro
true.
default sim no Objeto O valor padro se o valor do resultado for nulo

Exemplos:

Desenvolvimento de Aplicaes Mveis 12


JEDITM

Rows: <c:out value="${param.numRows}" defaultValue="20" />


Description:
<pre>
<c:out value="${bookmark.description}" escapeXml="false" />
</pre>

3.5.2. Tag <c:set>

Ajusta o valor de um atributo em um determinado escopo.


Sintaxe:
<c:set
value="value"
var="varName"
[scope="{page|request|session|application}"]
/>

Nome Dinmico Requisito Tipo Descrio


value sim sim Objeto A expresso a ser avaliada
O nome do atributo exportada que conter o valor da
var no sim String expresso. O tipo do atributo segue o tipo do
resultado da expresso
scope no no String O escopo do atributo

Exemplo:
<c:set var="fullName" value="${lastName, firstName}" />

3.5.3. Tag <c:remove>

Esta tag remove um atributo de um determinado escopo.


Sintaxe:
<c:remove
var="varName"
[scope="{page|request|session|application}"]
/>

Nome Dinmico Requisito Tipo Descrio


var no sim String O nome do atributo a ser eliminado
scope no no String O escopo do atributo

3.5.4. Tag <c:if>

Realiza uma avaliao condicional. O contedo do corpo ser processado se o teste de avaliao
da condio informada for verdadeiro.
Sintaxe:
<c:if test="testCondition"
[var="varName"] [scope="{page|request|session|application}"]>
body content
</c:if>

ou
<c:if test="testCondition"
var="varName" [scope="{page|request|session|application}"]
/>

Desenvolvimento de Aplicaes Mveis 13


JEDITM

Nome Dinmico Requerido Tipo Descrio


A condio testada que determina se o contedo do
test sim sim boolean
corpo dever ser processado
Nome do atributo exportado que ir conter o valor da
var no no/sim String condio testada. O tipo do atributo de escopo
Boolean
scope no no String Escopo do atributo

Exemplo:
<c:if test="${empty param.username}">No username</c:if>

3.5.5. Tag <c:choose><c:when><c:otherwise>

A tag <c:choose> uma substituta para a instruo if-else-if do Java, permitindo a execuo
condicional mutuamente exclusiva. O contedo do corpo composto pela tag <c:otherwise> ser
avaliado se nenhuma instruo das tags <c:when> for considerada verdadeira. O bloco
<c:otherwise> dever ser o ltimo da instruo e tambm ser precedido por no mnimo uma tag
do tipo <c:when>.
Sintaxe:
<c:choose>
<c:when test="condition1">
instrues para esta condio
</c:when>
<c:when test="condition2">
instrues para esta condio
</c:when>...
<c:otherwise>
instrues caso nenhuma condio tenha sido considerada verdadeira
</c:otherwise>
</c:choose>

Nome Dinmico Requerido Tipo Descrio


A condio de teste que determina se o contedo
test sim sim boolean
do corpo dever ser processado

Exemplo:
<c:choose>
<c:when test="${gender eq 'M'}">Male</c:when>
<c:when test="${gender eq 'F'}">Female</c:when>
<c:otherwise>Unknown</c:otherwise>
</c:choose>

3.5.6. Tag <c:forEach>

A tag <c:forEach> realiza iterao sobre o contedo de uma coleo. A coleo pode ser qualquer
uma das subclasses de java.util.Collection e java.util.Map. Arrays de objetos e tipos primitivos
tambm so suportados. Uma String com valores separados por vrgula ("True,False") tambm
pode ser utilizada para o processo. Enquanto houver itens na coleo o contedo do corpo ser
processado.
A tag tambm poder ser utilizada para iteraes com nmero fixo de repeties.
O atributo varStatus do tipo javax.servlet.jsp.jstl.core.LoopTagStatus e tem a propriedade index
(ndice da iterao atual, iniciado em zero) e count (a contagem da iterao atual, iniciada em 1
(um), por exemplo, se o ndice inicial 20, o ndice final 80 e o intervalo 10, o count poder
ser 1,2,3,4,5,6,7). As propriedades lgicas first e last indicam se a iterao atual a primeira ou
a ltima, respectivamente. Existem tambm as propriedades begin, end e step que guardam os

Desenvolvimento de Aplicaes Mveis 14


JEDITM

valores dos argumentos inicial, final e do passo realizado pelo lao.


Sintaxe:
<c:forEach
[var="varName"]
items="collection"
[varStatus="varStatusName"]
[begin="begin"] [end="end"] [step="step"]
>
instrues a serem executadas
</c:forEach>

ou
<c:forEach [var="varName"]
[varStatus="varStatusName"]
begin="begin" end="end" [step="step"]
>
instrues a serem executadas
</c:forEach>

Nome Dinmico Requerido Tipo Descrio


O nome de um atributo exportado para cada
var no no varivel
elemento de uma coleo
Collection,
items sim sim/no Map, Array, Coleo de itens para realizar interaes
String
O nome do atributo exportado para a situao da
varStatus no no String operao. O tipo do objeto exportado
javax.servlet.jsp.jstl.core.LoopTagStatus
ndice inicial (base zero) na coleo, ou um ndice
begin sim no/sim int
inicial fixo (se a coleo no for especificada)
ndice final (base zero) na coleo, ou um ndice
end sim no/sim int
final fixo (se a coleo no for especificada)
O lao ser processado por um intervalo definido de
step sim no int
itens da iterao

Exemplo:
<select name="gender">
<c:forEach var="gender" items="${genderList}">
<option value="<c:out value="${gender.code}"/>">
<c:out value="${gender.name}"/>
</option>
</c:forEach>
</table>

3.5.7. Tag <c:forTokens>

Esta tag realiza iterao sobre os segmentos de texto que devem ser separados por um
delimitador em um objeto do tipo String.
Sintaxe:
<c:forTokens
items="stringOfTokens"
delims="delimiters"
[var="varName"]
[varStatus="varStatusName"]
[begin="begin"] [end="end"] [step="step"]
>
instrues a serem executadas

Desenvolvimento de Aplicaes Mveis 15


JEDITM

</c:forTokens >

Nome Dinmico Requerido Tipo Descrio


O nome do atributo exportado para toda instruo
var no no String
iterao e smbolo
items sim sim String Literal de smbolos
Delimitadores, caracteres que separam os smbolos no
delims sim sim String
literal de itens
O nome do atributo exportado para o status da
varStatus no no String operao. O objeto exportado do tipo
javax.servlet.jsp.jstl.core.LoopTagStatus
ndice do comeo (base-zero) da iterao. Se no for
begin sim no int especificado, a iterao vai comear com o primeiro
smbolo.
end sim no int Final do ndice da iterao
O lao ser processado por um intervalo definido de
step sim no int
itens da iterao

Exemplo:
<select name="gender">
<c:forEach var="gender" items="Male,Female" delims=",">
<option value="<c:out value="${gender}"/>">
<c:out value="${gender}"/>
</option>
</c:forEach>
</table>

Desenvolvimento de Aplicaes Mveis 16


JEDITM

4. JDBC
Nessa seo, discutiremos como persistir dados ou objetos. Para essa funcionalidade precisamos
de um banco de dados (relacional). A biblioteca JDBC permite executar consultas e alteraes em
um banco de dados. Antes de podermos usar o JDBC, precisamos ter certeza de que trs pr-
requisitos esto sendo satisfeitos:
JDBC library (biblioteca) includo no JDK
O servidor de banco de dados usaremos o MySQL (www.mysql.com)
Driver JDBC vem com o DBMS, instale o jar mysql-connector-java-3.x.x-bin.jar para o
JDBC 3.0

Figura 10: Adicionando as bibliotecas ao projeto

A tabela usada nesses exemplos pode ser recriada usando os comandos SQL CREATE AND
INSERT:
CREATE TABLE `task` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`task` varchar(128) NOT NULL default '',
`duration` int(11) NOT NULL default '0',
`assignedTo` varchar(64) NOT NULL default '',
`status` char(1) NOT NULL default '',
PRIMARY KEY (`id`)
);

INSERT INTO `task`


(`id`, `task`, `duration`, `assignedTo`, `status`)
VALUES
(1,'connect to database',2,'alex','0'),
(2,'list table rows',4,'alex','0'),
(3,'update row',8,'you','0');

4.1. Carregando o Driver

Para utilizar o driver JDBC com um banco de dados em particular temos que carreg-lo utilizando
Class.forName(). O nome do driver dependente do driver do banco de dados que carregaremos.
Em nosso caso, utilizaremos o mysql jdbc driver:
String driver = "com.mysql.jdbc.Driver";
Class.forName(driver);

4.2. Estabelecendo a Conexo

Para estabelecer uma conexo com o banco de dados precisamos da URL para o banco de dados.
Precisaremos tambm ter acesso ao banco de dados. Um nome de usurio e senha vlidos para o
acesso ao banco de dados sero requeridos.
String url = "jdbc:mysql://localhost:3306/jedi";
String username = "root";

Desenvolvimento de Aplicaes Mveis 17


JEDITM

String password = "password";


conn = DriverManager.getConnection(url, username, password);

4.3. Executando consultas SQL

O mtodo executeQuery() retorna um objeto do tipo ResultSet. Para percorrer por todas as linhas
do resultado da consulta utilizaremos o mtodo next(). Existem alguns mtodos que retornam as
colunas da linha corrente, cada uma para um tipo de dados especfico. Nesse exemplo,
recuperamos atributos dos tipos String e int utilizando getString() e getInt():
Statement statement = conn.createStatement();
String query = "SELECT task,duration,duration FROM task";
ResultSet rs = statement.executeQuery(query);
out.println("<table>");
out.println("<tr>");
out.println("<th>Task</th>");
out.println("<th>Duration</th>");
out.println("<th>Assigned to</th>");
out.println("</tr>");
while (rs.next()) {
String task = rs.getString("task");
int duration = rs.getInt("duration");
String assignedTo = rs.getString("assignedTo");
out.println("<tr>");
out.println("<td>" + task + "</td>");
out.println("<td>" + duration + "</td>");
out.println("<td>" + duration + "</td>");
out.println("</tr>");
}
out.println("</table>");

Figura 11: Resultado da consulta

4.4. Alterando tabelas

Para modificar registros nas tabelas com os comandos INSERT, UPDATE e DELETE (incluso,
alterao e excluso, respectivamente), o mtodo executeUpdate() utlizado.
String task = (String) request.getParameter("task");
String duration = (String) request.getParameter("duration");
String assignedTo = (String) request.getParameter("assignedTo");
String status = (String) request.getParameter("status");
Long id = new Long(idStr);
String updateQuery;
ResultSet rs = dao.query("SELECT id from task WHERE id ='" + id + "'");
if (rs.next()){
// altera a entrada da tarefa
updateQuery = "UPDATE task SET"
+ " task='" + (task != null? task:"") + "'"
+ ",duration='" + (duration != null ? duration:"") + "'"
+ ",assignedTo='" + (assignedTo != null ? assignedTo:"") + "'"
+ ",status='" + (status != null ? status:"") + "'"
+ " WHERE id=" + id;
} else {
// nova entrada da tarefa
updateQuery = "INSERT INTO task (task, duration, assignedTo, status) "
+ "VALUES ("

Desenvolvimento de Aplicaes Mveis 18


JEDITM

+ "'" + task + "',"


+ "'" + duration + "',"
+ "'" + assignedTo + "',"
+ "'" + status + "'"
+ ")";
}
statement.executeUpdate(updateQuery);

Desenvolvimento de Aplicaes Mveis 19


JEDITM

5. XML
XML, a linguagem de marcao extensvel (eXtensible Markup Language), uma linguagem de
marcao baseada em texto. Com XML, pode-se apresentar dados em um documento estruturado
de texto.
Assim como o HTML, as tags XML so definidas usando os smbolos maior e menor: <>.
Entretanto, diferente do HTML, XML mais fcil de se analisar. Um documento XML estruturado
com entidades formando uma estrutura de rvore.
Pode-se utilizar qualquer nome de tag apropriado que seja desejado, desde que todas as
aplicaes que utilizam o documento XML utilizem os mesmos nomes de tag. Tags podem conter
atributos. No exemplo abaixo, a primeira "task" (tarefa) tem um atributo "id" (identificador) igual
a "1" enquanto a segunda "task" tem um atributo "id" igual a "2".
<tasks>
<task id="1">
<name>connect to database</name>
<duration>2</duration>
<assignedTo>alex</assignedTo>
<status>0</status>
</task>
<task id="2">
<name>list table rows</name>
<duration>4</duration>
<assignedTo>alex</assignedTo>
<status>4</status>
</task>
</tasks>

5.1. Analisando o XML

At a data da escrita deste texto, no havia nenhuma biblioteca padro definida pelo JCP para
anlise de XML em CLDC. Entretanto, existem muitas bibliotecas XML que trabalham com a CLDC.
Uma delas a NanoXML (http://nanoxml.sourceforge.net/). A verso original da NanoXML no
trabalha com a CLDC. O usurio deve baixar a verso modificada que trabalha com CLDC em
http://www.ericgiguere.com/nanoxml e inclu-la no seu projeto mvel sob o nome de pacote
"nanoxml".
import java.io.*;
import java.util.*;
import nanoxml.*;

...
public String[] parseXml(String xml) {
kXMLElement root = new kXMLElement();
try {
root.parseString(xml);
Vector taskList = root.getChildren();
Vector items = new Vector();
for (int i=0; i<taskList.size(); i++){
kXMLElement task = (kXMLElement) taskList.elementAt(i);
String tagName = task.getTagName();
if (tagName != null && tagName.equalsIgnoreCase("task")){
Vector taskProperties = task.getChildren();
String[] fieldNames = {"name", "duration", "assignedTo", "status"};
String[] fields = new String[fieldNames.length];
String id = task.getProperty("id", "0");
for (int j=0; j<taskProperties.size(); j++) {
kXMLElement prop = (kXMLElement) taskProperties.elementAt(j);
String propTagName = prop.getTagName();
if (propTagName != null) {
for (int p=0; p<fieldNames.length; p++) {
if (propTagName.equalsIgnoreCase(fieldNames[p])) {

Desenvolvimento de Aplicaes Mveis 20


JEDITM

fields[p] = prop.getContents();
}
}
}
}
items.addElement(id + ": " + fields[0]);
}
}
String[] itemArr = new String[items.size()];
items.copyInto(itemArr);
return itemArr;
} catch( kXMLParseException ke ){
return(null);
}
}

Desenvolvimento de Aplicaes Mveis 21


JEDITM

6. Exerccios
6.1. Cabealhos das tabelas com linhas de cores alternadas

Escrever um cdigo JSTL que ir interagir com o mapa implcito "header" e mostrar o header
chave/nome e o valor em uma tabela HTML. Linhas de nmero mpar tem um fundo na cor
lightyellow (<tr bgcolor="lightyellow">...). Note que o ndice varStatus comea em zero. Note
que o (header) Map tem as propriedades "key" e "value".
Sada do exemplo:

accept-encoding gzip,deflate
connection keep-alive
accept-language en-us,en;q=0.5
host localhost:8084
accept-charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Mozilla/5.0 (Linux; U; Linux v0.99; en-US) Gecko/20050511 Firefox/
user-agent
1.2.3
text/xml,application/xml,application/xhtml
accept
+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
keep-alive 300

6.2. Servlets e JSP

Criar um servlet e uma aplicao JSTL que deve mostrar no formato XML em um array de objetos.
Os atributos do objeto so: nome e endereo IP. A classe Java deve parecer com esta:
public class Host {
private String name;
private String ip;
public Host(String name, String ip) {
this.name = name;
this.ip = ip;
}
public String getName(){ return(name); }
public String getIp(){ return(ip); }
public void setName(String name){ this.name = name; }
public void setIp(String ip){ this.ip = ip; }
}

Deve se passar um array esttico dos Hosts no Servlet para o JSP usando o mtodo
request.setAttribute().
Host[] hosts = {
new Host("localhost", "127.0.0.1"), new Host("java.sun.com", "1.2.3.4")};

A sada em XML se deve parecer como esta:


<hosts>
<host name="localhost">
<ip>127.0.0.1</ip>
</host>
<host name="java.sun.com">
<ip>1.2.3.4</ip>
</host>
</hosts>

Desenvolvimento de Aplicaes Mveis 22


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 8
Otimizaes

Verso 1.0 - Set/2007


JEDITM

1. Objetivos
Antes de realmente fazer qualquer otimizao em seus programas, deve-se certificar de que o
pacote de software de boa qualidade. A execuo das otimizaes nas classes do projeto deve
ser deixado por ltimo. Algumas tcnicas discutidas nesta lio so teis para evitar alguns erros
de programao.
Ao final desta lio, o estudante ser capaz de:
Utilizar as diferentes tcnicas de otimizao em aplicaes mveis.

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. Execuo de Classes
2.1. Utilizar StringBuffer ao invs de String

Deve-se recordar que em Java Strings so objetos imutveis. Usando-se os mtodos de String
criamos objetos individuais da String. A simples concatenao de Strings cria mltiplos objetos de
Strings (a menos que as Strings sejam constantes e o compilador seja aguado o suficiente para
concaten-las durante sua compilao). O uso da StringBuffer no apenas otimiza o tempo de
execuo de suas classes (menos tempo de execuo na criao de objetos), como tambm ir
otimizar o uso da memria (menos Strings para alocar).

String StringBuffer
String a, b, c; String a, b, c;
... ...
String message = StringBuffer message = new StringBuffer(255);
"a=" + a + "\n" message.append("a=");
+ "b=" + b + "\n" message.append(a);
+ "c=" + c + "\n"; message.append("\n");
message.append("b=");
message.append(b);
message.append("\n");
message.append("c=");
message.append(c);
message.append("\n");

2.2. Utilizar uma rea de clipping ao desenhar

Usar Graphics.setClip() reduz o tempo de execuo porque se est desenhando, somente, o


nmero correto de pixels na tela. Lembre-se que grficos desenhados na tela consomem muito
tempo de execuo. Reduzir o nmero de pixels a serem desenhados melhora o desempenho de
seu programa durante a execuo.
Graphics g;
int x1, y1, x2, y2;
...
g.setClip(x1, y1, x2, y2);
g.drawString("JEDI", x, y, Graphics.TOP | Graphics.HCENTER);
// mais operaes com desenhos...

2.3. Evitar o modificador sincronizado

Usar um modificador do tipo sincronizado aumentar a velocidade de execuo de sua classe, pois
ao mesmo tempo que ele ter de executar algumas medidas extras e no poder ser acessado
simultaneamente.

2.4. Passar o menor nmero de parmetros possvel

Ao chamar um mtodo, o interpretador empurra todos os parmetros para a pilha da execuo.


Passar muitos parmetros afeta a velocidade de execuo e utiliza muita memria.

2.5. Reduzir as chamadas de mtodos

As chamadas de mtodos ocupam muita memria e tempo de execuo. Veja o item anterior.

2.6. Atrasar as inicializaes

Para ganhar tempo no incio das aplicaes, atrase todas as inicializaes pesadas at que sejam

Desenvolvimento de Aplicaes Mveis 5


JEDITM

necessrias. No ponha inicializaes no construtor de MIDlet's ou no mtodo startApp. Apressar


a inicializao far com que a aplicao demore mais para ficar plenamente utilizvel. A maioria
dos usurios recusaria aplicaes que exigem um longo tempo para inicializar. Lembre-se que o
tempo de carga da aplicao afeta diretamente a primeira impresso que o usurio tem de seu
programa.

2.7. Utilizar arrays (matrizes) ao invs de Collection

Acessar matrizes mais rpido do que usar um objeto do tipo Vector.

2.8. Utilizar atributos locais

mais rpido acessar variveis locais do que variveis globais.

Desenvolvimento de Aplicaes Mveis 6


JEDITM

3. Tamanho do Arquivo JAR


3.1. Utilizar um ofuscador (obfuscator)

A inteno original do ofuscador complicar o mximo possvel os arquivos da classe compilada


para que seja muito complicado reverter essa situao. O Netbeans e o pacote Mobility vm com
um ofuscador. No est ativo por padro. Selecione a aba propriedade da aplicao e clique no
cone "Obfuscating":

Figura 1: Ativando o ofuscador

So dez nveis de ofuscao e deve-se ser o mais agressivo possvel em se tratando de


ofuscamento:

Figura 2: Maximizando o ofuscador

Desenvolvimento de Aplicaes Mveis 7


JEDITM

Entretanto, o processo de ofuscar tambm reduz o tamanho da aplicao. Um dos mtodos


empregados pelo ofuscador renomear as classes utilizando letras simples (por exemplo, classe
A). O ofuscador consegue fazer isto por possuir um transformador de mtodos. Se o mtodo tiver
um modificador private ou protected, ento podemos, com segurana, supor que este mtodo no
ser usado por outros pacotes e poder, conseqentemente, ser renomeado sem problemas.

3.2. Compresso dos arquivos JAR

Antes de distribuir seu aplicativo, deve-se comprimir o arquivo JAR final para distribu-lo. Um
arquivo tipo JAR um arquivo tipo ZIP, e um arquivo tipo ZIP possui diversos nveis de
compresso (incluindo a no compresso). O NetBeans no implementa os nveis de compresso.

Figura 3: Comprimindo o arquivo JAR

Para definir a compresso do JAR, abra a janela de propriedades do projeto e selecione a opo
Creating JAR. Marque a opo Compress JAR para comprimir o arquivo final. No esquea de
gerar (rebuild) o projeto novamente.
O Netbeans armazena o arquivo JAR final na pasta denominada dist abaixo da pasta de projeto.
Pode-se renomear a extenso do arquivo JAR para um arquivo com extenso ZIP e abr-lo com
qualquer programa de compresso (exemplo, WinZip) para ver os tamanhos de seus arquivos de
classe compilados.

3.3. Evitar a criao de classes desnecessrias

Isto pode parecer contraditrio aos princpios da orientao a objetos, entretanto uma classe
vazia e simples como:
public class EmptyClass {
public EmptyClass(){}
}

ser compilada em um arquivo do tipo class com com um tamanho de arquivo de no mnimo
250kb (no comprimveis). Compile esta classe vazia e observe o resultado.

Desenvolvimento de Aplicaes Mveis 8


JEDITM

3.4. Evitar a criao de interfaces

Esta tcnica est relacionada com a anteriormente vista. Quanto mais classes e interfaces, mais
(kilo)bytes teremos na aplicao final.

3.5. Evitar a criao de classes internas e annimas

Classes internas (inner class) so classificadas do mesmo modo. Classes annimas (anonymous
class) podem no ter um nome, entretanto ocupam o mesmo espao nas definies de classe.

3.6. Utilizar um objeto nico (padro Singleton) para mltiplos objetos

Isto reduz o nmero de classes em sua aplicao. Faa com que seu MIDlet implemente a
interface CommandListener e lhe ajudaria a reduzir seu pacote atravs de uma classe (isso 250,
ou mais, bytes menos).

3.7. Utilizar um pacote "padro" (no significa no usar package)

Utilize um tamanho de pacote pequeno, encurtando (e no usando) nomes de pacote, o que


contribui para a reduo dos bytes.

3.8. Utilizar o limite dos inicializadores estticos

Usando inicializaes estticas, tipo:


int[] tones = { 64, 63, 65, 76, 45, 56, 44, 88 };

seria traduzido pelo compilador de Java nas seguintes declaraes:


tones[0] = 64;
tones[1] = 63;
tones[2] = 65;
tones[3] = 76;
tones[4] = 45;
tones[5] = 56;
tones[6] = 44;
tones[7] = 88;

Este exemplo ilustra apenas oito elementos. Pense na possibilidade de inicializar centenas de
valores que utilizam declaraes separadas. Tentar realizar isso, estaria muito acima do tamanho
das possveis aplicaes.
Como uma alternativa, possvel utilizar o mtodo getResourceAsStream() para obter valores de
um arquivo ou utilizar uma nica String para armazenar os valores do array.

3.9. Combinar as imagens em um nico arquivo

Imagens so comprimidas melhor quando esto agrupadas em um nico arquivo de imagem. Isso
porque a compresso do formato de imagem (formato PNG) mais especfico para imagens do
que o mtodo de compresso do arquivo JAR. H tcnicas para se obter uma imagem especfica
de uma imagem maior, tal como recort-la.

3.10. Experimentar mtodos diferentes de compresso de imagens

Mtodos de compresso no so criados de forma semelhante. Alguns podem comprimir melhor


alguns tipos de imagem mas podem ter relao de compresso pobre em outros tipos. Escolha
um formato de imagem que melhora a relao de compresso. s vezes, a relao de compresso
tambm afetada pelo software de imagem que se est utilizando. Experimente com
manipulao de imagem diferentes programas para conseguir tamanhos de imagem melhores.

Desenvolvimento de Aplicaes Mveis 9


JEDITM

3.11. Utilizar classes pr-instaladas

No reinvente a roda. Utilize classes disponveis na plataforma que est usando. Criar suas
classes no s aumenta o tamanho da aplicao como tambm diminui a estabilidade.

Desenvolvimento de Aplicaes Mveis 10


JEDITM

4. Rede
4.1. Utilizar threads

Utilize uma thread separada para sua funo de rede para evitar travamentos da tela.

4.2. Comprimir os dados da rede

Utilize dados comprimidos para diminuir o trfego de rede da sua aplicao. Isso requerer que seu
cliente e servidor estejam utilizando o mesmo protocolo de rede e mtodo de compresso.
Comprimir XML resulta em melhor taxa de compresso porque o XML representado em formato
texto.

4.3. Reduzir o trfego de rede

J que as comunicaes via rede so lentas e onerosas, tente o quanto mais possvel colocar
dentro de uma nica requisio de rede vrios comandos. Isso reduzir a sobrecarga imposta
pelos protocolos de rede.

Desenvolvimento de Aplicaes Mveis 11


JEDITM

5. Uso de Memria
5.1. Utilizar estruturas de dados mais compactas

Utilize estruturas de dados mais amigveis para memria. Arrays espaados podem ser
representados de outra maneira sem consumir a mesma quantidade de memria.
Existe um equilbrio quando se otimizando tamanho e velocidade. Utilizar estruturas complexas
de dados pode afetar a velocidade de execuo do programa.

5.2. Liberar objetos no usados para o Garbage Collector

Libere objetos que no sero mais utilizados para o Garbage Collector tela, conexes de rede,
Registros RMS, entre outros. Ao atribuir para estes objetos o valor nulo, informamos ao Garbage
Collector que estes objetos podem ser seguramente descarregados da memria.

5.3. Criar as telas que so raramente usadas como objetos annimos

Criar os objetos de Tela que so raramente utilizadas (como telas de auxlio e sobre o
sistema) como objetos annimos libera a necessidade de memria heap, embora tenhamos que
pagar o preo por uma carga mais lenta destas telas em particular. A memria heap destas telas
supostamente seria ocupada enquanto elas no estivessem sendo usadas e pode ajudar na
conservao de memria.
public void commandAction(Command c, Displayable d) {
if (c == helpCommand) {
display.setCurrent(new HelpForm());
}
}

Desenvolvimento de Aplicaes Mveis 12


JEDITM

6. Exerccios
6.1. Outras idias de otimizao

Discuta outras idias de otimizao que possui ou tem em mente ou, ainda, outras tcnicas que
desenvolveu. Compartilhe-as.

Desenvolvimento de Aplicaes Mveis 13


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 9
Pacotes Opcionais

Verso 1.0 - Set/2007


JEDITM

1. Objetivos
Nesta lio, iremos aprofundar em como escrever, construir, utilizar o emulador e o empacotador
de aplicaes J2ME. O ambiente de programao que iremos utilizar ser o Netbeans.
Nem todos os dispositivos so criados de maneira semelhante, pois cada um deles possui
caractersticas diferentes. Por isso pode ser muito complicado para se criar uma especificao
padro que atenda a todos os dispositivos.
Para acomodar as diferentes capacidades de cada dispositivo, a tecnologia MIDP definiu vrios
pacotes opcionais. Esses pacotes so especficos para atender dispositivos especficos que tenham
esses recursos. Iremos aprender como utilizar a Mobile Media API (MMAPI) e a Wireless
Messaging API (WMA).
Ao final desta lio, o estudante ser capaz de:
Saber quais so as funcionalidade oferecidas pela Mobile Media API
Reproduzir tons simples
Reproduzir um arquivo de udio de uma rede e de um JAR
Enviar e receber mensagens SMS

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. Mobile Media API (MMAPI)


A Mobile Media API (MMAPI) permite-nos gerar tons, tocar e gravar udio e vdeo nos dispositivos
compatveis. A reproduo e a gravao de mdia so tratadas por dois objetos: o DataSource e o
Player.

DataSource Player

Figura 1: Relao entre DataSource e Player

O DataSource trata de detalhes de como obter o dado de uma fonte. A fonte pode ser um arquivo
de um JAR ou de uma rede (via HTTP), um registro de um RMS, uma conexo de streaming de
um servidor ou outra fonte proprietria. O Player no tem o que se preocupar sobre de onde o
dado vem ou de que uma maneira ele pode ser obtido. Tudo o que o Player necessita fazer ler
um dado de um DataSource, processar e exibir ou reproduzir a mdia para o dispositivo de sada.
O terceiro ator na nossa cena o Manager. O Manager cria players de DataSources. O Manager
tem mtodos para criar Players vindos dos locais de mdia (atravs de URL), DataSources e
InputStreams.

Manager

DataSource Player

Figura 2: Relacionamento do Manager com o DataSource e Player

Pode-se consultar propriedades MMAPI via String System.getProperty(String key).

Chave Descrio
microedition.media.version A verso da especificao MMAPI implementada pelo dispositivo.
Exemplo: "1.1"
supports.mixing Retorna "true" se o dispositivo suporta mixagem de udio. Pode
reproduzir os dois ltimos tons simultaneamente. Pode ter dois
Players reproduzindo udio simultaneamente e pode reproduzir
um tom enquanto o outro Player est reproduzindo udio ao
mesmo tempo.
supports.audio.capture Retorna "true" se a captura de udio suportada.

supports.video.capture Retorna "true" se a captura de vdeo suportada.

supports.recording Retorna "true" se a gravao de udio suportada.

2.1. Gerao de Tons

Para reproduzir tons necessrio chamar o mtodo esttico Manager.playTone(int tom, int
duration, int volume). Os valores vlidos para o parmetro tom vo de 0 a 127. O parmetro
duration representa a durao da reproduo do tom e deve ser especificada em milissegundos. O
parmetro volume varia de 0 a 100.

Desenvolvimento de Aplicaes Mveis 5


JEDITM

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;

public class ToneMIDlet extends MIDlet implements CommandListener{


private Command exitCommand, playCommand;
private Form form;
private Gauge volumeGauge;
private Gauge durationGauge;
private Gauge toneGauge;
private Display display;
private int duration = 2; // seconds
private int volume = 100;
private int tone = ToneControl.C4;
private static int MAX_VOLUME = 100;
private static int MAX_TONE = 127;
private static int MAX_DURATION = 5;

public ToneMIDlet() {
playCommand = new Command("Play", Command.OK, 1);
exitCommand = new Command("Exit", Command.EXIT, 1);
volumeGauge = new Gauge("Volume", true, MAX_VOLUME, volume);
toneGauge = new Gauge("Tone", true, MAX_TONE, tone);
durationGauge = new Gauge("Duration",true,MAX_DURATION,duration);

form = new Form("Tone Player");


form.addCommand(playCommand);
form.addCommand(exitCommand);
form.append(volumeGauge);
form.append(durationGauge);
form.append(toneGauge);
}
public void startApp() {
display = Display.getDisplay(this);
form.setCommandListener(this);
display.setCurrent(form);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand) {
notifyDestroyed();
}
if (c == playCommand){
try {
volume = volumeGauge.getValue();
tone = toneGauge.getValue();
duration = durationGauge.getValue();
Manager.playTone(tone, duration*1000, volume);
} catch (MediaException mex){}
}
}
}

2.2. Tocando udio

Por convenincia, o mtodo Manager.createPlayer(String URI) cria um objeto player a partir de


uma URI.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;

Desenvolvimento de Aplicaes Mveis 6


JEDITM

public class NetAudioMidlet extends MIDlet implements CommandListener{


private Command exitCommand, playCommand;
private Form form;
private Gauge volumeGauge;
private Display display;
private int volume = 100;
private static int MAX_VOLUME = 100;
Player player;

public NetAudioMidlet() {
playCommand = new Command("Play", Command.OK, 1);
exitCommand = new Command("Exit", Command.EXIT, 1);
volumeGauge = new Gauge("Volume", true, MAX_VOLUME, volume);
form = new Form("Audio Player");
form.addCommand(playCommand);
form.addCommand(exitCommand);
form.append(volumeGauge);
}
public void startApp() {
display = Display.getDisplay(this);
form.setCommandListener(this);
display.setCurrent(form);
try {
player = Manager.createPlayer("http://localhost:8084/Chapter07/bong.wav");
player.realize();
player.prefetch();
} catch (IOException ioex) {
display.setCurrent(new Alert("IO Exception",
ioex.getMessage(),
null, AlertType.ERROR));
} catch (MediaException mex) {
display.setCurrent(new Alert("Media Exception",
mex.getMessage(),
null, AlertType.ERROR));
}
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand) {
notifyDestroyed();
}
if (c == playCommand){
try {
VolumeControl control = (VolumeControl)
player.getControl("VolumeControl");
if (control != null){
control.setLevel(volumeGauge.getValue());
}

player.start();
} catch (MediaException mex) {
display.setCurrent(new Alert("Media Exception",
mex.getMessage(), null, AlertType.ERROR));
} catch (Exception ex){
display.setCurrent(new Alert("Exception",
ex.getMessage(), null, AlertType.ERROR));
}
}
}
}

Tambm possvel tocar uma mdia a partir de um arquivo inserido no JAR do projeto.
Entretanto, deve ser criado um objeto do tipo Stream que ser repassado para o mtodo
Manager.createPlayer().

Desenvolvimento de Aplicaes Mveis 7


JEDITM

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;

public class AudioMidlet extends MIDlet implements CommandListener{


private Command exitCommand, playCommand;
private Form form;
private Gauge volumeGauge;
private Display display;
private int volume = 100;
private static int MAX_VOLUME = 100;
Player player;

public AudioMidlet() {
playCommand = new Command("Play", Command.OK, 1);
exitCommand = new Command("Exit", Command.EXIT, 1);
volumeGauge = new Gauge("Volume", true, MAX_VOLUME, volume);
form = new Form("Audio Player");
form.addCommand(playCommand);
form.addCommand(exitCommand);
form.append(volumeGauge);
}
public void startApp() {
display = Display.getDisplay(this);
form.setCommandListener(this);
display.setCurrent(form);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand) {
notifyDestroyed();
}
if (c == playCommand){
try {
InputStream stream = getClass().
getResourceAsStream("bong.wav");
player = Manager.createPlayer(stream, "audio/x-wav");
player.realize();

VolumeControl control = (VolumeControl)


player.getControl("VolumeControl");
if (control != null){
control.setLevel(volumeGauge.getValue());
}

player.start();
} catch (MediaException mex) {
display.setCurrent(new Alert("Media Exception",
mex.getMessage(), null, AlertType.ERROR));

} catch (Exception ex){


display.setCurrent(new Alert("Exception",
ex.getMessage(), null, AlertType.ERROR));
}
}
}
}

Desenvolvimento de Aplicaes Mveis 8


JEDITM

3. Wireless Messaging API (WMA)


Utilizar o Wireless Messaging API quase semelhante maneira que uma conexo feita atravs
de soquetes e Datagramas. Utiliza-se o mesmo aplicativo Generic Connection Framework (GCF).
A URL de conexo possui o seguinte formato "sms://+639178888888", onde "+639178888888"
o nmero do telefone para qual se deseja enviar a mensagem.
public void sendSMS(String number, String message) throws Exception{
String url = "sms://" + number;
MessageConnection connection = (MessageConnection) Connector.open(url);
TextMessage msg = (TextMessage) connection.newMessage(
MessageConnection.TEXT_MESSAGE);
msg.setPayloadText(message);
connection.send(msg);
connection.close();
}

3.1. Enviando uma mensagem SMS

O desenvolvimento de aplicaes mveis com o Netbeans muito simples. No necessrio


enviar mensagens reais de SMS apenas para testar a aplicao que estamos desenvolvendo. O
Netbeans (com o pacote Mobility) possui a ferramenta J2ME Wireless Toolkit. Esta ferramenta vem
com um emulador e inclui tambm aplicativos para testar o envio e recebimento de mensagens
do tipo SMS. possvel configurar o nmero do telefone utilizando as preferncias do WMA
acessando a partir do menu principal:
Tools
Java Platform Manager
J2ME Wireless Toolkit 2.2
Tools & Extensions
Preferences -> WMA
Utilities -> WMA: Open Console

Figura 3: Java Platform Manager

Desenvolvimento de Aplicaes Mveis 9


JEDITM

Figura 4: Java Platform Manager - Devices

Figura 5: Java Platform Manager Tools & Extensions

Desenvolvimento de Aplicaes Mveis 10


JEDITM

Figura 6: J2ME Wireless Toolkit Preferences

Figura 7: J2ME Wireless Toolkit Utilities e Console

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.wireless.messaging.*;

public class SMSMidlet extends MIDlet implements CommandListener, Runnable {

private Command exitCommand, sendCommand;

Desenvolvimento de Aplicaes Mveis 11


JEDITM

private Form form;


private TextField addressField, mesgField;
private Display display;

public SMSMidlet() {
sendCommand = new Command("Send", Command.OK, 1);
exitCommand = new Command("Exit", Command.EXIT, 1);

addressField = new TextField(


"Phone Number", "+5550000", 32, TextField.ANY);
mesgField = new TextField(
"Message", "hello, world!", 160, TextField.ANY);

form = new Form("SMS Message");


form.append(addressField);
form.append(mesgField);
form.addCommand(sendCommand);
form.addCommand(exitCommand);
}

public void startApp() {


display = Display.getDisplay(this);
form.setCommandListener(this);
display.setCurrent(form);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand) {
notifyDestroyed();
}
if (c == sendCommand) {
Thread thread = new Thread( this );
thread.start();
}
}
public void sendSMS(String number, String message) throws Exception{
String url = "sms://" + number;
MessageConnection connection =
(MessageConnection) Connector.open(url);
TextMessage msg = (TextMessage) connection.newMessage(
MessageConnection.TEXT_MESSAGE);
msg.setPayloadText(message);
connection.send(msg);
connection.close();
}
public void run() {
try {
String address = addressField.getString();
String message = mesgField.getString();
sendSMS(address, message);
display.setCurrent(new Alert("SMS Message", "Message Sent\n"
+ "To: " + address + "\n" + "Message: " + message, null,
AlertType.INFO));
} catch (Exception ex) {
display.setCurrent(new Alert("SMS Error", ex.getMessage(),
null, AlertType.ERROR));
}
}
}

Desenvolvimento de Aplicaes Mveis 12


JEDITM

Figura 8: Execuo da aplicao

3.2. Recebendo mensagens SMS

Para receber um mensagem de texto, abra uma MessageConnection especificando uma porta. O
Protocolo para mensagem SMS "sms". Este comando ficar esperando at receber uma
mensagem de SMS pela porta 8888:
conn = (MessageConnection) Connector.open("sms://:8888");

Devemos registrar nossa aplicao para ser um receptor da mensagem de forma que o AMS
notifique o MIDlet da chegada da mensagem.
conn.setMessageListener(this);

O mtodo notifyIncomingMessage ser chamado pelo AMS quando uma mensagem for recebida

Desenvolvimento de Aplicaes Mveis 13


JEDITM

pelo dispositivo. Precisamos criar uma Thread separada para as mensagens de leitura de forma
que o mtodo que for chamado novamente possa ter uma sada imediata.
public void notifyIncomingMessage(MessageConnection messageConnection) {
if (thread == null){
thread = new Thread(this);
thread.start();
}
}

E, deste modo, ser utilizado o mtodo run(), do qual obteremos a mensagem:


public void run(){
try {
Message mesg = conn.receive();
if (mesg != null && mesg instanceof TextMessage) {
TextMessage text = (TextMessage) mesg;
addressField.setText(text.getAddress());
mesgField.setText(text.getPayloadText());
dateField.setText("" + text.getTimestamp());
statusField.setText("Message received.");
}
} catch (Exception e) {
statusField.setText("Error: " + e.getMessage());
}
thread = null;
}

Este o cdigo completo para receber e listar a mensagem SMS:


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.wireless.messaging.*;

public class SMSReceiverMidlet extends MIDlet


implements CommandListener, MessageListener, Runnable {
private Command exitCommand, sendCommand;
private Form form;
private StringItem statusField, addressField, mesgField, dateField;
private Display display;
private MessageConnection conn;
private Thread thread;
private String port = "8888";

public SMSReceiverMidlet() {
exitCommand = new Command("Exit", Command.EXIT, 1);
statusField = new StringItem("Status:", "");
addressField = new StringItem("From:", "");
mesgField = new StringItem("Message:", "");
dateField = new StringItem("Timestamp:", "");
form = new Form("SMS Receiver");
form.append(statusField);
form.append(addressField);
form.append(mesgField);
form.append(dateField);
form.addCommand(exitCommand);
}
public void startApp() {
display = Display.getDisplay(this);
form.setCommandListener(this);

startReceiver();
display.setCurrent(form);
}
public void pauseApp() {
thread = null;

Desenvolvimento de Aplicaes Mveis 14


JEDITM

}
public void destroyApp(boolean unconditional) {
thread = null;
if (conn != null){
try {
conn.close();
} catch (Exception ex){}
}
}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand) {
notifyDestroyed();
}
}
private void startReceiver(){
try {
String addr = "sms://:" + port;
if (conn == null){
conn = (MessageConnection) Connector.open(addr);
conn.setMessageListener(this);
statusField.setText(
"waiting for message at port " + port);
}
} catch (Exception ex){
statusField.setText("Cannot open connection on port "
+ port + ":" + ex.getMessage());
}
thread = new Thread(this);
thread.start();
}
public void notifyIncomingMessage(MessageConnection messageConn) {
if (thread == null){
thread = new Thread(this);
thread.start();
}
}
public void run(){
try {
Message mesg = conn.receive();
if (mesg != null && mesg instanceof TextMessage) {
TextMessage text = (TextMessage) mesg;
addressField.setText(text.getAddress());
mesgField.setText(text.getPayloadText());
dateField.setText("" + text.getTimestamp());
statusField.setText("Message received.");
} else {
statusField.setText(
"Non-text message received: "
+ mesg.getClass().toString());
}
} catch (Exception e) {
statusField.setText("Error: " + e.getMessage());
}
thread = null;
}
}

Desenvolvimento de Aplicaes Mveis 15


JEDITM

Figura 9: Recebimento da mensagem

Desenvolvimento de Aplicaes Mveis 16


JEDITM

4. Exerccios
4.1. Tocador de udio

Crie uma MIDlet que toque um arquivo de udio por um nmero indefinido de vezes. O arquivo de
udio deve ser lido a partir do JAR da aplicao. Dica: envie uma propriedade para o objeto Player
controlar o lao.

4.2. Auto-respondedor de SMS

Crie uma MIDlet que responda automaticamente quando receber uma mensagem de texto. Dica:
modifique a classe SMSReceiverMidlet e utilize a mesma conexo para enviar a mensagem de
resposta.

Desenvolvimento de Aplicaes Mveis 17


Mdulo 5
Desenvolvimento de Aplicaes Mveis

Lio 10
Outros Tpicos

Verso 1.0 - Set/2007


JEDITM

1. Objetivos
Timers e TimeTasks permitem programar tarefas para que sejam executadas em um horrio
determinado. A tarefa pode ainda ser programada para que se repita num intervalo de tempo
designado pelo programador.
Ao final desta lio, o estudante ser capaz de:
Programar tarefas utilizando Timers (marcadores)
Registrar o recebimento de conexes no Registro

Desenvolvimento de Aplicaes Mveis 4


JEDITM

2. Timers
possvel criar uma tarefa utilizando-se a herana, estendendo a classe TimerTask e
implementando o mtodo run(). Este mtodo ser executado baseado na programao do Timer.
class CounterTask extends TimerTask {
int counter = 0;
public void run() {
System.out.println("Counter: " + counter++);
}
}

Para programar uma tarefa, cria-se um objeto do tipo Timer e utiliza-se o mtodo schedule() do
Timer para que se possa configurar o andamento da tarefa. Cada Timer roda em uma thread
independente. O mtodo schedule() possui vrias formas diferentes. possvel especificar o
tempo de incio para a tarefa utilizando um tempo em milissegundos ou especificando uma data
absoluta (java.util.Date). O terceiro parmetro para o mtodo o perodo de repetio da tarefa.
Se o perodo de repetio for especificado, a tarefa ser executada a cada "perodo" de
milissegundos definido.
Timer timer = new Timer();
TimerTask task = new CounterTask();
// inicia a tarefa em 8 segundos, e repete a cada segundo
timer.schedule(task, 8000, 1000);

Para parar a execuo do objeto Timer, utiliza-se o mtodo close(). Isto far com que a Thread
contendo o Timer seja interrompida e a tarefa agendada, descartada. Lembre-se sempre de que
uma vez que o Timer tenha sido parado, no poder ser reiniciado.
void schedule( Agendar a tarefa para que seja executada a cada perodo (em
TimerTask task, milissegundos).
long delay)
void schedule( Agendar a tarefa para que ela seja repetida, comeando aps
TimerTask task, o perodo especificado (em milissegundos).
long delay,
long period)
void schedule( Agenda a tarefa para que seja executada num tempo
TimerTask task, especfico.
Date time)
void schedule( Agenda a tarefa para que ela seja repetida, comeando pelo
TimerTask task, tempo especificado.
Date time,
long period)
void cancel() Interrompe o timer e descarta qualquer tarefa agendada.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;

public class TimerMidlet extends MIDlet implements CommandListener{


private Command exitCommand;
private Form form;
private StringItem textField;
private Display display;
private Timer timer;

public TimerMidlet() {
exitCommand = new Command("Exit", Command.EXIT, 1);
textField = new StringItem("Counter", "");
timer = new Timer();

Desenvolvimento de Aplicaes Mveis 5


JEDITM

TimerTask task = new CounterTask(this);


timer.schedule(task, 2000, 1000);
form = new Form("Timer Test");
form.addCommand(exitCommand);
form.append(textField);
}
public void startApp() {
display = Display.getDisplay(this);
form.setCommandListener(this);
display.setCurrent(form);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {
timer.cancel();
}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand) {
destroyApp(true);
notifyDestroyed();
}
}
public void setText(String text){
textField.setText(text);
}
}
class CounterTask extends TimerTask {
int counter = 0;
TimerMidlet midlet;

public CounterTask(TimerMidlet midlet){


this.midlet = midlet;
}
public void run() {
counter++;
midlet.setText("" + counter);
System.out.println("Counter: " + counter);
}
}

Desenvolvimento de Aplicaes Mveis 6


JEDITM

3. Registro de Conexes
Permite que os MIDlets registrem as conexes com o software de gerenciamento da aplicao
(AMS). Se o programa no estiver em execuo, o AMS ficar esperando por conexes nos limites
dos endereos registrados pelas aplicaes. Quase todos os tipos de conexes so suportadas,
incluindo SMS, CBS e AMS.
possvel fazer o registro de novas conexes de duas maneiras: da maneira esttica, utilizando o
arquivo application descriptor (JAD), ou dinamicamente durante o tempo de execuo, utilizando
a API PushRegistry.
Iremos demostrar como utilizar a API PushRegistry. Pressionar o boto direito do mouse sobre o
Project Name e selecionar properties para abrir a pgina de propriedades do projeto. Selecionar a
opo de Push Registry.

Figura 1: Janela de Propriedades do Projeto

Pressionar o boto add... para registrar uma nova conexo:

Figura 2: Adicionando um novo registro

Class Name: SMSReceiveMidlet


Sender IP: *

Desenvolvimento de Aplicaes Mveis 7


JEDITM

Connection String: sms://:50000

Verifique a conexo adicionada na figura abaixo.

Figura 3: Registro da Conexo

Selecionar a opo API Permissions e pressionar o boto Add para inserir uma permisso do
MIDlet para uma biblioteca em particular.

Figura 4: Adicionando permisses

Adicionar as seguintes bibliotecas:


javax.microedition.io.PushRegistry
javax.microedition.io.Connector.sms
javax.wireless.messaging.sms.receive
javax.wireless.messaging.sms.send

Desenvolvimento de Aplicaes Mveis 8


JEDITM

Figura 5: Permisses adicionadas

Para finalizar, criar um atributo para configurar automaticamente a porta, selecionar Attributes
conforme a seguinte janela:

Figura 6: Adicionar novos atributos

Pressionar o boto Add... para adicionar um novo atributo do tipo Custom.

Desenvolvimento de Aplicaes Mveis 9


JEDITM

Figura 7: Adicionando o atributo

Encerre a janela de configurao do projeto pressionando o boto OK e execute a suite do MIDlet.


Executar a aplicao duas vezes para conseguir dois emuladores conforme as figuras:

Figura 8: Emulador do aplicativo

Observe que o primeiro telefone possui o nmero +5550000 e o segundo +5550001. Selecionar
a opo SMSReceiveMidlet no primeiro telefone. Uma mensagem solicitando a autorizao para
comunicao via mensagem ser mostrada, selecionar a opo Yes e deixar em modo de espera:

Figura 9: Modo de Espera da Mensagem

Desenvolvimento de Aplicaes Mveis 10


JEDITM

No segundo telefone, selecionar SMSSendMidlet, informar o endereo 5550000 e pressionar OK.

Figura 10: Emulador do aplicativo

Digitar uma mensagem e pressionar Send:

Figura 11: Janela de confirmao

Responder afirmativamente mensagem de confirmao da comunicao:

Figura 12: Confirmao da Comunicao

Responder afirmativamente a prxima mensagem e aguardar o envio. Observar no primeiro


telefone o recebimento da mensagem.

Figura 13: Aplicativo concludo

Desenvolvimento de Aplicaes Mveis 11


JEDITM

3.1. Programas

Classe Auxiliar
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.wireless.messaging.*;
import java.io.IOException;

public class SMSSender implements CommandListener, Runnable {


Command sendCommand = new Command("Send", Command.OK, 1);
Command backCommand = new Command("Back", Command.BACK, 2);
Display display;
String smsPort;
String destinationAddress;
TextBox messageBox;
Displayable backScreen;
Displayable sendingScreen;

public SMSSender(String smsPort, Display display,


Displayable backScreen, Displayable sendingScreen) {
this.smsPort = smsPort;
this.display = display;
this.destinationAddress = null;
this.backScreen = backScreen;
this.sendingScreen = sendingScreen;
messageBox = new TextBox("Enter Message", null, 65535, TextField.ANY);
messageBox.addCommand(backCommand);
messageBox.addCommand(sendCommand);
messageBox.setCommandListener(this);
}
public void promptAndSend(String destinationAddress) {
this.destinationAddress = destinationAddress;
display.setCurrent(messageBox);
}
public void commandAction(Command c, Displayable s) {
try {
if (c == backCommand) {
display.setCurrent(backScreen);
} else if (c == sendCommand) {
display.setCurrent(sendingScreen);
new Thread(this).start();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void run() {
String address = destinationAddress + ":" + smsPort;
MessageConnection smsconn = null;
try {
smsconn = (MessageConnection)Connector.open(address);
TextMessage txtmessage = (TextMessage)smsconn.newMessage(
MessageConnection.TEXT_MESSAGE);
txtmessage.setAddress(address);
txtmessage.setPayloadText(messageBox.getString());
smsconn.send(txtmessage);
} catch (Throwable t) {
System.out.println("Send caught: ");
t.printStackTrace();
}
if (smsconn != null) {
try {
smsconn.close();
} catch (IOException ioe) {
System.out.println("Closing connection caught: ");

Desenvolvimento de Aplicaes Mveis 12


JEDITM

ioe.printStackTrace();
}
}
}
}

Midlet para receber mensagem SMS


import javax.microedition.midlet.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.wireless.messaging.*;
import java.io.IOException;

public class SMSReceiveMidlet extends MIDlet


implements CommandListener, Runnable, MessageListener {
Command exitCommand = new Command("Exit", Command.EXIT, 2);
Command replyCommand = new Command("Reply", Command.OK, 1);
Alert content;
Display display;
Thread thread;
String[] connections;
boolean done;
String smsPort;
MessageConnection smsconn;
Message msg;
String senderAddress;
Alert sendingMessageAlert;
SMSSender sender;
Displayable resumeScreen;

public SMSReceiveMidlet() {
smsPort = getAppProperty("SMS-Port");
display = Display.getDisplay(this);
content = new Alert("SMS Receive");
content.setTimeout(Alert.FOREVER);
content.addCommand(exitCommand);
content.setCommandListener(this);
content.setString("Receiving...");
sendingMessageAlert = new Alert("SMS", null, null, AlertType.INFO);
sendingMessageAlert.setTimeout(5000);
sendingMessageAlert.setCommandListener(this);
sender = new SMSSender(smsPort, display, content, sendingMessageAlert);
resumeScreen = content;
}
public void startApp() {
String smsConnection = "sms://:" + smsPort;
if (smsconn == null) {
try {
smsconn = (MessageConnection) Connector.open(smsConnection);
smsconn.setMessageListener(this);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
connections = PushRegistry.listConnections(true);
if (connections == null || connections.length == 0) {
content.setString("Waiting for SMS on port " + smsPort + "...");
}
done = false;
thread = new Thread(this);
thread.start();

display.setCurrent(resumeScreen);
}
public void notifyIncomingMessage(MessageConnection conn) {
if (thread == null) {

Desenvolvimento de Aplicaes Mveis 13


JEDITM

done = false;
thread = new Thread(this);
thread.start();
}
}
public void run() {
try {
msg = smsconn.receive();
if (msg != null) {
senderAddress = msg.getAddress();
content.setTitle("From: " + senderAddress);
if (msg instanceof TextMessage) {
content.setString(((TextMessage)msg).getPayloadText());
} else {
StringBuffer buf = new StringBuffer();
byte[] data = ((BinaryMessage)msg).getPayloadData();
for (int i = 0; i < data.length; i++) {
int intData = (int)data[i] & 0xFF;
if (intData < 0x10) {
buf.append("0");
}
buf.append(Integer.toHexString(intData));
buf.append(' ');
}
content.setString(buf.toString());
}
content.addCommand(replyCommand);
display.setCurrent(content);
}
} catch (IOException e) {
// e.printStackTrace();
}
}
public void pauseApp() {
done = true;
thread = null;
resumeScreen = display.getCurrent();
}
public void destroyApp(boolean unconditional) {
done = true;
thread = null;
if (smsconn != null) {
try {
smsconn.close();
} catch (IOException e) {
// Ignora erros no caso de finalizao
}
}
}
public void commandAction(Command c, Displayable s) {
try {
if (c == exitCommand || c == Alert.DISMISS_COMMAND) {
destroyApp(false);
notifyDestroyed();
} else if (c == replyCommand) {
reply();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void reply() {
String address = senderAddress.substring(6);
String statusMessage = "Sending message to " + address + "...";
sendingMessageAlert.setString(statusMessage);
sender.promptAndSend(senderAddress);
}

Desenvolvimento de Aplicaes Mveis 14


JEDITM

Midlet para enviar mensagem SMS


import javax.microedition.midlet.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.wireless.messaging.*;
import java.io.IOException;

public class SMSSendMidlet extends MIDlet implements CommandListener {


Command exitCommand = new Command("Exit", Command.EXIT, 2);
Command okCommand = new Command("OK", Command.OK, 1);
Display display;
String smsPort;
TextBox destinationAddressBox;
Alert errorMessageAlert;
Alert sendingMessageAlert;
SMSSender sender;
Displayable resumeScreen = null;

public SMSSendMidlet() {
smsPort = getAppProperty("SMS-Port");
display = Display.getDisplay(this);
destinationAddressBox = new TextBox("Destination Address?",
null, 256, TextField.PHONENUMBER);
destinationAddressBox.addCommand(exitCommand);
destinationAddressBox.addCommand(okCommand);
destinationAddressBox.setCommandListener(this);
errorMessageAlert = new Alert("SMS", null, null, AlertType.ERROR);
errorMessageAlert.setTimeout(5000);
sendingMessageAlert = new Alert("SMS", null, null, AlertType.INFO);
sendingMessageAlert.setTimeout(5000);
sendingMessageAlert.setCommandListener(this);
sender = new SMSSender(smsPort, display, destinationAddressBox,
sendingMessageAlert);
resumeScreen = destinationAddressBox;
}
public void startApp() {
display.setCurrent(resumeScreen);
}
public void pauseApp() {
resumeScreen = display.getCurrent();
}
public void destroyApp(boolean unconditional) {
}
public void commandAction(Command c, Displayable s) {
try {
if (c == exitCommand || c == Alert.DISMISS_COMMAND) {
destroyApp(false);
notifyDestroyed();
} else if (c == okCommand) {
promptAndSend();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void promptAndSend() {
String address = destinationAddressBox.getString();
if (!SMSSendMidlet.isValidPhoneNumber(address)) {
errorMessageAlert.setString("Invalid phone number");
display.setCurrent(errorMessageAlert, destinationAddressBox);
return;
}
String statusMessage = "Sending message to " + address + "...";
sendingMessageAlert.setString(statusMessage);

Desenvolvimento de Aplicaes Mveis 15


JEDITM

sender.promptAndSend("sms://" + address);
}
private static boolean isValidPhoneNumber(String number) {
char[] chars = number.toCharArray();
if (chars.length == 0) {
return false;
}
int startPos = 0;
if (chars[0] == '+') {
startPos = 1;
}
for (int i = startPos; i < chars.length; ++i) {
if (!Character.isDigit(chars[i])) {
return false;
}
}
return true;
}
}

Desenvolvimento de Aplicaes Mveis 16


JEDITM

4. Exerccios
4.1. Relgio no Celular

Criar um MIDlet que mostre a data e hora atual e que seja atualizada a cada segundo. Utilize um
Timer para atualizar a data e hora e um StringItem para exibi-las.

Desenvolvimento de Aplicaes Mveis 17


JEDITM

Parceiros que tornaram JEDITM possvel

Instituto CTS
Patrocinador do DFJUG.

Sun Microsystems
Fornecimento de servidor de dados para o armazenamento dos vdeo-aulas.

Java Research and Development Center da Universidade das Filipinas


Criador da Iniciativa JEDITM.

DFJUG
Detentor dos direitos do JEDITM nos pases de lngua portuguesa.

Banco do Brasil
Disponibilizao de seus telecentros para abrigar e difundir a Iniciativa JEDITM.

Politec
Suporte e apoio financeiro e logstico a todo o processo.

Borland
Apoio internacional para que possamos alcanar os outros pases de lngua
portuguesa.

Instituto Gaudium/CNBB
Fornecimento da sua infra-estrutura de hardware de seus servidores para que os
milhares de alunos possam acessar o material do curso simultaneamente.

Desenvolvimento de Aplicaes Mveis 18

Você também pode gostar