Buscar

Padrões Projetos Java

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você viu 3, do total de 21 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você viu 6, do total de 21 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você viu 9, do total de 21 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Prévia do material em texto

1/21 
 
Aplicando Padrões de Projetos em 
Java ME 
Solucione problemas comuns encontrados em aplicações móveis utilizando 
padrões de projetos para a plataforma Java ME 
RAMON RIBEIRO RABELLO, PEDRO JORGE FERREIRA TRECCANI E THIENNE JHONSON 
 
De que se trata o artigo: 
Utilizar padrões de projetos específicos para a plataforma Java ME para geração de conteúdo 
interativo em MIDP. 
Para que serve: 
Fornecer uma alternativa para aplicação de padrões de projetos existentes ou específicos para a 
plataforma Java ME em aplicações móveis, com o intuito de resolver problemas enfrentados durante 
o desenvolvimento de GUIs para MIDlets. 
Em que situação o tema é útil: 
Caso deseje utilizar padrões de projetos em Java ME que minimizem a complexidade enfrentada 
durante o desenvolvimento de conteúdo gráfico interativo. 
 
Aplicando padrões de projetos em Java ME: 
A plataforma Java ME se tornou uma das tecnologias mais utilizadas para o desenvolvimento de 
aplicações móveis. Com a evolução das tecnologias dos dispositivos (aumento do poder de 
processamento, de armazenamento, etc.), o desenvolvimento de MIDlets deixou de ser ad-hoc e 
passou a seguir um caráter mais profissional e comercial, no qual “BluePrints” disponíveis para as 
outras especificações da linguagem Java como Java SE ou Java EE puderam ser aplicados também 
para a versão móvel do Java. 
Diante deste cenário, vários desenvolvedores móveis começaram a aplicar tais padrões de projetos 
em seus projetos e obtiveram casos de sucesso. E outros, dentre eles Ben Hui, desenvolveram 
padrões de projetos específicos para solucionarem problemas comuns enfrentados durante o 
desenvolvimento de interfaces gráficas em MIDP, que são: Cascading Menu, Wizard Dialog, 
Pagination e Slide Show. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2/21 
 
Os padrões de projetos há muito tempo foram criados para solucionar problemas que nós, 
programadores, encontramos no desenvolvimento de cada dia, aumentando o nível de modularidade, 
a reusabilidade e diminuindo o grau de acoplamento entre os módulos ou componentes das nossas 
aplicações. 
Estes padrões (Design Patterns ou simplesmente Patterns) são muito utilizados e conhecidos nas 
plataformas Java SE e Java EE. Entretanto, o desenvolvimento de aplicações móveis na plataforma 
Java ME tem amadurecido a cada dia, e “BluePrints” específicos para a confecção de aplicações têm 
surgido. Tudo isso com o objetivo de diminuir o esforço no desenvolvimento de aplicações que 
precisam ser executadas em dispositivos com características limitadas, como é o caso dos telefones 
celulares e Smartphones. 
Este artigo irá demonstrar a viabilidade da utilização de padrões de projetos e como estes podem 
melhorar significativamente o desenvolvimento de MIDlets (aplicações para o perfil MIDP). Para 
isso, serão apresentados quatro padrões de projeto específicos para a plataforma Java ME: 
Cascading Menu, Wizard Dialog, Pagination e Slide Show. 
Restrições em dispositivos móveis 
Programar para dispositivos móveis requer um pouco de cautela, haja vista as limitadas 
configurações da maioria dos dispositivos. Restrições como baixo poder de processamento, 
capacidade de memória limitada e escassez de recursos gráficos ainda preocupam o desenvolvedor 
no momento de implementação da sua aplicação móvel Java ME. Em dispositivos celulares mais 
antigos, por exemplo, não há suporte para cores. Porém, há anos que os fabricantes de dispositivos 
produzem telefones celulares com suporte a cores. Com a evolução da tecnologia, hoje é comum 
encontrar um celular com suporte de 262 mil cores ou mais. 
Outro fator restritivo é o limite da tela na maioria dos dispositivos. Por exemplo, em um celular que 
possui uma resolução de 12.288 pixels (96 x 128), se torna difícil exibir um simples nome completo 
ou endereço de uma pessoa. 
Entretanto, o avanço da tecnologia dos dispositivos móveis, principalmente a capacidade de 
armazenamento (hoje podemos armazenar gigas de dados) e a de processamento, aliada ao 
fenômeno da convergência digital, têm proporcionado uma alternativa de melhoria no 
desenvolvimento de aplicações móveis, sendo possível elaborar arquiteturas mais robustas (várias 
camadas) a serem utilizadas por MIDlets. Hoje em dia é raro encontrar uma aplicação móvel que 
seja restrita a uma única MIDlet (e talvez mais algumas classes utilitárias), onde é possível perceber 
claramente a mistura das regras de negócios com componentes de Interface Gráfica com o Usuário, 
o que dificulta consideravelmente a reusabilidade e manutenibilidade. Portanto, para solucionar o 
problema, entram em cena os Padrões de Projeto. 
Padrões de projetos em Java ME 
Java ME, desde sua concepção, tem sido a plataforma preferida entre os desenvolvedores de 
aplicações para dispositivos móveis, graças às suas mais variadas características que seguem o lema 
do WORA (Write Once, Run Anywhere – escreva uma vez, execute em qualquer lugar), um dos 
fatores essenciais para a garantia da portabilidade da linguagem Java. Contudo, desenvolver 
aplicações para dispositivos que suportam essa plataforma ainda é desafiante. A evolução das 
tecnologias dos dispositivos móveis – quer seja de hardware ou de software – vem possibilitando a 
construção de sistemas móveis cada vez mais complexos, que podem variar desde uma aplicação M-
Commerce que realiza transações bancárias até um jogo de estratégia. 
Com o passar dos anos, os “desenvolvedores móveis” foram adquirindo experiências nessa 
plataforma e perceberam que para implementar determinada funcionalidade era necessário que 
tarefas semelhantes fossem replicadas por várias linhas de código, o que prejudicava a produtividade 
e tornava o desenvolvimento monótono. Assim, perceberam que determinados padrões de projetos 
poderiam ser adaptados para a plataforma Java ME e utilizados em suas aplicações sem 
comprometer o propósito deles. Os próprios arquitetos da versão móvel de Java utilizaram alguns 
patterns para a construção da plataforma (veja o quadro “O Padrão Factory em MIDP”). 
3/21 
 
Outros desenvolvedores criaram seus próprios padrões e aplicaram em suas aplicações, relatando 
casos de sucesso na utilização de tais padrões. Um deles, chamado Ben Hui, elaborou quatro 
padrões de projeto: Cascading Menu, Wizard Dialog, Pagination e SlideShow, os quais simplificam o 
desenvolvimento de conteúdo interativo usando o perfil MIDP (Mobile Information Device Profile). 
A seguir será descrito cada padrão. Para o desenvolvimento dos exemplos deste artigo, foi utilizada 
a IDE Eclipse 3.4 - Ganymede (www.eclipse.org/ganymede/) juntamente com o plugin EclipseME 
1.7.9 (http://eclipseme.org/) e para a emulação, a ferramenta Sun Java Wireless Toolkit 2.5.2 for 
CLDC, para as especificações CLDC 1.1 e MIDP 2.0. Os exemplos de código dos padrões de 
projetos mostrados neste artigo foram baseados nas implementações do autor dos padrões. O link 
para baixá-los está disponível na seção Links. Para cada padrão de projeto apresentado, será 
utilizado um quadro que mostra a arquitetura e descreve sucintamente o objetivo, o problema e sua 
solução, os elementos que fazem parte do padrão, a conseqüência da aplicação deste pattern e sua 
implementação. 
 
O padrão Factory em MIDP 
 Desde a concepção de Java ME que os projetistas utilizam o conceito de padrão de projeto. Um 
exemplo disso é o GCF (Generic Connection Framework ou Framework de Conexão Genérica), 
que – como o nome sugere – é a estrutura que o MIDP utiliza para a realização de vários tipos de 
conexões. Este pattern deve ser aplicado quando não for possível determinar o tipo de objeto que 
deve ser instanciado (como pode ser visto na Listagem 1). Sendo assim, o padrão Factory 
(Fábrica) – que é caracterizado como um padrão de projeto criacional – pode ser utilizado para 
abstrair todo o trabalho de criação do objeto. 
 No caso doGCF, percebemos claramente a presença deste padrão por meio da Classe 
javax.microedition.io.Connector, na qual chamamos o método Connector.open() e passamos como 
parâmetro apenas uma string representando a URL ao qual queremos ter acesso. Depois, de 
acordo com o tipo de protocolo que for passado (HTTP, Socket, HTTPS, Bluetooth, etc.), o 
framework instancia uma classe específica que implementa todas as funcionalidades referente 
àquele protocolo. Para isso, o parâmetro passado a Connector.open() deve estar no seguinte 
formato: {scheme}:[{target}][{params}], onde {scheme} representa o tipo de protocolo sendo 
acessado, {target} normalmente é algum endereço de rede (www.algumsite.com.br, por exemplo) e 
{params}, os parâmetros passados na URL no formato “;param=valor”. A arquitetura com os 
principais componentes do GCF é mostrada na Figura 1. 
 Dessa forma, podemos tratar qualquer tipo de conexão como um Connection. Porém, caso 
queiramos, por exemplo, realizar uma conexão do tipo HTTP, deveremos realizar um cast para a 
interface HttpConnection. Então, o framework se encarregará de instanciar a classe que 
implemente a interface HttpConnection, tudo isso de forma transparente para o desenvolvedor, 
graças ao padrão Factory. A Listagem 1 mostra este pattern em ação no GCF, na qual é passado 
como parâmetro para o método open() de Connector apenas uma String que indica a URL a qual 
será realizada a conexão. De antemão, não se sabe qual será o tipo de objeto retornado pelo 
método, haja vista que este retorna uma interface (HttpConnection) em vez de uma classe 
concreta. Então, o framework trata de analisar o protocolo de acordo com o esquema da url 
passada (que no nosso caso é http://) e depois instanciar uma classe (esta classe irá variar de 
acordo com a implementação da CLDC do fabricante) que implemente todas as funcionalidades 
deste protocolo. 
 
4/21 
 
 
Figura 1. Arquitetura do GCF em MIDP. 
 
Listagem 1. Exemplo do padrão Factory no GCF: FactoryPattern.java. 
public class FactoryPattern extends MIDlet implements CommandListener { 
 
 private HttpConnection con; 
 
 //página inicial do portal DevMedia 
 public final String URL = "http://www.devmedia.com.br/portal/default.asp"; 
 
 // outras declarações de variáveis 
 
 private void conectar() { 
 try { 
 // Utilização do padrão Factory 
 con = (HttpConnection) Connector.open(URL); 
 con.setRequestMethod(HttpConnection.GET); 
 
 // abre a conexão 
 is = con.openInputStream(); 
 
 // código para tratamento dos dados retornados 
 } 
 catch (IOException e) { 
 // tratamento adequado da exceção 
 } 
 } 
} 
 
Padrão Cascading Menu 
Várias são as maneiras de se implementar navegação em uma aplicação. Uma delas é por meio de 
menus. Para a representação de cada menu, uma possível implementação seria por meio de 
subclasses da classe javax.microedition.lcdui.List contendo várias opções de escolha. Um exemplo 
interessante da utilização do padrão Cascading Menu seria em uma aplicação do tipo guia de 
cidades, no qual o usuário vai navegando por vários menus até ser retornada alguma informação. 
No modelo de tratamento de eventos em Java ME, as classes que necessitem capturar o 
pressionamento de teclas devem implementar a interface javax.microedition.CommandListener 
5/21 
 
juntamente com seu método commandAction(), e configurar o método setCommandListener() do 
objeto que gerou o evento. No desenvolvimento de MIDlets comuns, cada objeto List implementa 
implicitamente (por meio da constante List.IMPLICIT passada no construtor da classe List) a interface 
javax.microedition.CommandListener. Sendo assim, o papel do controlador é realizado por esta para 
gerenciar o fluxo da aplicação e redirecionar para o menu de acordo com a escolha do usuário. Essa 
abordagem só é viável quando a aplicação estiver usando poucas subclasses de List para representar 
as listas com itens de menus. Supondo que uma MIDlet simples em Java ME tivesse mais de 15 
menus, além de ser necessário criar subclasses de List para cada menu, a gerência do controle do 
fluxo entre os menus torna-se mais complexo e custoso. 
Uma implementação de estrutura semelhante a essa pode ser alcançada por meio do padrão de 
projeto MVC (Model-View-Controller/Modelo-Visão-Controlador). Neste padrão, ocorre o total 
desacoplamento das responsabilidades de cada parte da aplicação, sendo que o Modelo de dados é 
responsável pela representação das regras de negócio, a Visão renderiza o modelo de dados por 
meio de componentes de Interface Gráfica com o Usuário (GUI – Graphical User Interface, na 
verdade, em Java ME este termo pode ser substituído por LCDUI – Liquid Crystal Display User 
Interface – que são componentes gráficos de MIDP que foram projetados especificamente para 
serem visualizados por dispositivos com telas reduzidas) e o Controlador é responsável por capturar 
eventos gerados pelo usuário (que pode ser o clique de uma tecla de um dispositivo), gerenciar o 
fluxo da aplicação e controlar a “conversa” com o modelo e a visão. O modelo informa à visão que 
os dados foram alterados e esta renderiza os dados com os valores atualizados. A arquitetura MVC é 
mostrada na Figura 2. 
O padrão Cascading Menu (ver Figura 3) pode ser considerado uma versão “móvel” do MVC. 
Sendo assim, o modelo de dados pode ser mantido e atualizado independente do tipo de visão que 
será utilizada. Qualquer rearranjo no sistema de menus implicará apenas na reorganização da 
estrutura do modelo representada por uma árvore de menus. 
 
 
 
Figura 2. A Arquitetura MVC. 
 
Pattern: Cascading Menu 
 
6/21 
 
Figura 3. Arquitetura do padrão Cascading Menu. 
Objetivo Permitir criar uma hierarquia complexa de menus, de forma a abstrair o 
encadeamento entre telas. 
Problema Para implementação de uma hierarquia de menus com lista de itens, 
normalmente em MIDP, seria necessário criar subclasses de List para cada 
menu a ser utilizado pela aplicação. 
Solução A Arquitetura MVC para desacoplar a parte do Modelo da Visão por meio de 
um Controlador. 
Participantes MenuList: Responsável pela visualização da hierarquia de itens de menu. 
Realiza o papel da visão. 
List: Componente gráfico de MIDP para representação de lista. 
MenuElement: Representa um elemento do menu, que pode ser um texto ou 
um outro menu aninhado. Representa o modelo. 
MDisplayable: Interface responsável pela visualização dos Displayables que 
desejam ser exibidos ao término da navegação dos menus. 
Displayable: Classe mãe de todos os componentes gráficos de MIDP. 
CommandListener: Interface de MIDP que permite capturar eventos de 
comandos (clique em uma tecla do dispositivo, por exemplo). Realiza o papel 
do Controlador. 
Conseqüências Uma hierarquia de menus mais complexa, porém, novas adições de menus à 
estrutura acontecem de modo mais simples. 
Implementação Vários elementos de menus são criados e adicionados na hierarquia por meio 
do método addChild() de MenuElement. Os Displayables que necessitem ser 
exibidos (de acordo com as opções de menus selecionadas) devem 
obrigatoriamente implementar o método onDisplay() de MDisplayable. Depois, 
chama-se o método showMenu() de MenuList para que a estrutura completa de 
menus seja visualizada. 
 
 O exemplo para este padrão será um guia de informações de cidades onde serão exibidos vários 
menus. O usuário selecionará o que deseja (por exemplo, informações sobre lazer, restaurantes, etc.) 
e conforme a opção escolhida, novos menus são apresentados de acordo com o filtro selecionado 
anteriormente. Ao término será mostrado uma mensagem informando o item selecionado. A Figura 
4 mostra a hierarquia de menus disponíveis na aplicação. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Figura 4. Hierarquia de menus no padrão Cascading Menu. 
 
O componenteMenuElement representa o modelo, que será utilizado para criar a árvore de menus. 
Cada MenuElement representa um nó (ou item do menu) da árvore de menus. Esses nós podem se 
Menu Principal 
 
Lojas 
Restaurantes 
Lazer 
 
Lojas 
 
Automóveis 
Livros 
Moda 
 
Restaurantes 
 
Padarias 
Cafés 
Refeições 
 
Lazer 
 
Museus 
Galerias 
Espetáculos 
 
7/21 
 
comportar tanto como um nó-pai ou nó-filho. Analisando a Listagem 2, podemos perceber que a 
relação de hierarquia é realizada pelo método addChild() que foi sobrecarregado e possui suas 
versões recebendo ambos dois parâmetros: addChild(child,next_container), no qual child representa o 
item de menu que está sendo adicionado e next_container, o próximo MenuElement a ser exibido 
assim que o item do menu for selecionado (se selecionássemos o item de menu “Lojas” na tela do 
menu principal, a tela de lojas disponíveis seria exibida em seguida); e addChild(child,display) onde 
display será o Displayable que será mostrado assim que child for selecionado. Esta classe possui o 
vetor children representando um container para MenuElements e o Hashtable menuMap, que fará o 
mapeamento dos próximos itens de menu ou Displayables que serão exibidos. O método 
commandAction() possui a regra de negócio para escolher o que será visualizado assim que o item de 
menu for selecionado. Assim que o modelo é criado, a classe MenuList, que é uma especialização de 
uma List, renderiza os dados representados pelo modelo, realizando dessa forma o papel da camada 
de visão. A grande vantagem é que MenuList pode ser reutilizada em aplicações futuras, uma vez que 
a visão está totalmente desacoplada do modelo. 
A Listagem 3 representa este componente. O método showMenu() de MenuList é o responsável por 
visualizar os dados do modelo. Ele possui um laço interno responsável por recuperar todos os 
MenuElements salvos em children e visualizá-los. Mas primeiro ele chama o método deleteAll(), 
sobrescrito de List, para remover quaisquer itens de menu que estejam sendo exibidos no momento. 
Porém, para que os dados possam ser exibidos assim que a navegação pelos menus terminar, as 
classes obrigatoriamente devem ser um Displayable. 
A Listagem 4 mostra a implementação de SampleMenuAction, que será a classe que visualizará os 
dados retornados. No nosso exemplo, adotamos um caráter mais didático no qual o dado visualizado 
será somente o nome do item de menu que o usuário selecionou. Porém, em uma aplicação móvel 
comercial, os dados poderiam ser resultado de uma pesquisa em um banco de dados armazenado em 
um servidor remoto ou da consulta utilizando um Web Service. A classe SampleMenuAction estende 
TextBox, que é o componente de MIDP que permite entrada de textos longos, ocupando toda a tela 
do dispositivo. Basicamente, ela define seu construtor que chama o construtor de TextBox e são 
passados os parâmetros, respectivamente, representando o título, o texto, a quantidade máxima de 
caracteres e a restrição de entrada de texto, indicando que qualquer texto alfanumérico e com 
caracteres especiais pode ser inserido. Além disso, ela implementa a interface MDisplayable 
(Listagem 5) e o método onDisplay(), que é chamado quando o usuário seleciona a opção de menu 
associada a um MDisplayable. 
A Listagem 6 descreve a MIDlet que utiliza os outros componentes participantes do padrão 
Cascading Menu. Essencialmente, os MenuElements são instanciados e o método addChild() de cada 
objeto é chamado e configurado para poder construir a hierarquia de menus. Por fim, o método 
showMenu() de MenuList é chamado e passado como parâmetro o objeto que representa o menu 
principal (variável main). 
Padrão Wizard Dialog 
Este padrão de projeto tem como objetivo abstrair o desenvolvedor sobre o controle do fluxo de 
navegação entre as telas (que podem ser representados pelo componente Form do perfil MIDP), 
desacoplando as telas entre si e permitindo que nos preocupemos unicamente com a implementação 
do conteúdo de cada tela. Tal abstração pode ser alcançada conjuntamente com outro padrão de 
projeto, o Mediator, que permite que um componente intermediário controle vários outros 
componentes relacionados. 
No diagrama de classes apresentado na Figura 5, o componente WizardEngine (apresentado na 
Listagem 7) realiza o papel do mediador. Ele possui uma referência para um vetor de telas de 
diálogo utilizadas na aplicação (representado pelo Vector dialogs), que pode ser qualquer subclasse 
direta ou indireta de WDialog (Listagem 8). Além disso, a engine do padrão possui os métodos 
addDialog() (um detalhe interessante referente a este método pode ser visto no quadro “Curiosidade 
8/21 
 
no método addDialog()”) e startWizard() que, respectivamente, adiciona os diálogos no vetor e 
retorna o índice da tela de diálogo que está sendo adicionada. 
 Inicialmente, a classe WDialog – que é uma especialização de javax.microedition.lcdui.Form – 
declara várias flags que representam as ações de navegação (NEXT e BACK), a direção do fluxo da 
aplicação: avançando (FORWARD) ou retornando para a tela anterior (BACKWARD); e valores para 
serem retornados de acordo com a validação dos dados, se estes foram aceitos (OK) a próxima tela 
será mostrada, caso contrário (REJECT) a mudança de tela não acontecerá enquanto os dados 
passados não forem válidos. 
Continuando, o método initByEngine() chama o método abstrato initDialog() que é o responsável 
por inicializar todas as telas de diálogos, permitindo configurar os objetos gráficos (como 
Commands, TextFields, ChoiceGroups, etc.) logo na inicialização de uma WDialog (subclasses desta). 
Ele deve ser implementado por todas as subclasses de WDialog (no nosso exemplo, WPage1, 
WPage2, WPage3 e WPage4). Esta classe possui também o método onLeave() – que realiza a 
validação dos dados assim que o fluxo da aplicação estiver entrando em uma tela; e o método 
onEnter() – que, analogamente a onLeave() – também realiza a validação dos dados, porém, quando 
uma tela (representada por subclasses de WDialog) estiver prestes a ser exibida. 
A MIDlet que exemplifica este padrão permite pesquisarmos informações de cidades de acordo 
com algum critério de busca. A aplicação possui quatro telas simples, que são representadas pelos 
componente WPage1 (Listagem 9), WPage2 (Listagem 10), WPage3 (Listagem 11) e WPage4 
(Listagem 12). 
A primeira tela mostra apenas uma informação inicial indicando como o usuário deve prosseguir 
para a execução da MIDlet. A segunda mostra uma lista de cidades disponíveis para escolha 
(representada pelo componente ChoiceGroup). A terceira permite que um termo de busca seja 
informado de acordo com o filtro (a cidade) selecionado anteriormente. Caso este termo não seja 
informado, a engine trata de validar os dados por meio do método sobrescrito onLeave() e exibe uma 
mensagem informando que o campo de pesquisa deve ser preenchido com no mínimo 3 caracteres, 
não permitindo que o fluxo da aplicação mude para outra tela enquanto o campo de busca não for 
preenchido. Caso a validação ocorra com sucesso, a quarta tela será exibida. No nosso exemplo, 
para melhor entendimento, ela apenas irá mostrar o nome da cidade selecionada (Wizardlet.answer1) 
e o valor que foi informado no campo de pesquisa (Wizardlet.answer2). A Listagem 13 mostra a 
MIDlet utilizando os outros componentes do padrão, na qual o método addDialog() é chamado e 
passados como parâmetros os objetos das subclasses de WDialog. Ao término, é chamado o método 
startWizard() para iniciar a exibição das telas da aplicação. 
 
Curiosidade do método addDialog() 
O método addDialog() possui uma característica no mínimo curiosa e que pode levar o leitor a 
pensar que o tratamento de eventos de pressionamento de teclas neste padrão não irá funcionar 
corretamente: se você perceber, WizardEngine possui a definição do método commandAction()de 
javax.microedition.CommandListener porém não implementa esta interface! Em vez disso, ele chama 
o método initByEngine() de WDialog que realmente implementa a interface de captura de comandos. 
Na verdade, WDialog desempenha também o papel de um Proxy para CommandListeners. Isto ocorre 
pois esta classe irá tratar somente eventos de comandos para ir para a próxima (variável 
NEXT_COMMAND) ou tela anterior (variável BACK_COMMAND) são capturados pelo 
CommandListener que ela implementa (representado pela chamada engine.commandAction() ), sendo 
que outros eventos gerados pelo usuário (eventos de confirmação, sair, etc) serão redirecionados 
para outros CommandListeners (representado pela chamada listener.commandAction()). 
 
Pattern: Wizard Dialog 
9/21 
 
 
Figura 5. Arquitetura do padrão Wizard Dialog. 
Objetivo Focar o desenvolvimento da aplicação nos dialogs (que podem ser 
representados por Forms) em vez de se preocupar com a complexidade do 
encadeamento de telas. 
Problema Os dados que são passados entre telas podem ser passados de forma 
inconsistente, sem terem sido validados durante a mudança de telas da 
aplicação. 
Solução A Arquitetura MVC é utilizada para separar o modelo da visão por meio de 
um Controller. 
Participantes WDialog: Classe abstrata que permite executar mecanismos de inicialização 
dos seus componentes gráficos, validar os dados antes de entrar ou depois de 
sair de uma tela (subclasses de WDialog). 
WizardEngine: Responsável pelo gerenciamento do fluxo entre as telas do 
sistema. 
WPage1, WPage2, Wpage3, WPageN: Subclasses de WDialog que representam 
as telas da aplicação. 
Form: Classe de MIDP para representar formulários. 
Conseqüências As telas da aplicação podem ser desenvolvidos de maneira independente, 
facilitando a validação dos dados passados entre telas. 
Implementação Subclasses de WDialog sobrescrevem os métodos onEnter(), onLeave() para 
validação dos dados de acordo com o fluxo da aplicação (entrando ou saindo 
de um Form) e implementam o método initDialog() para permitir a inicialização 
dos componentes gráficos. Depois, WizardEngine é responsável pela exibição 
das telas. 
 
Padrão Pagination 
Devido aos dispositivos móveis possuírem uma tela limitada, a disposição dos objetos de texto é 
reduzida a aproximadamente 10 linhas (dependendo do tamanho da tela do dispositivo), dificultando 
a navegação, visualização e legibilidade do conteúdo. Devido a esta limitação, torna-se necessário o 
uso de métodos que paginem o texto, seja por barra de rolagem ou por menus: avançar e voltar. O 
padrão Pagination visa contornar este problema por meio da utilização do componente PagableList. 
Este padrão permite que uma lista de elementos seja dividida em páginas menores para melhorar a 
visibilidade e navegabilidade dos dados apresentados, sendo utilizado para isso outro padrão de 
projeto, chamado Proxy, que é utilizado quando devem existir várias cópias de um objeto complexo, 
porém às vezes o processo de cópia pode requerer um espaço significativo na memória, o que 
conseqüentemente causa uma perda no desempenho da aplicação. Nessa ocasião, outro objeto 
(proxy) é instanciado em vez de ocorrer diretamente a instanciação do objeto real. Para minimizar o 
carregamento dos dados, o padrão utiliza outro padrão, chamado de Flyweight. Ele é fundamental 
10/21 
 
no padrão Pagination, pois, há muitos objetos (os itens da lista) e estes precisam ser carregados de 
forma a não ocupar muita memória durante este processamento. Sendo assim, este processo deve 
ocorrer por demanda, ou seja, somente quando necessário. Na Figura 6 vemos a arquitetura do 
padrão Pagination. 
Para exemplificar a facilidade na seleção e leitura dos itens na lista, é realizado um comparativo de 
como uma mesma aplicação é executada no emulador sem (Figura 7) ou com (Figura 8) a 
utilização deste padrão. Na Figura 7, percebemos claramente um “inchaço visual” na MIDlet. Caso 
o usuário necessite acessar, por exemplo, o item na posição 45 de uma lista de 50 itens, é preciso 
que o mesmo navegue incessantemente pelos elementos até alcançar o item desejado. Já na Figura 
8, vemos uma MIDlet mais “enxuta”, com menos itens por página, sendo possível avançar na 
paginação, representado pelo comando More, ou recuar, se selecionarmos o comando Prev. 
Na Listagem 14, percebemos que a classe PagableList possui métodos chamados showPrevPage() e 
showNextPage(). Estes métodos são centrais no padrão Pagination, pois acionam respectivamente a 
página anterior e posterior, facilitando sua navegabilidade e proporcionando maior conforto visual ao 
usuário, haja vista que não serão exibidas telas carregadas de textos (mais de 20 itens, por exemplo) 
ou figuras, o que normalmente necessita de uma parte considerável de memória do dispositivo para 
que a lista seja renderizada. Além disso, temos o método utilitário updateList(), que atualiza os itens 
da lista e os métodos sobrescritos da classe List (existem outros métodos de List que foram 
sobrescritos, entretanto, foram omitidos na listagem por questões de espaço), que são append(), 
delete(), insert() que – respectivamente – adiciona cada texto do item e sua imagem (opcional) nos 
vetores que os representam (allStrings e allImages), deleta e insere o texto ou imagem do item da 
lista nos vetores de acordo com sua posição. Na Listagem 15, a MIDlet representando este padrão, 
inicialmente instancia um objeto PagableList. Depois, dentro do método startApp(), o laço adiciona 
um número significativo de itens no objeto (100 itens) PagableList para colocar o padrão Pagination 
em funcionamento. 
 
Pattern: Pagination 
 
Figura 6. Arquitetura do padrão Pagination. 
Objetivo Permitir que uma lista consideravelmente grande de itens seja divida em 
páginas menores. 
Problema Uma lista pode conter um número muito grande de itens que na maioria das 
vezes torna cansativa a navegabilidade. 
Solução Particionar uma lista grande de itens em páginas menores, facilitando a 
visualização dos mesmos e evitar a sobrecarga da memória do dispositivo 
carregando as páginas menores de cada vez, por demanda. 
Participantes PagableList: Representa cada página da lista. 
List: Componente gráfico de MIDP para representação de lista de itens. 
Conseqüências Uma MIDlet com mais listas, porém, cada uma com menos itens sendo 
mostrados por página. Com isso, não ocorre sobrecarga da memória do 
11/21 
 
dispositivo, pois cada página é carregada por demanda. 
Implementação Cada PagableList possui mecanismos para visualização do próximo (método 
showNextPage()) ou da página anterior (método showPrevPage()); e pode, 
opcionalmente, definir o número de itens que devem ser exibidos por página. 
 
 
 
Figura 7. Exemplo de uma aplicação que não utiliza Pagination. 
 
12/21 
 
 
Figura 8. Aplicação usando o padrão Pagination. 
Padrão Slide Show 
Outro problema a ser resolvido refere-se à apresentação de telas (slides) e o tempo entre elas nos 
dispositivos móveis, como uma apresentação em um editor de slides. O padrão Slide Show propõe a 
utilização da classe Displayable (classe mãe dos componentes gráficos) da especificação MIDP para 
solucionar este problema. 
Para a utilização deste padrão, todos os Displayables são criados igualmente apenas mudando seu 
conteúdo (texto, imagem ou algum dado personalizado pelo desenvolvedor). Assim, se atribui a 
responsabilidade da apresentação dos slides e a passagem dos mesmos baseando-se em uma espera 
de tempo pré-definida no componente SlideEngine, deixando com isso o programador livre da 
implementação da mudança de slides e seu tempo, melhorando o desempenho do aplicativo e 
diminuindo a complexidade do código. Alguns exemplos de aplicação deste padrão são os helps de 
games que descrevem passo-a-passo, como um tutorial, como realizar cada funcionalidadedo jogo 
(comandos de navegação, regras de pontuação, etc.). Pela Figura 9, podemos observar a estrutura 
deste padrão. 
Analogamente ao padrão Pagination visto anteriormente, temos os métodos startShow() e 
endShow() na classe SlideEngine (Listagem 16). Tais métodos permitem o início e o término da 
apresentação dos slides, respectivamente. Podemos visualizar também nesta listagem o método 
addSlide(), responsável pela adição dos slides. Ele recebe dois parâmetros: um Displayable, que será 
o componente gráfico a ser exibido e um inteiro, representando o tempo de espera entre o próximo 
slide. Para melhorar o gerenciamento da duração, temos a classe Timer que implementa Runnable 
para representar um contador para o próximo slide. Finalmente, chamando o método startShow() 
iniciamos a exibição dos slides. A Listagem 17 mostra a MIDlet necessária para exemplificar este 
padrão, na qual os slides (objetos da classe Form) vão sendo criados e ao término, adicionados na 
engine por meio do método addSlide() e iniciada a execução por meio do método startShow(). 
 
 
13/21 
 
Pattern: Slide Show 
 
Figura 9. Arquitetura do padrão Slide Show. 
Objetivo Permitir que a transição entre telas da aplicação seja realizada de maneira 
automática de acordo com determinado intervalo de tempo. 
Problema A necessidade de pressionar sempre o comando para ir para a próxima tela 
pode se tornar um tanto quanto tediosa. Em determinados casos, por exemplo, 
em helps da aplicação ou em slides de imagens, é viável definir uma duração 
para a transição entre telas. 
Solução Definir uma duração entre telas para que a transição seja realizada de maneira 
automática. 
Participantes SlideEngine: Responsável por adicionar a duração entre os slides e gerenciar o 
fluxo da aplicação. 
Displayable: Classe de MIDP que representa qualquer elemento gráfico que 
pode ser exibido na tela do dispositivo. 
Screen: Classe mãe dos componentes gráficos que podem ser mostrados na 
tela do dispositivo. 
Canvas: Classe que representa uma tela simples que possui recursos para 
desenho (muito usada para construção de jogos). 
TextBox: Componente em MIDP que permite entrada de textos extensos. 
Form: Classe de MIDP que representa formulários. 
Conseqüências Não é necessário o usuário pressionar nenhum comando para mudar de um 
slide para outro. 
Implementação Subclasses de Screen ou Canvas devem ser criadas e adicionadas por meio do 
método addSlide() de SlideEngine, possibilitando a transição automática das 
telas da aplicação de acordo com o tempo de duração fornecido. 
 
Frameworks em Java ME 
 A utilização massiva de padrões de projetos na plataforma Java ME tem proporcionado o 
desenvolvimento de frameworks (alguns open sources e outros comerciais) que permitem criar 
aplicações móveis mais complexas e robustas. Alguns exemplos são o Floggy (www.floggy.org) – 
projeto “verde e amarelo” – que implementa a idéia de persistência no modelo objeto-relacional e o 
J2ME Polish (www.j2mepolish.org), que além de ser um framework que incrementa vários aspectos 
em Java ME, como novos widgets, serviços de log, serialização de objetos, desenvolvimento de 
GUIs baseadas em CSS (Cascading Style Sheet) e outros, possui integração com IDEs conhecidas, 
como o Eclipse, Netbeans, IntelliJ e permite, por meio de diretivas de pré-processamento, que uma 
única aplicação seja desenvolvida para várias famílias de dispositivos, diminuindo com isso o 
problema da fragmentação. Este framework possui uma versão livre, mais restrita em 
funcionalidades, e outra versão comercial que possui todas as novidades disponíveis no framework. 
14/21 
 
 Percebemos que apesar do desenvolvimento de framework em Java ME ser restrito, devido à 
plataforma ainda não suportar recursos mais complexos como reflexão (também chamado de 
introspecção), várias empresas e pesquisadores vêm criando frameworks que abrangem diversos 
domínios, a exemplo os frameworks Floggy e J2ME Polish citados anteriormente (recomendo o 
leitor a realizar uma pesquisa em sites de hospedagens de projetos Open Source, como 
SourceForge.net, Google Code, etc. para analisar a quantidade significativa de frameworks 
desenvolvidos para Java ME). 
 Nós desenvolvedores esperamos ansiosamente por novas JSRs para as versões da configuração 
CLDC 1.1 e perfil MIDP 2.0 ou um incremento da versão móvel de Java (a tão aguardada MIDP 
3.0) que suporte tais recursos citados anteriormente, o que conseqüentemente iria tornar a 
plataforma uma das mais promissoras para desenvolvimento de aplicações comerciais móveis. 
Conclusões 
Este artigo mostrou a viabilidade de se aplicar padrões de projetos em aplicações móveis para Java 
ME, sendo descritos, por meio de exemplos práticos, quatro padrões: Cascading Menu, Wizard 
Dialog, Pagination e Slide Show, que solucionam problemas comumente enfrentados por nós 
durante a composição de GUIs para dispositivos MIDP. 
A criação de um padrão de projeto, na maioria das vezes, implica na utilização de duas ou mais 
classes abstratas e interfaces. Por isso, caso a aplicação utilize muitos padrões de projeto, a 
conseqüência disso pode ser uma MIDlet “pesada” e lenta, o que acabaria diminuindo o desempenho 
do dispositivo. Entretanto, isso não significa que a utilização de mais de um padrão de projeto se 
torne inviável para as aplicações (por exemplo, a MIDlet Suite com os quatro padrões de projetos 
que foram utilizados neste artigo ficou com um tamanho aproximado de 12 Kb sem utilizar um 
obfuscador). Nesse caso, determinado padrão pode sofrer uma leve adaptação para se comportar 
bem ao ambiente móvel, porém sem perder as suas características. Até o próximo artigo! 
 
 
Ramon Ribeiro Rabello (ramon.rabello@gmail.com) é desenvolvedor Java há 4 anos, tendo experiência nas três 
especificações:JSE, JEE e JME. Já trabalhou em projetos de aplicações móveis e serviços M-Payment. Publicou artigos sobre 
plataformas móveis e atualmente cursa Mestrado pela Universidade Federal de Pernambuco (UFPE) em Engenharia de Software. 
 
 
Pedro J. F. Treccani (pedrotreccani@gmail.com) é desenvolvedor Java há 4 anos, com experiência nas três especificações de 
Java. Já trabalhou no desenvolvimento de projetos integrando aplicações móveis com Sistemas Integrados de Gestão 
Empresarial(SIGE),serviços M-Commerce e E-Commerce. Publicou artigos sobre plataformas móveis, cursando atualmente 
Mestrado como aluno especial pela Universidade Federal de Pará (UFPA) em Engenharia de Software. 
 
15/21 
 
 
Thienne Johnson (thienne@ieee.org) é professora da Unama, com mestrado (UFSCar) e Doutorado (UFPE) em Ciência da 
Computação. Atualmente faz pós-doutorado na Faculdade de Engenharia Elétrica e de Computação na Unicamp. É autora do livro 
“Java para Dispositivos Móveis – Desenvolvendo Aplicações com J2ME”, da editora Novatec. 
 
Links 
javaworld.com/javaworld/jw-12-2002/jw-1213-j2medesign.html 
Sobre os quatro padrões de projetos. 
eclipse.org/ganymede 
Site da IDE Eclipse Ganymede. 
eclipseme.org 
Site do EclipseME. 
http://www.ibm.com/developerworks/library/wi-arch22/ 
O Padrão de Projeto Factory em MIDP 2.0. 
 
Listagem 2. Implementação do componente MenuElement: MenuElement.java 
public class MenuElement implements CommandListener { 
 public Vector children = new Vector(); 
 Hashtable menuMap = new Hashtable(); 
 public String text; 
 
 // construtor e outros métodos utilitários // adiciona um item de menu e liga ao próximo container 
 public void addChild(MenuElement child, MenuElement next_container) { 
 children.addElement(child); 
 menuMap.put(child, next_container); 
 } 
 
 // adiciona um item de menu e liga ao próximo componente gráfico 
 public void addChild(MenuElement child, Displayable display) { 
 children.addElement(child); 
 menuMap.put(child, display); 
 } 
 public void commandAction(Commandcommand, Displayable displayable) { 
 if (command.equals(List.SELECT_COMMAND) && displayable instanceof MenuList){ 
 MenuList list = (MenuList) displayable; 
 int i = list.getSelectedIndex(); 
 MenuElement item = (MenuElement) children.elementAt(i); 
 Object next = menuMap.get(item); 
 
 if (next instanceof MenuElement) 
 list.showMenu((MenuElement) next); 
 else if (next instanceof MDisplayable && next instanceof Displayable) { 
 ((MDisplayable) next).onDisplay(item); 
 list.getDisplay().setCurrent((Displayable) next); 
 } 
 else if (next instanceof Displayable) 
 list.getDisplay().setCurrent((Displayable) next); 
 } 
 } 
} 
 
Listagem 3. Implementação do componente MenuList: MenuList.java 
public class MenuList extends List { 
 Display display = null; 
 
 public void showMenu(MenuElement menu) { 
 deleteAll(); // sobrescreve deleteAll() de List 
 display.setCurrent(this); 
 
 for (int i = 0; i < menu.children.size(); i++) { 
 MenuElement item = (MenuElement) menu.children.elementAt(i); 
 append(item.text, null); 
 } 
16/21 
 
 this.setTitle(menu.text); 
 setCommandListener(menu); 
 } 
} 
 
Listagem 4. TextBox representando os dados retornados pela navegação: SampleMenuAction.java 
public class SampleMenuAction extends TextBox implements MDisplayable { 
 
 public SampleMenuAction() { 
 super("Action", "Conteúdo", 40, TextField.ANY); 
 } 
 
 public void onDisplay(MenuElement e) { 
 this.setString("Você selecionou o item" + e.text); 
 } 
} 
Listagem 5. Implementação do componente MDisplayable: MDisplayable.java 
public interface MDisplayable { 
 public void onDisplay( MenuElement e ); 
} 
 
 
Listagem 6. MIDlet que utiliza o padrão Cascanding Menu: Menulet.java 
public class Menulet extends MIDlet { 
 static Menulet instance; 
 MenuList menulist = null; 
 
 public void startApp() { 
 menulist = new MenuList(Display.getDisplay(this)); 
 MenuElement menu3 = new MenuElement("Lazer"); 
 menu3.addChild(new MenuElement("Museu"), new SampleMenuAction()); 
 menu3.addChild(new MenuElement("Galeria"), new SampleMenuAction()); 
 menu3.addChild(new MenuElement("Espetáculos"), new SampleMenuAction()); 
 
 // a mesma idéia para menu2 e menu1 
 
 MenuElement main = new MenuElement("Menu"); 
 main.addChild(new MenuElement("Lojas"), menu1); 
 main.addChild(new MenuElement("Restaurantes"), menu2); 
 main.addChild(new MenuElement("Lazer"), menu3); 
 
 menulist.showMenu(main); 
 } 
} 
 
Listagem 7. Criando os WDialogs com WizardEngine: WizardEngine.java 
public class WizardEngine { 
 Display display = null; 
 Vector dialogs = new Vector(); 
 
 public int addDialog(WDialog dialog) { 
 dialogs.addElement(dialog); 
 dialog.initByEngine(this); 
 return dialogs.size() - 1; 
 } 
 
 // inicia mostrando o primeiro dialog no Vector 
 public void startWizard() { 
 if (dialogs.size() > 0) { 
 WDialog dialog = (WDialog) dialogs.elementAt(0); 
 display.setCurrent(dialog); 
 } 
 } 
 
 public void commandAction(Command command, Displayable displayable) { 
 WDialog cur_dialog = (WDialog) displayable; 
 
 if (command == WDialog.NEXT_COMMAND) { 
 int i1 = dialogs.indexOf(displayable); 
 if (i1 < dialogs.size() - 1) { 
 WDialog next_dialog = (WDialog) dialogs.elementAt(i1 + 1); 
 if (cur_dialog.onLeave(WDialog.FORWARD) != WDialog.OK) return; 
 if (next_dialog.onEnter(WDialog.FORWARD) != WDialog.OK) return; 
 display.setCurrent(next_dialog); 
 } 
 } 
 else if (command == WDialog.BACK_COMMAND) { 
 int i1 = dialogs.indexOf(displayable); 
 if (i1 > 0) { 
17/21 
 
 WDialog prev_dialog = (WDialog) dialogs.elementAt(i1 - 1); 
 if (cur_dialog.onLeave(WDialog.BACKWARD) != WDialog.OK) return; 
 if (prev_dialog.onEnter(WDialog.BACKWARD) != WDialog.OK) return; 
 display.setCurrent(prev_dialog); 
 } 
 } 
 } 
} 
 
Listagem 8. Representando um WizardDialog em código: WizardDialog.java 
public abstract class WDialog extends Form implements CommandListener { 
 public final static int NEXT = -1; 
 public final static int BACK = -2; 
 // parâmetros para onEnter() e onLeave() 
 public final static int FORWARD = -3; 
 public final static int BACKWARD = -4; 
 // valores de retorno para onEnter() e onLeave() 
 public final static int OK = -5; 
 public final static int REJECT = -6; 
 public final static Command NEXT_COMMAND = new Command("NEXT", Command.OK, 1); 
 public final static Command BACK_COMMAND = new Command("BACK", Command.BACK, 1); 
 // declaração de CommandListener e WizardEngine 
 
 public void initByEngine(WizardEngine e) { 
 initDialog(); 
 
 // Cada wizard dialog deve conter commandos de Next e Back 
 // Uma melhor solução deverá exibir somente um comando de Next 
 // no primeiro dialog e somente um Back na última dialog. 
 // Fica como exercício adicional aos leitores 
 addCommand(NEXT_COMMAND); 
 addCommand(BACK_COMMAND); 
 this.engine = e; 
 super.setCommandListener(this); 
 } 
 
 public int onEnter(int dir) { return OK; } 
 
 public int onLeave(int dir) { return OK; } 
 
 public void commandAction(Command command, Displayable displayable) { 
 if (command == NEXT_COMMAND || command == BACK_COMMAND) 
 engine.commandAction(command, displayable); 
 else if (listener != null) 
 listener.commandAction(command, displayable); 
 } 
 
 public abstract void initDialog(); 
} 
 
Listagem 9. Primeira tela a ser mostrada: WPage1.java 
public class WPage1 extends WDialog { 
 public void initDialog() { 
 setTitle("Passo 1"); 
 append("Introdução: Pressione NEXT em cada página para avançar"); 
 } 
} 
 
Listagem 10. Segunda tela a ser mostrada: WPage2.java 
public class WPage2 extends WDialog { 
 
 public void initDialog() { 
 setTitle("Passo 2"); 
 question1 = new ChoiceGroup("Selecione a cidade que deseja obter informações:", 
 ChoiceGroup.EXCLUSIVE, 
 new String[] { "Belém", "Recife", "Rio", ”São Paulo” }, null); 
 append(question1); 
 } 
 
 public int onLeave(int dir) { 
 if (dir == WDialog.FORWARD) { 
 int idx = question1.getSelectedIndex(); 
 
 if (idx == -1) 
 return WDialog.REJECT; 
 else { 
 String answer = question1.getString(idx); 
 Wizardlet.answer1 = answer; 
 return OK; 
18/21 
 
 } 
 } 
 else return OK; 
 } 
} 
 
Listagem 11. Terceira tela a ser mostrada: WPage3.java 
public class WPage3 extends WDialog { 
 
 public void initDialog() { 
 setTitle("Step 3"); 
 question2 = new TextField("Entre com o termo de busca", null, 40, TextField.ANY); 
 append(question2); 
 } 
 
 public int onLeave(int dir) { 
 if (dir == WDialog.FORWARD) { 
 String answer = question2.getString(); 
 if (answer.length() < 3) { 
 Alert alert = new Alert("Erro de Entrada"); 
 alert.setString("Você deve digitar pelo menos 3 caracteres"); 
 super.engine.getDisplay().setCurrent(alert, this); 
 return WDialog.REJECT; 
 } 
 else { 
 Wizardlet.answer2 = answer; 
 return WDialog.OK; 
 } 
 } 
 else return OK; 
} 
} 
 
Listagem 12. Quarta tela mostrando o resultado: WPage4.java 
public class WPage4 extends WDialog { 
 StringItem text; 
 
 public WPage4() {} 
 
 public void initDialog() { 
 setTitle("Passo 4"); 
 text = new StringItem(null, null); 
 append(text); 
 } 
 
 public int onEnter(int dir) { 
 // retorna os valores da tela anterior e os exibem 
 text.setText("Você selecionou " + Wizardlet.answer1 + " e digitou o valor " 
 + Wizardlet.answer2+ " como critério de busca. Este é o fim deste Wizard demo."); 
 return WDialog.OK; 
 } 
} 
 
Listagem 13. MIDlet que utiliza o padrão Wizard Dialog: Wizardlet.java 
public class Wizardlet extends MIDlet { 
 
 // declaração de variáveis e construtor 
 
 public void startApp() { 
 engine = new WizardEngine(Display.getDisplay(this)); 
 engine.addDialog(new WPage1()); 
 engine.addDialog(new WPage2()); 
 engine.addDialog(new WPage3()); 
 engine.addDialog(new WPage4()); 
 engine.startWizard(); 
 } 
} 
 
Listagem 14. Elementos que podem ser paginados: PagableList.java 
public class PagableList extends List { 
 public final static Object DUMMY = new Object(); 
 public final static Command MORE_COMMAND = 
 new Command("More", Command.SCREEN, 1); 
 public final static Command PREV_COMMAND = 
 new Command("Prev", Command.SCREEN, 1); 
 
 Vector allStrings = new Vector(100); 
 Vector allImages = new Vector(100); 
19/21 
 
 int maxItem = 4; // só um default 
 int curItem = 0; 
 CommandListener listener = null; 
 
 public PagableList(String title, int listType) { 
 super(title, listType); 
 addCommand(MORE_COMMAND); 
 addCommand(PREV_COMMAND); 
 super.setCommandListener(new CommandAction()); 
 } 
 
 public PagableList(String title, int listType, String[] stringElements, 
 Image[] imageElements) 
 { 
 super(title, listType); 
 addCommand(MORE_COMMAND); 
 addCommand(PREV_COMMAND); 
 super.setCommandListener(new CommandAction()); 
 } 
 
 private void updateList() { 
 int s = super.size(); 
 for (int i = 0; i < s; i++) { 
 super.delete(0); 
 } 
 for (int i = curItem; i < curItem + maxItem; i++) { 
 
 // se i exceder o último índice de allStrings, então sai do laço 
 if (!(i < allStrings.size())) 
 break; 
 String a_item = (String) allStrings.elementAt(i); 
 Image img = null; 
 Object obj = allImages.elementAt(i); 
 if (obj == DUMMY) 
 img = null; 
 else img = (Image) obj; 
 super.append(a_item, img); 
 } 
 } 
 
 public void showPrevPage() { 
 int last = allStrings.size() - 1; 
 
 if (curItem - maxItem >= 0) { 
 curItem -= maxItem; 
 updateList(); 
 } 
 } 
 
 public void showNextPage() { 
 int last = allStrings.size() - 1; 
 
 if (curItem + maxItem <= last) { 
 curItem += maxItem; 
 updateList(); 
 } 
 } 
 
 public int append(String stringPart, Image imagePart) { 
 if (stringPart == null) throw new NullPointerException(); 
 if (imagePart != null && imagePart.isMutable()) throw new IllegalArgumentException(); 
 
 allStrings.addElement(stringPart); 
 
 if (imagePart != null) 
 allImages.addElement(imagePart); 
 else allImages.addElement(DUMMY); 
 
 int last = allStrings.size() - 1; 
 if (last < curItem + maxItem) super.append(stringPart, imagePart); 
 
 return last; 
 } 
 
 public void delete(int elementNum) throws IndexOutOfBoundsException { 
 if (elementNum >= allStrings.size()) throw new IndexOutOfBoundsException(); 
 
 allStrings.removeElementAt(elementNum); 
 allImages.removeElementAt(elementNum); 
 
 // if affected element is currently showing, then refresh the list 
 if (elementNum >= curItem && elementNum < curItem + maxItem) updateList(); 
20/21 
 
 } 
 
 public void insert(int elementNum, String stringPart, Image imagePart) { 
 if (elementNum >= allStrings.size()) throw new IndexOutOfBoundsException(); 
 if (stringPart == null) throw new NullPointerException(); 
 if (imagePart != null && imagePart.isMutable()) throw new IllegalArgumentException(); 
 
 allStrings.insertElementAt(stringPart, elementNum); 
 if (imagePart != null) 
 allImages.insertElementAt(imagePart, elementNum); 
 else 
 allImages.insertElementAt(DUMMY, elementNum); 
 if (elementNum >= curItem && elementNum < curItem + maxItem) 
 updateList(); 
 } 
 
 private class CommandAction implements CommandListener { 
 public void commandAction(Command command, Displayable displayable) { 
 if (command == MORE_COMMAND) 
 showNextPage(); 
 else if (command == PREV_COMMAND) 
 showPrevPage(); 
 else if (listener != null) 
 listener.commandAction(command, displayable); 
 } 
 } 
} 
 
Listagem 15. MIDlet que utiliza o padrão Pagination: Paginglet.java 
public class Paginglet extends MIDlet{ 
 static Paginglet instance; 
 PagableList pagablelist = new PagableList( "Paging", List.IMPLICIT); 
 
 public Paginglet() { 
 instance = this; 
 } 
 
 public void startApp() { 
 Display.getDisplay(this).setCurrent(pagablelist); 
 
 for ( int i=0; i< 100; i++ ) 
 pagablelist.append( "Item #"+i, null ); 
 } 
} 
 
Listagem 16. Classe que configura os slides e duração das transições: SlideEngine.java 
public class SlideEngine { 
 Display display; 
 Vector sequence; // Conterá a seqüência de slides 
 Thread thread; 
 Timer timer; 
 
 public SlideEngine(Display d) { 
 display = d; 
 sequence = new Vector(); 
 } 
 
 public void addSlide(Displayable slide, int t) { 
 sequence.addElement(slide); 
 sequence.addElement(new Integer(t)); 
 } 
 
 public void startShow() { 
 timer = new Timer(); 
 thread = new Thread(timer); 
 thread.start(); 
 } 
 
 public void endShow() { 
 timer.done = true; 
 } 
 
 class Timer implements Runnable { 
 int time; 
 boolean done; 
 
 public void run() { 
 done = false; 
 int cur = 0; // índice da seqüência 
 
 while (!done && cur < sequence.size()) { 
21/21 
 
 Object o = sequence.elementAt(cur); 
 System.out.println("sequence: " + o); 
 if (o instanceof Displayable) { 
 Displayable d = (Displayable) o; 
 display.setCurrent(d); 
 } 
 else if (o instanceof Integer) { 
 time = ((Integer) o).intValue(); 
 try { 
 Thread.sleep(time); 
 } 
 catch (Exception e) {} 
 } 
 cur++; // avança para o próximo slide 
 } 
 } 
 } 
} 
 
Listagem 17. MIDlet que utiliza o padrão Slide Show: Slidelet.java 
public class Slidelet extends MIDlet { 
 static Slidelet instance; 
 SlideEngine engine = null; 
 
 public Slidelet() { 
 instance = this; 
 } 
 
 public void startApp() { 
 engine = new SlideEngine(Display.getDisplay(this); 
 Form f1 = new Form("Slide 1"); 
 f1.append("Este é o slide 1"); 
 
 // semelhante para f2 e f3 
 
 // adiciona os slides na engine, 
 // com a duração de 2 segundos de transição 
 engine.addSlide(f1, 2000); 
 engine.addSlide(f2, 2000); 
 engine.addSlide(f3, 2000); 
 
 // inicia a exibição dos slides 
 engine.startShow(); 
 } 
}

Outros materiais