Escolar Documentos
Profissional Documentos
Cultura Documentos
Lio 1
Introduo
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).
Auxiliadores especiais
Coordenao do DFJUG
Agradecimento Especial
John Paul Petines Criador da Iniciativa JEDITM
Rommel Feria Criador da Iniciativa 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.
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.
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.
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
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
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
3.4 Perfis
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
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).
File.java
Instalao
File.class
pr-verificar interpretar
File.class
Mquina de
Desenvolvimento Dispositivo
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
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.
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.
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
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.
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.
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()
9. Exerccios
9.1. Quais so as vantagens do uso de Java como plataforma de
desenvolvimento e execuo para os dispositivos mveis?
Lio 2
Como Comear
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.
new
destroyApp()
startApp() Pausado
Destrudo
Ativo pauseApp()
destroyApp()
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 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);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void commandAction(Command c, Displayable d){
if (c == exitCommand){
destroyApp(true);
notifyDestroyed(); // Exit
}
}
}
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 {
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
Etapa 7: Selecionar na opo Categories a opo MIDP e em File Types a opo MIDlet
Passo 10: Compilar e Executar o MIDlet de maneira idntica vista nos projetos anteriores
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..."
Lio 3
Interface de Alto Nvel para o Usurio
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
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()
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.
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)
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.5. CommandListener
O CommandListener uma interface que possui um nico mtodo:
void commandAction(Command command, Displayable displayable)
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
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.
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:
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
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.*;
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
alerts[4].addCommand(okCommand);
// Define o Alert como Modal
alerts[5].setTimeout(Alert.FOREVER);
}
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 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);
}
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().
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.*;
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.
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);
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);
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);
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)
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
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);
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.
Lio 4
Interface de Baixo Nvel para o Usurio
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
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.
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.
import javax.microedition.lcdui.*;
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();
}
}
}
Com o midlet Hello, world! definimos a classe que estende a classe Canvas
class HelloCanvas extends Canvas implements CommandListener {
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());
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);
setCommandListener(this);
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
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.
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
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 );
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
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()
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
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
BOTTOM | HCENTER
BASELINE | HCENTER
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
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);
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);
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);
TOP | HCENTER
try {
Image image = Image.createImage("/jedi.png");
g.drawImage(image,
getWidth()/2, getHeight()/2,
Graphics.VCENTER | Graphics.HCENTER);
} catch (Exception e){}
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.*;
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.
Lio 5
Sistema de Gerenciamento de Registro
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.
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).
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.
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
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
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.
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
void setRecord(
int recordId, byte[] newData, int offset, int numBytes)
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);
Dicas de Programao:
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:");
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());
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
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)
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)
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();
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.*;
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.*;
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;
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
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:
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.
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);
Lio 6
Redes
1. Objetivos
Nesta lio, iremos estudar como acessar redes utilizando MIDlets.
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 (:)
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.
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
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
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;
}
...
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");
...
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.*;
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
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.
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.*;
Classe Client.java:
package socket;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
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) {
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.*;
try {
os.write(message.getBytes());
os.write("\r\n".getBytes());
} catch (IOException ioe) {
ioe.printStackTrace();
}
message = null;
}
}
public synchronized void stop() {
message = null;
notify();
}
}
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).
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.*;
Classe Server.java:
package socket;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
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() {
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) {
}
}
}
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.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
Classe Server.java:
package datagram;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public Server(ServerDatagramMidlet m) {
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();
}
}
}
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.*;
import javax.microedition.midlet.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
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 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();
}
}
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();
}
}
}
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.
Lio 7
Comunicao Corporativa
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).
Auxiliadores especiais
Coordenao do DFJUG
Agradecimento Especial
John Paul Petines Criador da Iniciativa JEDITM
Rommel Feria Criador da Iniciativa 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.
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 ...
}
Para criar um novo Projeto WEB (Web Project) no NetBeans, selecione a partir do menu principal
a opo File -> New Project...
Na janela acima selecione em Categories a opo Web e em Projects selecione a opo Web
Application.
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...
Na janela acima selecione em Categories a opo Web e em File Types selecione a opo Servlet.
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.
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" %>
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.
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"%>
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:
processRequest(request, response);
}
public String getServletInfo() {
return "Short description";
}
}
3.4.3. Operadores
> 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>
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}"/>
Exemplos:
Exemplo:
<c:set var="fullName" value="${lastName, firstName}" />
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}"]
/>
Exemplo:
<c:if test="${empty param.username}">No username</c:if>
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>
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>
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
ou
<c:forEach [var="varName"]
[varStatus="varStatusName"]
begin="begin" end="end" [step="step"]
>
instrues a serem executadas
</c:forEach>
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>
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
</c:forTokens >
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>
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
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`)
);
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);
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";
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>");
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 ("
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>
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])) {
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);
}
}
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
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")};
Lio 8
Otimizaes
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.
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");
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.
As chamadas de mtodos ocupam muita memria e tempo de execuo. Veja o item anterior.
Para ganhar tempo no incio das aplicaes, atrase todas as inicializaes pesadas at que sejam
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.
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.
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.
Esta tcnica est relacionada com a anteriormente vista. Quanto mais classes e interfaces, mais
(kilo)bytes teremos na aplicao final.
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.
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).
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.
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.
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.
4. Rede
4.1. Utilizar threads
Utilize uma thread separada para sua funo de rede para evitar travamentos da tela.
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.
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.
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.
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.
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());
}
}
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.
Lio 9
Pacotes Opcionais
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
DataSource 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
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.
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.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;
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);
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().
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;
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();
player.start();
} catch (MediaException mex) {
display.setCurrent(new Alert("Media Exception",
mex.getMessage(), null, AlertType.ERROR));
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.wireless.messaging.*;
public SMSMidlet() {
sendCommand = new Command("Send", Command.OK, 1);
exitCommand = new Command("Exit", Command.EXIT, 1);
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
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();
}
}
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;
}
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;
}
}
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.
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.
Lio 10
Outros Tpicos
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
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 TimerMidlet() {
exitCommand = new Command("Exit", Command.EXIT, 1);
textField = new StringItem("Counter", "");
timer = new Timer();
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.
Selecionar a opo API Permissions e pressionar o boto Add para inserir uma permisso do
MIDlet para uma biblioteca em particular.
Para finalizar, criar um atributo para configurar automaticamente a porta, selecionar Attributes
conforme a seguinte janela:
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:
3.1. Programas
Classe Auxiliar
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.wireless.messaging.*;
import java.io.IOException;
ioe.printStackTrace();
}
}
}
}
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) {
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);
}
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);
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;
}
}
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.
Instituto CTS
Patrocinador do DFJUG.
Sun Microsystems
Fornecimento de servidor de dados para o armazenamento dos vdeo-aulas.
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.