Aplicando Padrões de Projetos em Java ME



Documentos relacionados
Programação para Celular com Java

Orientação a Objetos

Agregador de feeds RSS para dispositivos móveis

Prototype, um Design Patterns de Criação

Tema UFPel 2.0 WP Institucional Guia de Opções de Personalização

Manual do Usuário Android Neocontrol

Diamond Powder - um framework Java ME para coleta de dados

DarkStat para BrazilFW

5 Mecanismo de seleção de componentes

Uma Introdução ao. Computação Móvel (MAC5743/MAC330) Prof. Alfredo Goldman Monitores: Rodrigo Barbosa Daniel Cordeiro

Construtor de sites SoftPixel GUIA RÁPIDO - 1 -

Conteúdo. Disciplina: INF Engenharia de Software. Monalessa Perini Barcellos. Centro Tecnológico. Universidade Federal do Espírito Santo

Programação Orientada a Objetos com PHP & MySQL Sistema Gerenciador de Banco de Dados: Introdução e configuração de bases de dados com Postgre e MySQL

DESENVOLVENDO APLICAÇÃO UTILIZANDO JAVA SERVER FACES

Banco de Dados Microsoft Access: Criar tabelas. Vitor Valerio de Souza Campos

Sistemas Operacionais

2 Diagrama de Caso de Uso

Configurando o DDNS Management System

Banco de Dados Microsoft Access: Criar tabelas

MANUAL DO USUÁRIO SORE Sistema Online de Reservas de Equipamento. Toledo PR. Versão Atualização 26/01/2009 Depto de TI - FASUL Página 1

Aplicativo da Manifestação do Destinatário. Manual

02 - Usando o SiteMaster - Informações importantes

Comm5 Tecnologia Manual de utilização da família MI. Manual de Utilização. Família MI

Apesar de existirem diversas implementações de MVC, em linhas gerais, o fluxo funciona geralmente da seguinte forma:

Novell. Novell Teaming 1.0. novdocx (pt-br) 6 April 2007 EXPLORAR O PORTLET BEM-VINDO DESCUBRA SEU CAMINHO USANDO O NOVELL TEAMING NAVIGATOR

4 O Workflow e a Máquina de Regras

Programação para Internet Orientada a Objetos com PHP & MySQL Instalando e configurando um ambiente de ferramentas PHP e MySQL. Prof. MSc.

Microsoft Office Outlook Web Access ABYARAIMOVEIS.COM.BR

Manual SAGe Versão 1.2 (a partir da versão )

NetEye Guia de Instalação

I N T R O D U Ç Ã O W A P desbloqueio,

Microsoft Office PowerPoint 2007

Tutorial Plone 4. Manutenção de Sites. Universidade Federal de São Carlos Departamento de Sistemas Web Todos os direitos reservados

UNIVERSIDADE FEDERAL DE GOIÁS CERCOMP (CENTRO DE RECURSOS COMPUTACIONAIS) TUTORIAL DE USO DO WEBMAIL - UFG

2 de maio de Remote Scan

SISTEMA TYR DIAGRAMAS DE CLASSE E SEQUÊNCIA Empresa: Academia Universitária

Faculdade de Tecnologia SENAC Goiás. Disciplina: Gerenciamento de Rede de Computadores. Goiânia, 16 de novembro de 2014.

Parte I. Demoiselle Mail

Bem- Vindo ao manual de instruções do ECO Editor de COnteúdo.

Manual das funcionalidades Webmail AASP

Programação Orientada a Objetos com PHP & MySQL Cookies e Sessões. Prof. MSc. Hugo Souza

Follow-Up Acompanhamento Eletrônico de Processos (versão 3.0) Manual do Sistema. 1. Como acessar o sistema Requisitos mínimos e compatibilidade

EDITORA FERREIRA MP/RJ_EXERCÍCIOS 01

Instalação: permite baixar o pacote de instalação do agente de coleta do sistema.

INTRODUÇÃO AO WINDOWS

Documentação. Programa de Evolução Contínua Versão 1.72

ECD1200 Equipamento de Consulta de Dados KIT DE DESENVOLVIMENTO

Manual de Publicaça o no Blog da Aça o TRIBOS nas Trilhas da Cidadania

FERRAMENTAS DE COLABORAÇÃO CORPORATIVA

Smart Laudos 1.9. A Forma Inteligente de Criar seus Laudos Médicos. Manual do Usuário

ANDRÉ APARECIDO DA SILVA APOSTILA BÁSICA SOBRE O POWERPOINT 2007

Manual de Utilização do Sistema GRServer Cam on-line (Gerenciamento de Câmeras On-line)

Status. Barra de Título. Barra de Menu. Barra de. Ferramentas Padrão. Caixa de nomes. Barra de. Ferramentas de Formatação. Indicadores de Coluna

O Windows 7 é um sistema operacional desenvolvido pela Microsoft.

Java ME e suas principais tecnologias de conectividade. Gracieli Begia Mateus

Organização do Curso. Instalação e Configuração. Módulo II. Pós Graduação em Projeto e Gerencia de Redes de Computadores

Curso de Capacitação em Gerenciador de Conteúdo PLONE

Guia de Início Rápido

Android e Bancos de Dados

3 Um Framework Orientado a Aspectos para Monitoramento e Análise de Processos de Negócio

PRODUTO 1 (CONSTRUÇÃO DE PORTAL WEB)

TOTVS Série 1 Varejo (Simples) - Módulo e-commerce

CONSTRUÇÃO DE BLOG COM O BLOGGER

Criando Quiz com BrOffice.impress

Utilizando a ferramenta de criação de aulas

Barra de ferramentas padrão. Barra de formatação. Barra de desenho Painel de Tarefas

MÓDULO 11 ELEMENTOS QUE FAZEM PARTE DO PROJETO DO SISTEMA

Listando itens em ComboBox e gravando os dados no Banco de Dados MySQL.

IMPLEMENTAÇÃO DE SOCKETS E THREADS NO DESENVOLVIMENTO DE SISTEMAS CLIENTE / SERVIDOR: UM ESTUDO EM VB.NET

Capítulo 14. Herança a e Polimorfismo. Rui Rossi dos Santos Programação de Computadores em Java Editora NovaTerra

INTRODUÇÃO E CONFIGURAÇÃO DO PRIMEFACES MOBILE EM APLICAÇÕES JSF

Programação de Computadores - I. Profª Beatriz Profº Israel

Polycom RealPresence Content Sharing Suite Guia rápido do usuário

Manual de Instalação... 2 RECURSOS DESTE RELÓGIO REGISTRANDO O ACESSO Acesso através de cartão de código de barras:...

Despachante Express - Software para o despachante documentalista veicular DESPACHANTE EXPRESS MANUAL DO USUÁRIO VERSÃO 1.1

Google Drive. Passos. Configurando o Google Drive

Guia Site Empresarial

COMO USAR DOIS MONITORES NO WINDOWS 8

Conectar diferentes pesquisas na internet por um menu

ALBUM DE FOTOGRAFIAS NO POWER POINT

Dicas para usar melhor o Word 2007

Google Drive: Acesse e organize seus arquivos

Adapti - Technology Solutions Leonor cardoso nº 331 Fone : (041) Curitiba - PR MANUAL DO USUÁRIO

Manual Captura S_Line

APOSTILA DE EXEMPLO. (Esta é só uma reprodução parcial do conteúdo)

DOCUMENTAÇÃO DO FRAMEWORK - versão 2.0

ArpPrintServer. Sistema de Gerenciamento de Impressão By Netsource Rev: 02

Modelagem e Implementação (Incremental de um Software para Controle) de Aquário de Peixes

QUESTINAMENTOS AO EDITAL DE CONCORRÊNCIA 01/2013

SISTEMA DE GERENCIAMENTO DE PROJETOS - REDMINE MANUAL DE USO

Entendendo como funciona o NAT

Fluxo de trabalho do Capture Pro Software: Indexação de código de barras e separação de documentos

ARRAYS. Um array é um OBJETO que referencia (aponta) mais de um objeto ou armazena mais de um dado primitivo.

COLÉGIO ESTADUAL PAULO LEMINSKI APOSTILA SOBRE O BROFFICE IMPRESS

Sumário 1. SOBRE O NFGoiana DESKTOP Apresentação Informações do sistema Acessando o NFGoiana Desktop

Noções de. Microsoft SQL Server. Microsoft SQL Server

Universidade Federal de Santa Maria UFSM Centro de Tecnologia CT. Power Point. Básico

O Windows 7 é um sistema operacional desenvolvido pela Microsoft.

Transcrição:

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 1/21 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 do GCF, 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 Objetivo Problema Solução Participantes Conseqüências Implementação Figura 3. Arquitetura do padrão Cascading Menu. Permitir criar uma hierarquia complexa de menus, de forma a abstrair o encadeamento entre telas. 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. A Arquitetura MVC para desacoplar a parte do Modelo da Visão por meio de um Controlador. 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. Uma hierarquia de menus mais complexa, porém, novas adições de menus à estrutura acontecem de modo mais simples. 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. Menu Principal Lojas Restaurantes Lazer Lojas Automóveis Livros Moda Restaurantes Padarias Cafés Refeições Lazer Museus Galerias Espetáculos Figura 4. Hierarquia de menus no padrão Cascading Menu. O componente MenuElement 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

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 Objetivo Problema Solução Participantes Conseqüências Implementação Figura 5. Arquitetura do padrão Wizard Dialog. 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. 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. A Arquitetura MVC é utilizada para separar o modelo da visão por meio de um Controller. 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. As telas da aplicação podem ser desenvolvidos de maneira independente, facilitando a validação dos dados passados entre telas. 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 Objetivo Problema Solução Participantes Conseqüências Figura 6. Arquitetura do padrão Pagination. Permitir que uma lista consideravelmente grande de itens seja divida em páginas menores. Uma lista pode conter um número muito grande de itens que na maioria das vezes torna cansativa a navegabilidade. 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. PagableList: Representa cada página da lista. List: Componente gráfico de MIDP para representação de lista de itens. 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 Implementação dispositivo, pois cada página é carregada por demanda. 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 funcionalidade do 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 Objetivo Problema Solução Participantes Conseqüências Implementação Figura 9. Arquitetura do padrão Slide Show. Permitir que a transição entre telas da aplicação seja realizada de maneira automática de acordo com determinado intervalo de tempo. 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. Definir uma duração entre telas para que a transição seja realizada de maneira automática. 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. Não é necessário o usuário pressionar nenhum comando para mudar de um slide para outro. 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(command command, 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();