1_o que é j2me

26
O que é J2ME? A plataforma Java 2 Micro Edition (J2ME) implementa a linguagem Java para vários dispositivos tais como telefones celulares, PDAs, Internet screenphones, settop boxes digitais para TV, sistemas de navegação automotiva, comutadores e roteadores de rede, componentes para automação residencial, etc. A plataforma J2ME consiste de máquinas virtuais (KVM), APIs especificadas em "documentos de configuração" ("Configuration" – CDC e CLDC) em conjunto com perfis ("Profiles" - MIDP) para uma determinada aplicação ou mercado. Tudo está disposto em camadas de software como segue no diagrama abaixo: Figura 1 Camadas de software do J2ME O desenvolvimento de Configurações e Perfis se dá de acordo com processos estabelecidos pela “Comunidade Java”. Nesse processo, similar aos do IETF, podem participar o setor privado, público, “neutro”, ou mesmo indivíduos. Há votações para a aprovação de uma determinada especificação que só se torna pública uma vez que aprovada pela maioria. Maiores detalhes podem ser obtidos no site da SUN: http://java.sun.com/products/cldc http://java.sun.com/products/midp A versão suportada na maioria dos dispositivos celulares no Brasil é a CLDC 1.1 e o MIDP 2.0. O CLDC (Connected Limited Device Configuration) contem uma API mínima para poder rodar aplicativos em dispositivos móveis com limites de processamento e memória, tais como, telefones celulares, smartphones, pagers e PDAs. Em oposição temos a CDC (Connected Device Configuration) que supõe dispositivos com mais capacidade tais como settop boxes digitais, screen-phones, Nokia Communicator e alguns PDAs mais poderosos. No que diz respeito ao CLDC para aparelhos celulares, temos as seguintes características:

Upload: raphaelramos

Post on 02-Jul-2015

230 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: 1_O que é J2ME

O que é J2ME?A plataforma Java 2 Micro Edition (J2ME) implementa a linguagem Java para vários

dispositivos tais como telefones celulares, PDAs, Internet screenphones, settop boxes digitais para TV, sistemas de navegação automotiva, comutadores e roteadores de rede, componentes para automação residencial, etc.

A plataforma J2ME consiste de máquinas virtuais (KVM), APIs especificadas em "documentos de configuração" ("Configuration" – CDC e CLDC) em conjunto com perfis ("Profiles" - MIDP) para uma determinada aplicação ou mercado. Tudo está disposto em camadas de software como segue no diagrama abaixo:

Figura 1 Camadas de software do J2ME

O desenvolvimento de Configurações e Perfis se dá de acordo com processos estabelecidos pela “Comunidade Java”. Nesse processo, similar aos do IETF, podem participar o setor privado, público, “neutro”, ou mesmo indivíduos. Há votações para a aprovação de uma determinada especificação que só se torna pública uma vez que aprovada pela maioria.

Maiores detalhes podem ser obtidos no site da SUN:• http://java.sun.com/products/cldc

http://java.sun.com/products/midp

A versão suportada na maioria dos dispositivos celulares no Brasil é a CLDC 1.1 e o MIDP 2.0.

O CLDC (Connected Limited Device Configuration) contem uma API mínima para poder rodar aplicativos em dispositivos móveis com limites de processamento e memória, tais como, telefones celulares, smartphones, pagers e PDAs.

Em oposição temos a CDC (Connected Device Configuration) que supõe dispositivos com mais capacidade tais como settop boxes digitais, screen-phones, Nokia Communicator e alguns PDAs mais poderosos.

No que diz respeito ao CLDC para aparelhos celulares, temos as seguintes características:

Page 2: 1_O que é J2ME

· Hardware requerido: mínimo de 160KB de memória para Java, um processador de no mínimo 16 bits com baixo consumo (adequado a baterias típicas de um celular) e conexão de rede (neste caso wireless – 9.6Kbps, 144Kbps ou 2Mbps).

· Software que inclua suporte a um subconjunto da linguagem Java e a um subconjunto da máquina virtual Java que definam um núcleo de funções que permitam o desenvolvimento de aplicações móveis.

A segurança, que a CLDC define, está baseada no chamado “Sandbox Security Model”, isto é, a máquina virtual terá um espaço de memória independente do restante das aplicações do celular (tais como agenda, tons, imagens, configuração, browser WAP, etc).

Nesse modelo de segurança restringe-se as operações que podem ser executadas a um conjunto de funções da API tão somente. Nenhuma outra operação é permitida. Com isso a aplicação não pode acessar a área de memória do calendário ou agenda de contatos do aparelho celular. Outro ponto importante no que tange ao Java é o fato que não é permitido carga de classes definidas pelo usuário de forma a garantir a segurança de qualquer aplicação desenvolvida com a API CLDC.

Essa é uma diferença significativa em relação ao BREW que não define limites à aplicações que por sua vez podem acessar áreas de memória de qualquer parte do celular, compartilhar dados com outros aplicativos, alterar áreas de código também. O fato do C/C++ permitir acesso via apontadores a memória, o que o Java não permite, ajuda o BREW a ser mais flexível, porém exige que o programador saiba o que está fazendo.

Por esse motivo o custo de desenvolvimento no BREW é mais alto, pois toda aplicação tem que ser testada e certificada pela Qualcomm para garantir que não se introduza na rede aplicações “mal intencionadas ou simplesmente mal feitas” e com isso ponha-se em risco toda a c redibilidade da plataforma BREW.

O J2ME corta esse risco pela raiz, o que o faz ser mais limitado, porém seguro e com custos de desenvolvimento menores. Em cada plataforma há suas vantagens e seus “trade-offs”. No topo da camada de CLDC temos a camada de software chamada Profile. O Profile, ou Perfil, especifica um conjunto de APIs que moldam-se a um determinado tipo de dispositivo.

A diferença entre Configuração e Perfil é que a Configuração descreve de forma geral uma família de dispositivos, enquanto o Perfil fica mais específico para um tipo particular de aparelho em uma dada família.

O Perfil tão somente acrescenta funcionalidades àquele particular aparelho. O Perfil MIDP contem, por exemplo, APIs para aparelhos celulares enquanto o CLDC aborda APIs para dispositivos móveis de pouca capacidade de processamento, dentre os quais temos celulares, pagers etc.

O CLDC define em sua API os pacotes java.io, java.lang, java.util e javax.microedition.io (conexão e interfaces). Notem que não há suporte a ponto flutuante, suporte completo à classe Error do J2SE, a referências fracas, verificação de arquivos de classes (há no lugar uma ferramenta de “pré-verificação”), finalização - Object.finalize(), JNI (Java Native Interface), reflection, thread groups/ daemons e user-defined class loaders.

O MIDP define tudo o que há no CLDC com a adição aos pacotes javax.microedition.lcdui (interface com o usuário), javax.microedition.rms (sistema de gerência de registros para persistência de informa ções), javax.microedition.midlet (suporte para aplicações MIDP, os chamados midlet s).

Page 3: 1_O que é J2ME

Vários fabricantes adicionam ao MIDP algumas outras APIs, tais como suporte a uma forma simplificada de AWT (Abstract Window Toolkit) e controles de vibração, som e display. Cada fabricante adiciona livremente o que considerar importante. Isso torna difícil muitas vezes portar aplicações entre fabricantes, a menos que se use sempre o conjunto mínimo especificado no MIDP 1.0.

Com o MIDP 2.0, haverá um conjunto mínimo que incluirá controles de vibração, som e display entre outras capacidades. Dessa forma haverá mais portabilidade entre os vários modelos e fabricantes.

De onde baixar ferramentas de desenvolvimento?No site da SUN Microsystems podem ser encontradas ferramentas que permitem

gerar os arquivos necessários para rodar aplicações em aparelhos compatíveis com o J2ME. Entre as ferramentas há um gerenciador de projetos bem simples e um emulador genérico de terminais com MIDP, tudo faz parte do J2ME Tool Kit.

Nesse Tool Kit não há um IDE (Integrated Development Environment), portanto poderá ser necessário editar o código fonte em ferramentas próprias, compilar, pré-verificar e empacotar usando as ferramentas do Kit para , em seguida, emular o resultado e depurar o código. É um ciclo comum em ambientes como UNIX, usando-se por exemplo Makefile.

Porém, para facilitar as coisas, a SUN disponibilizou um IDE livre chamado Forte for Java ou SUN One Studio, nome que atualmente é usado. Existem outras opções tais como o NetBeans IDE ou a versão comercial do JBuilder da Borland.

Para instalar um ambiente de desenvolvimento para J2ME, o primeiro passo é baixar e instalar o J2SE SDK e JRE da SUN. Sem os quais não é possível se fazer nada.É necessário ter o sistema operacional Windows NT ou 2000. Existem versões para Linux e Solaris, caso se prefira ambiente UNIX.

Caso o objetivo seja apenas poder rodar aplicações de demonstração, é necessário apenas o J2SE JRE (Java Runtime Environment).

Se o objetivo é desenvolver aplicações são necessários ambos o J2SE JRE e SDK (Software Development Kit).

Para obter o Java2 SDK, Standard Edition (J2SE SDK) e/ou o Java 2, Standard Edition Runtime Environment (J2SE JRE) na versão mínima - 1.3 (atualmente está disponível a versão 1.4.1) vá para: http://java.sun.com/j2se/1.4.1/download.htmlEscolha o sistema operacional, língua, etc.

Após baixar o JRE e/ou SDK, instale cada qual, preferencialmente o JRE primeiro.Em seguida baixe o J2ME Wireless Toolkit versão 1.0.4 _01 pelo link abaixo:

http://java.sun.com/products/j2mewtoolkit/download.html Instale o J2ME toolkit.Com isso já será possível criar aplicações J2ME e testá-las no simulador que está

incluído nas ferramentas. Caso esteja usando Windows NT ou 2000, as ferramentas estarão disponíveis na barra

de ferramentas no botão “Start” ou “Início”.Aos que não gostam de usar Makefiles ou .bats em conjunto com NotePads para

editar ou Edit do “MS DOS Prompt”, existe a opção de se baixar um JDE (Java IDE) da própria SUN, o SUN One Studio 4 update 1, Mobile Edition no link abaixo:http://wwws.sun.com/software/sundev/jde/buy/index.html

Apesar de ter uma referência a “buy” na URL acima, na verdade é possível baixar o IDE gratuitamente.

Page 4: 1_O que é J2ME

Note que a parte que trata sobre o SUN One Studio Mobile Edition está bem ao final da página na WEB.

Baixe o arquivo e instale-o.Com isso temos um conjunto de ferramentas sem custo algum que permite que se

desenvolva e teste aplicativos que poderão ser executados em qualquer aparelho com suporte a J2ME.

Java 2, Micro Edição (J2ME) dá aos desenvolvedores Java a oportunidade de aproveitar suas habilidades em programação numa grande variedade de dispositivos móveis, como telefones celulares, PDAs, etc.. Sem sombra de dúvida, dispositivos móveis são diversos em suas capacidades e poder de processamento. J2ME cria uma camada de abstração, minimizando estas diferenças ao definir configurações e interfaces, as quais, juntas, provêem uma plataforma completa e uma Interface para Programação de Aplicativos (API). Estas APIs possibilitam o desenvolvimento de aplicativos em qualquer dispositivo que possua suporte a estas.

A Configuração Limitada de Dispositivos Conectados (Connected Limited Device Configuration - CLDC) e o Perfil de Informações para Dispositivos Móveis (Mobile Information Device Profile - MIDP) combinados estão presentes na maioria de dispositivos móveis de baixo custo, como PDAs, telefones celulares e pagers two-way. Neste artigo, você terá a possibilidade de começar a aprender J2ME ao construir um pequeno aplicativo de teste.

Hello World!O processo de fazer uma build, instalar, e rodar um aplicativo MIDP é bem diferente

daquele utilizado normalmente em aplicativos Java. Isto é um tópico diferente, que virá num artigo futuro. Por enquanto, você terá de se contentar em examinar a estrutura de nosso aplicativo teste. Logo abaixo encontra-se o código para um aplicativo "Hello World" e logo abaixo a figura mostrando o resultado.

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class HelloJ2ME extends MIDlet implements CommandListener{ private Display display; private TextField caixaDeTextoHello; private Command comandoDeSaida; private Form formularioPrincipal; public HelloJ2ME() { // Armazenar ponteiro para o objeto “Display”, passando a // instância deste aplicativo display = Display.getDisplay(this); //Criar o formulário principal (janela) formularioPrincipal = new Form("HelloJ2ME"); //Criar o botão de comadno de saída do aplicativo comandoDeSaida = new Command("Exit", Command.SCREEN,1); //Create a single-line text field 15 characters long //with the label "Text" caixaDeTextoHello = new TextField("Text","Hello World!",15,TextField.ANY);

Page 5: 1_O que é J2ME

//Adicionar os comandos do nosso aplicativo e //o nosso método que tratará dos comandos // Adicionar o comando de saída à nossa janela formularioPrincipal.addCommand(comandoDeSaida); // Adicionar a caixa de texto contendo o texto “Hello World” // à nossa janela formularioPrincipal.append(caixaDeTextoHello); // Registrar o método que tratará os comandos // com o sistema formularioPrincipal.setCommandListener(this); } public void startApp() { // Setar meu formulário principal como // o objeto ativo. Em outras palavras: nossa // janela é a que aparece na tela! display.setCurrent(formularioPrincipal); } // Método que trata o comando de pausa vindo do sistema public void pauseApp() { /*aplicativo está sendo pausado*/ } // Método que destroi o nosso aplicativo // O sistema chama este método quando precisa public void destroyApp(boolean incondicional) { /*nosso aplicativo está terminando aqui*/ } public void commandAction(Command comando, Displayable s) { // Alguém clicou na janela // Vamos checar se clicaram no comando de saída if (comando == comandoDeSaida) { // Clicaram no comando de saída! // Temos de terminar nosso aplicativo manualmente // chamando o método “destroyApp”, passando argumento // booleano “falso” destroyApp(false); // Agora temos de notificar o gerente que nosso aplicativo // foi terminado notifyDestroyed(); } }}O resultado:

Page 6: 1_O que é J2ME

Com certeza, não é de impressionar, eu sei, mas bons exemplos raramente são. Como você pode ver, nosso exemplo J2ME estende ao aplicativo a classe base MIDP através da classe MIDlet e importa dois namespaces: javax.microedition.midlet e javax.microedition.lcdui. Um inclui a classe base MIDIlet para o nosso aplicativo, enquanto o outro provê a interface gráfica (Graphical User Interface - GUI), respectivamente.

A classe MIDlet provê três métodos abstratos que são usados pela aplicação. Estes métodos são chamados à partir do gerenciador de aplicações do dispositivo, e é usado para comunicar com os aplicativos que estão rodando. O método "startApp" é chamado imediatamente depois do construtor e cada vez que um aplicativo é ativado (está visível). Isto implica que este método não é chamado somente ao aplicativo ser iniciado. Uma aplicação pode fazer a transição entre os estados de ativa e inativa muitas vezes durante o tempo em que está sendo rodada, portanto você deve evitar colocar código de inicialização que só pode ser rodado uma única vez. Um bom exemplo é o código utilizado para inicializar a GUI, que deve ser colocado no construtor ao invés desse método.

O método "destroyApp" é chamado pelo gerencaidor de aplicativos para indicar que uma aplicação está prestes à ser terminada. Não como o método "startApp", este método será chamado uma única vez durante o tempo de execução de uma aplicativo, portanto é recomendado o uso de "código de limpeza" aqui. De fato, por causa do fato da MIDP não incluir em sua funcionalidade a capacidade de finalizar seus objetos, você terá de terá de fazer "a limpeza" aqui mesmo. Ao mesmo tempo, entretanto, um dispositivo móvel típico é bem menos estável que uma plataforma típica de desenvolvimento e será constantemente desligado e/ou reinicializado pelo usuário. Portanto, você não pode contar com a execução de "destroyApp" toda as vezes.

O método abstrato remanescente, "pauseApp", pode ser considerado um tanto quanto esquisito quando analisado pela primeira vez. Este método é utilizado para notificar o aplicativo que está rodando está para ser pausado porque o usuário acabou de começar a rodar um outro aplicativo ou está utilizando uma função do dispositivo que prevenirá seu aplicativo de continuar rodando. Por causa do fato da maioria dos dispositivos móveis não terem poder de processamento para estarem realmente "multitasking"(executando várias funções ao mesmo tempo), este método provavelmente será chamado com uma certa freqüência. Você também deve manter em mente que os recursos sendo utilizados pelo seu aplicativo devem ser liberados neste momento. Quando a sua aplicação volta à rodar, o método "startApp" será chamado pelo gerenciador de aplicativos.

Comunicando com o gerenciador de aplicações (application manager)Claramente, toda comunicação tem que acontecer em ambas direções, ou seja, ir e vir,

para ser eficiente. Aplicações MIDP não são exceção nenhuma. O MIDlet provê um conjunto de métodos que você pode usar para comunicar-se com o gerenciador de aplicações:

Page 7: 1_O que é J2ME

· NotifyDestroyed fala ao gerenciador que a sua aplicação quer ser terminada. Ao chamar este método, o resultado não será ter o método "destroyApp" ser executado, portanto você terá de chamá-lo manualmente.

. NotifyPaused notifica o gerenciador que a sua aplicação quer ser pausada.· ResumeRequest solicita que o gerenciador volte a rodar a sua aplicação, se este

estiver pausada. · GetAppProperty busca as informações de configuração de uma aplicação. Tal

informação pode ser acessada através do fornecimento de um manifesto ou um arquivo de descrição de um aplicativo (application descriptor file). Em outras palavras, este método dá acesso a um arquivo de inicialização privada.

Gerenciando a interfaceO pacote javax.microedition.lcdui contém os elementos de interface gráfica utilizados

por aplicativos MIDP.Conheça a famíliaHá basicamente três famílias de componentes GUI definidos no pacote "lcdui", que

são agrupados baseados em suas classes base: Componentes de tela; Componentes de item; e Componentes diversos de display.

Componentes de telaOs componentes de tela são descendentes da classe abstrata "Screen" e provêem os

widgets de interface gráfica em forma de janela. O objeto "Form" (formulário) usado no exemplo "HelloJ2ME" é um descendente da classe "Screen", que contém e forma controles de interface gráfica. Outros componentes de "Screen" incluem alertas (Alert), caixas de diálogo (dialog box), listas (List) e caixas de texto (TextBox), sendo esta última uma forma de entrada de texto que suporta múltiplas linhas.

Componentes de item Os componentes de item são controles tradicionais, como o campo de texto "Hello

World!" na nossa aplicação exemplo. Estes controles todos são descendentes da classe "Item". Esta classe provê uma API uniforme para colocar-se etiquetas de nome, tratamento de eventos, e exibição de controles. ChoiceGroup, DateField, Gauge, ImageItem e StringItem são outros componentes da classe Item.

Componentes diversos de display Todos os componentes diversos de display são, na sua grande maioria, descendentes

da classe de hierarquia mais alta e abstrata "Displayable". Este grupo inclui componentes como a classe "Command", que integra os botões de comando; "Ticker", que integra as caixas de texto rolantes; "Graphics", que exibe os gráficos; e "Choice", que é uma interface de manipulação de seleções pré-definidas, que, por sua vez, não se encaixam em qualquer outra categoria.

Esta figura ilustra a hierarquia destes componentes.

Page 8: 1_O que é J2ME

Os membros do pacote "lcdui"Toda a parafernália gráfica é gerenciada por um objeto "Display", à partir do qual,

cada aplicação tem acesso à uma única e privada instancia. Esta instancia pode ser obtida através do método estático "Display.getDisplay". É de costume manter uma única referência à esta instância em uma variável, da mesma maneira que é feita no construtor do nosso exemplo "HelloJ2ME". Além dos métodos para concentrar o foco da tela em um elemento em particular (setCurrent) e descobrir qual o elemento com o foco (getCurrent), a classe "Display " também expõe vários outros métodos muito úteis para obtenção de informação sobre as capacidades do display do dispositivo. Entre estas capacidades estão a detecção de suporte à cores (isColor) e quantas cores são suportadas (numColors).

Coisas para lembrar-se Vamos terminar este tutorial com uma curta lista de coisas para manter em mente ao

desenvolver aplicações em Java para uma plataforma móvel. Primeiro, você terá que lidar com uma biblioteca de classes bem limitada: sem refletir, JNI, ou, como mencionado antes, suporte à finalizações. Segundo, você terá que lidar com altíssimas restrições quanto ao uso de memória, já que a maioria dos dispositivos rodando MIDP terá menos de 100K de memória dinâmica disponíveis. Como resultado, você terá de ser bem cuidadoso com a memória utilizada pelos algoritmos que costuma usar. Finalmente, tenha em mente que qualquer conectividade com redes será limitada em largura de banda e, provavelmente, esporádica.

IntroduçãoComo pudemos aprender nos tutoriais anteriores, os dispositivos celulares podem

implementar em seu sistema o KVM, a máquina virtual que roda aplicações J2ME. A API de programação para aparelhos celulares está baseada em CLDC e MIDP. Para maiores detalhes veja o tutorial - parte 1

(http://geocities.yahoo.com.br/brasilwireless/tutorial_j2me/j2me_01/j2me_01.html)Também pudemos ver um exemplo de aplicação em J2ME que escreve na tela do celular a frase "Hello World!", conforme a figura abaixo:

Page 9: 1_O que é J2ME

O exemplo da aplicação "Hello World!" e as estruturas de programação utilizadas

podem ser encontrados no tutorial - parte 2 http://geocities.yahoo.com.br/brasilwireless/tutorial_j2me/j2me_02/j2me_02.html).

Neste capítulo 3 do tutorial vamos abordar como compilar e testar a aplicação "Hello World!" utilizando o Wireless ToolKit que a Sun Microsystems disponibiliza em seu site (para maiores detalhes de como obter as ferramentas, veja o tutorial - parte 1).

Suponhamos que o Toolkit foi instalado no diretório "C:\J2MEwtk". Dentro desse diretório teremos a seguinte estrutura de arquivos e diretórios referente ao próprio Toolkit:

· Arquivo: BinaryLicense.html contem o contrato da licença de uso do Toolkit. · Arquivo: BinaryReleaseNotes.html contem notas sobre a versão instalada do

Toolkit.· Arquivo: index.html página HTML que aponta para a documentação do Toolkit. · Diretório appdb\ contem arquivos de dados tais como informações RMS de cada

Midlet. · Diretório apps\ contem as aplicações demonstração e novas aplicações/projeto que

são criados adicionalmente no KToolbar. É aqui que será criada a estrutura para nossa aplicação "Hello World!".

· Diretório bin\ contem arquivos Batch e outros executáveis usados pelo Toolkit. · Diretório docs\ contem documentação e guias de uso do Toolkit e das APIs do

J2ME.· Arquivo lib\midpapi.zip contem as classes com as APIs CLDC e MIDP. Esses

arquivos são usados durante compilação dos arquivos fonte (*.java) e na pré-verificação do byte-code das classes geradas por esse fontes (*.class).

· Diretório sessions\ contem dados de monitoração da execução das aplicações no simulador. Com esses dados é possível monitorar o uso da memória, rede e outros durante a execução de um Midlet.

Para uso neste tutorial é necessário que o código a seguir seja copiado para um arquivo texto sem formatação (do tipo gerado com NotePad) e salvo com o nome "HelloJ2ME.java". Note que a linguagem JAVA faz distinção entre minúsculas e maiúsculas e portanto deve-se tomar especial atenção ao nome do arquivo que tem que ser obrigatoriamente igual ao nome da classe que nele é definida.

O código do programa que será utilizado em este tutorial segue abaixo:

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

public class HelloJ2ME extends MIDlet implements CommandListener

Page 10: 1_O que é J2ME

{ private Display display; private TextField t; private Command comandoDeSaida; private Form formularioPrincipal;

public HelloJ2ME() { display = Display.getDisplay(this); formularioPrincipal = new Form("HelloJ2ME"); comandoDeSaida = new Command("Exit", Command.SCREEN,1); t = new TextField("Text","Hello World!",15,TextField.ANY); formularioPrincipal.addCommand(comandoDeSaida); formularioPrincipal.append(t); formularioPrincipal.setCommandListener(this); }

public void startApp() { display.setCurrent(formularioPrincipal); }

public void pauseApp() { }

public void destroyApp(boolean incondicional) { }

public void commandAction(Command comando, Displayable s) { if (comando == comandoDeSaida) { destroyApp(false); notifyDestroyed(); } }}

Como usar o Wireless Toolkit?

Uma vez instalado conforme as instruções descritas no site da SUN, podemos iniciar o desenvolvimento de aplicações baseadas em J2ME. No nosso tutorial vamos demonstrar o uso do Wireless Toolkit através do programa "Hello World!".

O primeiro passo é iniciar o KToolbar que é onde criaremos um projeto. A figura abaixo ilustra onde pode ser localizada a aplicação em ambientes Windows.

Page 11: 1_O que é J2ME

Uma vez iniciado o aplicativo KToolbar, o mesmo se apresentará como a seguir.

Após iniciar o KToobar devemos abrir um novo projeto. Na tela da aplicação KToolbar existe o botão "New Project …". Aperte esse botão para que seja aberto um formulário que solicitará que seja dado um nome de projeto (qualquer) e o nome da classe MIDlet que rodará o programa J2ME. No nosso exemplo, o nome do projeto é "Hello World!" e conforme descrito no código fonte do programa, a classe é chamada "HelloJ2ME".

Ao apertar o botão "Create Project" o sistema automaticamente criará uma estrutura

de diretórios referentes ao projeto dentro do diretório de instalação do J2ME Wireless Toolkit. Essa estrutura estará abaixo do diretório "Apps\<Nome do Projeto>" que fica dentro da estrutura de diretórios do Toolkit (por exemplo "C:\J2MEwtk\Apps\Hello World!\"). Nela temos os seguintes diretórios:

· \Src - nele colocaremos o código fonte de nossa aplicação, ou seja, o arquivo "HelloJ2ME.java".

· \Bin - nele o Toolkit criará os arquivos .JAR e .JAD que são necessários para poder executar a aplicação em um celular ou mesmo no simulador.

Page 12: 1_O que é J2ME

· \Res - nele são colocados todos os arquivos adicionais que são necessários para que a aplicação seja executada. Um exemplo típico é uma imagem no formato PNG com o ícone da aplicação. Todos os arquivos que forem colocados nesse diretório serão empacotados dentro do .JAR e serão acessíveis pela aplicação J2ME. No nosso exemplo não colocaremos nada lá.

Ao pressionar o botão "Create Project", o KToolbar criará os diretórios acima descritos e também o próprio diretório do projeto "Hello World!". Porém antes o Toolkit pedirá para que sejam confirmadas as informações do descritivo do Projeto/aplicação. Essas informações ou atributos serão o conteúdo do arquivo .JAD (Java Descriptor) a ser criado. No nosso caso não nos preocuparemos com esses dados e simplesmente apertaremos o botão "OK". O resultado aparece a seguir.

Após apertar o "OK", o Toolkit indicará no seu console que os diretórios do projeto

foram criados conforme a figura abaixo.

Nesse momento o Toolkit nos sugere que os arquivos fonte sejam colocados no

diretório "…\apps\Hello World!\src\". Nesse momento devemos copiar o arquivo "HelloJ2ME.java" para esse diretório.

A partir de agora estamos prontos para construir a aplicação!

Page 13: 1_O que é J2ME

Basta apenas apertar o botão "Build" no KToolbar que o Toolkit compilará os arquivos fonte e criará os arquivos .class que serão usados para rodar o simulador. Abaixo segue a ilustração da construção do aplicativo "Hello World!".

Basta apenas apertar o botão "Build" no KToolbar que o Toolkit compilará os arquivos fonte e criará os arquivos .class que serão usados para rodar o simulador. Abaixo segue a ilustração da construção do aplicativo "Hello World!".

Caso não ocorra nenhum problema de compilação teremos a mensagem "Build Complete", ao final das mensagens, indicando que está tudo pronto para executar a aplicação "Hello World!" no simulador. Caso ocorram erros de compilação os mesmos serão apresentados no console do Toolkit.

No nosso caso, o programa está depurado e o código fonte está correto. Portanto não há nenhum problema de compilação. Neste caso estamos prontos para executar a aplicação. Para isso basta apertar o botão "Run" no KToolbar. Ao fazer isso será aberta uma nova janela com o simulador escolhido. No nosso exemplo é o simulador genérico colorido, conforme a figura abaixo.

Page 14: 1_O que é J2ME

A figura acima mostra o estágio inicial do simulador que permite que seja escolhido

qual Midlet executar. Nosso caso só há um Midlet especificado no arquivo .JAD, portanto temos apenas que pressionar o SoftKey para lançar a aplicação "Hello World!" (botão em destaque logo abaixo da palavra "Launch"). O resultado da execução do "Hello World!" segue abaixo.

Uma vez que a aplicação tenha executado a contento no simulador, é possível criar o arquivo .JAR (Java Archive) que é, na verdade, um arquivo compactado no formato PkZip

Page 15: 1_O que é J2ME

com todas as classes e arquivos do diretório "…\res" (resources).Para criar-se o .JAR basta selecionar "Project à Package" no menu do KToolbar. Esse arquivo somente é necessário para executar o programa no próprio aparelho celular. Com este tutorial, o estudante será capaz de compilar e simular seus programas desenvolvidos com a linguagem J2ME para aparelhos celulares. No próximo e último capítulo do tutorial, apresentarei uma versão mais sofisticada do programa "Hello World!", onde mostrarei como fazer animações simples usando caracteres de texto, o que pode ser melhorado, futuramente pelo próprio estudante, para fazer animações com imagens.Até lá!

IntroduçãoComo pudemos aprender nos tutoriais anteriores, os dispositivos celulares podem

implementar em seu sistema o KVM, a máquina virtual que roda aplicações J2ME. A API de programação para aparelhos celulares está baseada em CLDC e MIDP. Para maiores detalhes veja o tutorial - parte 1

(http://geocities.yahoo.com.br/brasilwireless/tutorial_j2me/j2me_01/j2me_01.html) Também pudemos ver um exemplo de aplicação em J2ME que escreve na tela do

celular a frase "Hello World!". O exemplo da aplicação "Hello World!" e as estruturas de programação utilizadas

podem ser encontrados no tutorial - parte 2 http://geocities.yahoo.com.br/brasilwireless/tutorial_j2me/j2me_02/j2me_02.html)

No capítulo 3 do tutorial abordamos como compilar e testar a aplicação "Hello World!" utilizando o Wireless ToolKit que a Sun Microsystems disponibiliza em seu site (para maiores detalhes veja

http://geocities.yahoo.com.br/brasilwireless/tutorial_j2me/j2me_03_1/j2me_03_1.html).

Neste quarto e último capítulo do tutorial, apresentarei uma versão mais sofisticada do programa "Hello World!", onde mostrarei como fazer animações simples usando caracteres de texto, o que pode ser melhorado, futuramente pelo próprio estudante, conforme alguns exercícios propostos ao final do documento.

Veja um pequeno vídeo de demonstração do resultado a ser obtido na tela do celular.

O código fonte em JAVA do exemplo aqui descrito tem direitos autorais pertencentes à NOKIA e pode ser encontrado no documento chamado "Brief Introduction to MIDP Programming".

Partes do aplicativoO aplicativo é dividido em 4 classes. São elas:

BouncingTextMIDletEsta classe é responsável por criar o Midlet (aplicação J2ME) e coordenar a transição

entre telas do aplicativo. Existem basicamente duas telas que são apresentada. Uma referente à edição do texto que será animado. Outra que é a própria animação. Cada qual está implementada em uma classe, sendoelas TextInputScreen eBouncingTextCanvas respectivamente.

No início da execução do aplicativo, criamos uma instância da classe TextInputScreen, para a qual passamos o foco do Display. Com isso a tela que é mostrada é referente a edição de um texto inicial ("Hello J2ME!"). Esse texto poderá ser modificado ou

Page 16: 1_O que é J2ME

mantido somente no início da execução da aplicação. Uma vez que esteja pronto para ser animado, o usuário pressiona a tecla "Iniciar" e nesse momento o controle que estava com o "TextInputScreen" volta para "BouncingTextMIDlet" através do método "textInputScreenDone". Nesse momento cria-se uma instância da classe "BouncingTextCanvas" e inicia-se a animação.

O controle somente volta para o "BouncingTextMIDlet" quando o usuário seleciona "Sair" durante a animação, forçando-se a desativação do Midlet e finalização da aplicação.

TextInputScreen

Esta classe contem uma tela que apresenta o texto a ser animado, permitindo sua alteração. É uma implementação muito simples que estende a classe "TextBox" de forma a ter uma base já pronta herdada com a finalidade de processar o teclado e mostrar os resultados na tela. O usuário pode selecionar "Sair" para forçar a finalização do aplicativo ou selecionar o comando "Iniciar" que faz o controle de execução voltar para a classe "BouncingTextMIDlet", a qual iniciará em seguida a animação do texto.

BouncingTextCanvas

A classe Canvas aqui utilizada é um "Displayable", assim como outras classes derivadas da classe Screen analisada na parte 2 do tutorial. A diferença é que esta classe é normalmente destinada ao uso de desenhos gráficos e contem uma série métodos para controle e processamento de eventos de entrada da interface com o usuário (teclado, eventos similares ao gerados com mouse ou com uso de touch screen).

Os métodos herdados dessa classe utilizados neste tutorial são:1. paint() - chamado a qualquer momento pelo sistema de controle de aplicativos para

redesenhar a tela. É ativado por uma ou múltiplas chamada ao método repaint(). O problema é que uma chamada a repaint() somente indica que a tela deve ser redesenhada e não implica em chamar paint() imediatamente (o qual nunca deve ser evocado diretamente!). Portanto usamos o método serviceRepaints() que bloqueia a execução da thread até que o método paint() tenha sido executado. Com isso podemos sincronizar o desenho de cada quadro da animação.

2. keyPressed(), keyRepeated() e keyReleased() - são chamados quando alguma tecla é pressionada. Embora não utilizemos esses métodos no nosso exemplo, eles serão necessários para os exercícios propostos.

Esta classe também implementa a interface "Runable", que lhe confere capacidade de ser executada em uma ou mais linhas de execução ou threads. A linguagem JAVA é nativamente multi-thread. Usando este recurso, podemos simplificar em muito o código executado reduzindo seu tamanho, o que é muito desejado pois o espaço disponível em muitos aparelhos celulares é bem limitado.

O método run() é o corpo da linha de execução, ou thread. Isto significa que quando uma instância da classe "BouncingTextCanvas" é criada, a primeira coisa que acontece é a execução do construtor. Em seguida, temos que criar um novo thread através da chamada a "new Thread(runable_objeto)". Nesse momento é criado uma nova thread, ou linha paralela de execução, cujo código a ser executado em paralelo é o que é definido pelo método run(). Essa nova thread somente será ativada (ou seja o método run será posto para rodar) quando for executado o método Thread.start(). Isto é feito através da execução do método

Page 17: 1_O que é J2ME

BouncingTextCanvas.startAnimation().

No nosso caso o método run() executa um "loop" infinito que somente é parado através do acionamento do comando "Sair" na interface da aplicação. Esse "loop" executa os seguintes passos:

i. calcula a hora corrente em milisegundos;ii. atualiza a posição do texto através de uma chamada a tick();iii. solicita o desenho do texto na nova posição através de repaint() e espera até que o

sistema indique que já desenhou a tela atualizada através de serviceRepaints();iv. verifica se já se passou mais que 100 ms. Caso não espera até que se passem os

100ms. v. Volta ao passo (i).

Como então esse "loop" é suspendido? Isto é feito pois a condição de parada do loop é quando a thread em execução não coincidir com a variável animationThread. Isto ocorre quando o usuário aciona "Sair" pois essa variável é mudada para "null". Notem que cada thread da classe "BouncingTextCanvas" acessa as mesmas variáveis da instância criada. Esses dados são compartilhados entre as várias threads criadas a partir de uma mesma instância. No nosso caso criamos apenas uma instância da classe e somente uma thread a partir dessa instância.

Programação com threads exige muito cuidado pois podemos entrar em situações conhecidas como "dead locks" ou "travadas fatais", onde o programa para de rodar por um thread esperar por uma condição que nunca vai ocorrer, a qual depende de outro thread que também espera por uma condição que nunca vai ocorrer no primeiro. É como se tivéssemos um problema de trânsito em um semáforo como abaixo:

Supondo que os carros somente podem seguir a direção das flechas, temos uma ilustração de um problema de "dead lock", onde tudo fica travado onde está.Existe um segundo possível problema em execuções multi-thread que é o sincronismo ou controle do acesso a dados compartilhados ou métodos compartilhados. Como não é possível prever onde a thread será paralisada para passar o controle de execução a outra thread, devemos utilizar o modificador synchronized para atributos ou métodos ou

Page 18: 1_O que é J2ME

synchronized(objeto) {} para blocos de código. Dessa forma garantimos que somente uma thread por vez acessará aquele atributo ou método ou mesmo executará um bloco de código por vez. Não havendo assim problemas de acesso "simultâneo" a essas áreas.

Com isso dito, podemos verificar que a classe "BouncingTextCanvas" cuida da execução da animação a uma taxa constante de quadros, através dos métodos run() e tick(), permite iniciar ou finalizar threads através dos métodos startAnimation() e stopAnimation() e implementa o método paint() que desenha cada quadro da animação.

Um objeto (instância) da classe "BouncingTextCanvas" pode conter um ou mais objetos do tipo "BouncingText". No nosso exemplo apenas controla um objeto desse tipo, portanto um único texto animado. Seria possível fazê-lo controlar mais que um...

BouncingTextClasse que controla um objeto animado da tela. Um objeto dessa classe tem atributos

específicos para ser animado, tais como posição na tela, o próprio texto a ser mostrado, direção e velocidade em um dado momento.

O método updatePosition(), garante que quando o texto ao ser animado atinge as bordas da tela, muda de direção de forma a se manter dentro dos limites da tela. Também condiciona que o movimento gerado não force com que o texto seja desenhado fora da tela. Para isso calcula o tamanho do texto em pixels e a cada interação verifica se a caixa imaginária que contem o texto estará dentro ou não da tela.

Outro método importante é o draw() que é chamado de dentro do BoucingTextCanvas.paint() de forma a desenhar o texto na última posição atualizada.Por últimos temos um método que inverte o texto (para "otxet" por exemplo) quando comandado via interface com o usuário.

Como rodar o programa usando o Wireless Toolkit?Conforme descrito no tutorial anterior, devemos criar um projeto e copiar o código no

diretório "Src". Serão criados três arquivos com extensão ".java". Novamente é fundamental tomar atenção quanto às maiúsculas e minúsculas no nome de cada arquivo pois o JAVA as distingue com sendo diferentes.

Abaixo segue o código fonte de cada qual com comentários que ajudam a entender o que foi feito.

(Nesta página estão os códigos BouncingTextMIDlet.java e TextInputScreen.java. Na página seguinte está o código para BouncingTextCanvas.java.)

BouncingTextMIDlet.javaimport javax.microedition.midlet.*;

import javax.microedition.lcdui.*; // Classe principal do Midlet public class BouncingTextMIDlet extends MIDlet {// Objeto que contem o texto a ser animado,

// o qual pode ser mudado no início da execução da aplicação private final TextInputScreen textInputScreen;// Objeto que contem o controle gráfico da animação

// É iniciado com null para saber que é a primeira vez que é executado private BouncingTextCanvas bouncingTextCanvas = null; // construtor da classe public BouncingTextMIDlet() {// Cria uma caixa de edição de texto que permitirá modificá-lo no

// início da execução da aplicação. Esse será o texto a ser animado.

Page 19: 1_O que é J2ME

textInputScreen = new TextInputScreen(this, "Hello J2ME"); }

// Método executado no início da execução da aplicação ou na volta de uma pausa public void startApp() {

Displayable current = Display.getDisplay(this).getCurrent();// verificamos se estamos voltando de uma pausa ou se estamos iniciando a aplicação if (current == null) {// caso a variável current seja null estamos na primeira execução da aplicação

// neste caso ativamos o foco para a edição inicial do texto a ser animado Display.getDisplay(this).setCurrent(textInputScreen);

} else {// caso seja a volta de uma pausa, ativamos o foco para o último objeto de onde

// a aplicação foi interrompida, seja qual for esse objeto. Display.getDisplay(this).setCurrent(current);// Em particular caso seja a tela da animação, inicia uma nova a animação... if (current == bouncingTextCanvas) {

bouncingTextCanvas.startAnimation(); } } }

// Método executado quando a aplicação sofre uma pausa public void pauseApp() {// Caso estávamos animando o texto, solicitamos a parada do mesmo if (bouncingTextCanvas != null) {

bouncingTextCanvas.stopAnimation(); } }

// Método executado quando a aplicação é terminada public void destroyApp(boolean b) {// Caso estávamos animando o texto, solicitamos a parada do mesmo if (bouncingTextCanvas != null) {

bouncingTextCanvas.stopAnimation(); } }

// Método conveniente para ser executado quando solicitado que se// termine a execução do aplicativo

void exitRequested() { destroyApp(false); notifyDestroyed(); }

// Método evocado ao final da execução da tela de edição de texto // associada ao objeto textInputScreen

void textInputScreenDone(String str) {// Cria e inicia a animação. bouncingTextCanvas =

new BouncingTextCanvas(this, Display.getDisplay(this), str); bouncingTextCanvas.startAnimation();

Page 20: 1_O que é J2ME

// Muda o foco para mostrar na tela a animação.

Display.getDisplay(this).setCurrent(bouncingTextCanvas); } }

TextInputScreen.java

import javax.microedition.lcdui.*; // Objeto que contem o texto a ser animado e cria uma tela para sua ediçãopublic class TextInputScreen extends TextBox implements CommandListener { // O objeto mantém uma referência ao objeto pai (seu criador) private final BouncingTextMIDlet midlet;

private final Command exitCommand; private final Command startCommand;

// Método construtor ... TextInputScreen(BouncingTextMIDlet midlet, String string) {// executa o construtor da super classe (TextBox) super("Texto: ", string, 256, TextField.ANY);// guarda a referência ao objeto Pai this.midlet = midlet;// Cria os comandos de softkey mostrados na parte inferior da tela exitCommand = new Command("Sair", Command.EXIT, 1);

addCommand(exitCommand); startCommand = new Command("Iniciar", Command.SCREEN, 1); addCommand(startCommand);

// Coloca o objeto na lista de objetos que podem receber entrada// isto é, podem interagir com o usuário via teclado, por exemplo

setCommandListener(this); }

// método executado quando acionada alguma softkey public void commandAction(Command c, Displayable d)

if (c == exitCommand) {// caso seja acionado o "sair" solicita a saída imediata da aplicação midlet.exitRequested();

} else if (c == startCommand) {// caso seja acionado o "iniciar" solicita o início da animação midlet.textInputScreenDone(getString());

} } }

BouncingTextCanvas.java

import java.util.Random; import javax.microedition.lcdui.*; class BouncingTextCanvas extends Canvas implements CommandListener, Runnable {

Page 21: 1_O que é J2ME

// os atributos do objeto com modificador final são referências a outros // objetos usados pela classe. Este não serão modificados durante a execução // da aplicação.

private final BouncingTextMIDlet midlet; private final Display display; private final Command exitCommand; private final Command reverseCommand; private final BouncingText text;

// variáveis que contem cores de fundo e do texto a ser animado private int bgRGB;

private int textRGB;// animationThread conterá a referência à thread (linha de execução) da animação private volatile Thread animationThread = null; // construtor associado à classe:

// guarda as referências a objetos importantes (midlet pai e display) BouncingTextCanvas (BouncingTextMIDlet midlet, Display display, String

string) { this.midlet = midlet; this.display = display;

// cria os comandos de softkey para sair e inverter o texto setCommandListener(this);

reverseCommand = new Command("Inv", Command.SCREEN, 1); exitCommand = new Command("Sair", Command.EXIT, 1); addCommand(exitCommand); addCommand(reverseCommand);

// gera as cores de acordo com a capacidade gráfica do aparelho celular nti ch = getHeight();

int cw = getWidth(); initColors();

// cria uma instância do objeto que será animado text = new BouncingText(string, textRGB, 0, ch/2, cw, ch);

} // método que inicia a animação, criando uma nova linha de execução void startAnimation() {

animationThread = new Thread(this); animationThread.start(); }

// método que para a animação sinalizando através da variável animationThread // que o loop de execução do método run() deve terminar, levando ao término // da linha de execução

void stopAnimation() { animationThread = null; }

// método que é executado durante a existência da linha de execução do objeto public void run() {// tempo ideal de execução de cada quadro da animação - 100 milisegundos

// equivalente a 10 FPS (quadros por segundo)

Page 22: 1_O que é J2ME

int millis_per_tick = 100;// toma o identificador da linha de execução corrente, a qual deverá

// apontar para esta própria execução... Thread currentThread = Thread.currentThread(); // cuida das exceções referentes a este bloco de execução... try {// se a animação não foi paralisada ... while (currentThread == animationThread) {// toma o relógio em milisegundos e anima o texto através de tick() ... long startTime = System.currentTimeMillis();

tick();// solicita o redesenho da tela e fica bloqueado até que a tela tenha sido atualizada repaint(0, 0, getWidth(), getHeight());

serviceRepaints();// não sabemos quanto tempo levou a execução dos passos anteriores, portanto

// calculamos a diferença do tempo de espera de cada quadro long elapsedTime = System.currentTimeMillis() - startTime;// se a execução foi mais rápida que os 100 ms aguardamos pelo tempo restante if (elapsedTime < millis_per_tick) {

synchronized(this) { wait(millis_per_tick - elapsedTime); } } else {

// caso contrário forçamos uma mudança de contexto para que outros processos // sejam executados pelo sistema, tais como organização da memória, ou outros threads

currentThread.yield(); } } } catch(InterruptedException e) { } }

// método executado quando a tela é desenhada public void paint(Graphics g) { // primeiro apagamos toda a tela com a cor de fundo g.setColor(bgRGB);

g.fillRect(0, 0, getWidth(), getHeight());// em seguida desenhamos o texto na posição corrente text.draw(g);

} // trata da execução de comandos via softkey public void commandAction(Command c, Displayable d) {// caso solicitemos a saída imediata da aplicação... if (c == exitCommand) {

stopAnimation(); midlet.exitRequested(); } else if (c == reverseCommand) {

// ou se apenas pedimos a inversão do texto em animação...

Page 23: 1_O que é J2ME

text.reverse(); } }

// a cada quadro de 100ms da animação atualizamos a posição do texto// criando a ilusão de uma animação livre, como o vôo de um mosquito

private synchronized void tick() { text.updatePosition();

} // cuida da seleção de cores para o fundo e para o texto a ser animado private void initColors() {

int white = 0xffffff; int black = 0x000000;

// caso seja colorido, geramos uma cor aleatória para o texto e fundo if (display.isColor()) {

Random random = new Random(); textRGB = random.nextInt() & 0xffffff;

// a cor de fundo será contrastante em relação ao texto... bgRGB = white - textRGB;

} else {// neste caso - não colorido, usamos o velho branco e preto... textRGB = black;

bgRGB = white; } }

// classe que controla um texto que é animado na tela class BouncingText { // atributos não modificáveis ao longo da execução...

// largura e altura da tela - limita fronteiras de movimentação private final int w;

private final int h;// cor do texto private final int textRGB;// gerador de seqüência pseudo aleatória private final Random random; // atributos variáveis ao longo da execução...

// texto a ser animado private String string;// posição do texto na tela em pixels

private int x; private int y;

// largura e altura do texto em pixels private int strWidth = 0;

private int strHeight = 0;// vetor de direção da animação private int xdir = 1;

private int ydir = 1; // construtor inicia os atributos do objeto

Page 24: 1_O que é J2ME

BouncingText(String string, int textRGB, int x, int y, int w, int h) { this.string = string; this.x = x; this.y = y; this.w = w; this.h = h; this.textRGB = textRGB; random = new Random(); }

// atualizamos a posição do texto de forma aleatória ... private void updatePosition() {

int vx = random.nextInt() & 0x07; int vy = random.nextInt() & 0x07;

// verificamos se não atingimos as fronteiras laterais da tela // caso no qual devemos mudar a direção da animação

if ((xdir == 1) && ((x + vx) >= maxAnchorX())) { xdir = -xdir; } else if ((xdir == -1) && ((x - vx) < 0)) { xdir = -xdir; }

// caso a nova posição não jogue o texto para fora da tela, atualizamos a mesma int xnew = x + (vx * xdir);

if ((xnew >= 0) && (x < maxAnchorX())) { x = xnew; }

// verificamos se não atingimos as fronteiras de fundo e topo da tela // caso no qual devemos mudar a direção da animação

if ((ydir == 1) && ((y + vy) >= maxAnchorY())) { ydir = -ydir; } else if ((ydir == -1) && ((y - vy) < 0)) { ydir = -ydir; }

// caso a nova posição não jogue o texto para fora da tela, atualizamos a mesma int ynew = y + (vy * ydir);

if ((ynew >= 0) && (y < maxAnchorY())) { y = ynew; } }

// método para desenho do texto private void draw(Graphics g) {// caso não tenhamos atualizado a altura e largura do texto em pixels... if (! (strHeight > 0)) {

Font f = g.getFont(); strHeight = f.getHeight(); strWidth = f.stringWidth(string); }

// desenhamos o texto na tela na posição correta

Page 25: 1_O que é J2ME

g.setColor(textRGB); g.drawString(string, x, y, Graphics.TOP|Graphics.LEFT); }

// calcula o valor máximo de x para não jogar o texto para fora da tela private int maxAnchorX() {

return w - strWidth; }

// calcula o valor máximo de y para não jogar o texto para fora da tela private int maxAnchorY() {

return h - strHeight; }

// método que inverte o texto -- exemplo <--> olpmexe private void reverse() {// convertemos o texto em uma cadeia de caracteres char[] carray = string.toCharArray();// para em seguida do fim para o início criar a cadeia de caracteres invertida for (int old = string.length() - 1, nu = 0; old >= 0; old--, nu++) {

carray[nu] = string.charAt(old); }

// por fim atualizamos o texto com seu conteúdo invertido... string = new String(carray);

} } }

Exercícios propostos: A fim de que o estudante tenha como exercitar o que aprendeu, proponho alguns

exercícios que aumentam em grau de complexidade. Tratam-se de modificações que devem ser feitas ao código original a fim de implementar algumas alterações, as quais podem ser acumuladas, produzindo um novo código final melhorado.

1) Na classe TextInputScreen seria interessante modificar o código a fim de não permitir que o usuário altere o texto a ser animado para uma cadeia vazia de caracteres. Se isto ocorrer, não haverá efeito gráfico da animação. Experimente para isso modificar o método commandAction() dessa classe.

2) Na atual implementação, o texto a ser animado só pode ser modificado no início da execução e somente uma única vez. Tente modificar o código de forma a permitir que o mesmo seja modificado durante a animação. Crie um comando adicional para implementar essa nova funcionalidade, alterando o fluxo das telas.

3) Implemente controle de velocidade. Atualmente a velocidade é recalculada a cada 100 ms através de tick() e de updatePosition(). Faça com que a velocidade seja calculada de forma aleatória uma única vez a fim de que o texto se mova suavemente a uma velocidade constante pela tela.

4) Em seguida implemente através das teclas de direção do celular um controle de velocidade horizontal e vertical. Por exemplo, as teclas de setas para cima e para baixo aumentam e diminuem a velocidade vertical, enquanto as teclas de setas para esquerda e direita controlam a velocidade horizontal. Para isso será necessário implementar um dos métodos descritos anteriormente (keyPressed, keyRepeated ou keyReleased).

Page 26: 1_O que é J2ME

5) Altere a classe BouncingTextCanvas e BouncingText de forma a permitir múltiplos textos animados ao mesmo tempo. Adicione o controle do botão “KEY_POUND”, por exemplo, para adicionar um novo texto e animá-lo. Adicione o controle do botão “KEY_STAR” para eliminar o último texto animado adicionalmente criado sem deixar que pelo menos fique um texto sendo animado na tela.