Um tutorial passo a passo

Rosfran Lins Borges

Um esquema completo, passo a passo, começando com a instalação do ambiente para rodar os MIDlets Java (WTK), até a execução de uma simples aplicação exemplo.

 

Um novo filão de desenvolvimento de aplicações foi aberto, há alguns anos atrás, quando uma nova tendência de mercado apontava para o crescimento no número de dispositivos móveis. Hoje, os dispositivos móveis, em diversos e variados aspectos, chegam a se igualar (ou até superar) o poder de desempenho e quantidade de recursos de muitas classes de sistemas de computação mais avançados, como os desktops de uso comercial ou doméstico. Aproveitando a grande oportunidade de mercado, e definindo os padrões MIDP e CLDC (usados em dispositivos com recursos limitados de memória ou processamento), a Sun™ Microsystems criou o modelo J2ME (Java 2 Micro Edition), que permite que se desenvolvam aplicativos para dispositivos móveis usando a linguagem Java. Esses aplicativos escritos em Java são comumente denominados MIDlets e são executados em uma máquina virtual Java reduzida, visando funcionar em dispositivos com baixos recursos, chamada KVM (Kilobyte Virtual Machine), usada na implementação de referência da especificação J2ME.

Para que possamos projetar, codificar, rodar e testar nossa aplicação MIDlet, usaremos a forma mais prática: usando um emulador de ambiente dos dispositivos móveis, onde possamos simular um ambiente bastante semelhante ao qual estaremos enviando nosso MIDlet (em nossos exemplos, qualquer aparelho celular com uma VM Java). O uso de tal ferramenta se faz adequado, uma vez que o desenvolvedor não precisa necessariamente ter em mãos um aparelho habilitado para executar MIDlets. A Sun Microsystems, pensando nessa facilidade para os desenvolvedores J2ME, disponibilizou a ferramenta WTK (Wireless Toolkit). O J2ME Wireless Toolkit 2.0, da Sun Microsystems (resumidamente, WTK), ganhou recentemente o JavaWorld Editor's Choice Award, como sendo a melhor ferramenta para desenvolvimento de aplicações Java em dispositivos móveis. Usaremos essa ferramenta para exemplificar o processo de criação e execução de uma aplicação exemplo habilitada ao CLDC e MIDP.

Instalando e configurando o ambiente

Antes de tudo, é necessário fazer o download do pacote do instalador do WTK no site da Sun (java.sun.com/products/j2mewtoolkit). Depois de finalizado o download, a execução do instalador é rápida, e, sem necessidade de maiores configurações, a instalação é completada.

Depois dessa etapa de instalação, você perceberá que existe uma nova entrada no menu Start > Programs > J2ME Wireless Toolkit 2.1. Clique no item KToolbar. Uma tela se abrirá, como na Figura 1.

pwm-24ago-midlets_image001.png

Figura 1. Tela principal do aplicativo KToolbar, do WTK

Para fazer um teste com o novo ambiente, você já pode executar as aplicações MIDlet de exemplo que já vem com o WTK. Basta clicar no botão “Open Project...”. Um diálogo aparecerá, e você poderá selecionar qual aplicação você quer abrir na tela do console (cada aplicação vem com uma bola cinza preenchida à esquerda do nome). Depois de aberta, a aplicação pode ser executada, quando você clica no botão Run. Depois de clicado, o evento associado a esse último botão abrirá uma tela, com uma imagem semelhante à de um aparelho celular. Esse aplicativo é um emulador de um dispositivo móvel, capaz de executar aplicações J2ME. Nesse momento, você poderá usar o mouse para clicar nos botões do emulador, da mesma forma que faria num aparelho físico existente. O botão Build compila a aplicação para o subdiretório classes da sua aplicação, gerando os bytecodes necessários para a execução do MIDlet.

Uma aplicação desde o princípio

Depois de ter tido uma visão geral do que o KToolbar pode fazer para ajudar na construção e deployment de aplicações para dispositivos móveis, vamos agora, com o auxílio dele, iniciar uma aplicação do princípio. Com a tela principal do KToolbar aberta, clique no botão “New Project...”. Será solicitado que você entre com duas informações: um nome para o Projeto (que pode ser qualquer um – lembre-se que depois disso será criado um diretório com esse nome na área de arquivos apps do diretório raiz de instalação do seu WTK); e o segundo campo é o nome da sua classe principal, que será uma especialização da classe javax.microedition.midlet.MIDlet (um exemplo simples e totalmente funcional na Listagem 1 – é necessário, no entanto, que a Listagem 2 esteja no mesmo arquivo, ou no mesmo pacote, ou diretório).

Confirme a criação do novo projeto clicando depois >em Create Project... Logo a seguir aparecerá uma tela como a da Figura 2. Nessa tela, iremos configurar as opções de configuração de nossa aplicação. O arquivo principal de configuração é o com extensão de arquivo JAD, que é semelhante aos arquivos de propriedade em Java (no nosso caso, MIDletExemplo.jad), criado a partir de um arquivo MANIFEST.MF de um JAR (um arquivo de configurações simples, com nomes de variáveis seguidas por sinais de 2 pontos e seu respectivo valor). O KToolbar é uma ferramenta muito útil, porque ele já cria o JAD (ou também podemos chamá-lo de “arquivo de configuração do MIDlet”) automaticamente, incluindo os campos que são mandatórios pelo MIDlet (“required fields”), e os campos opcionais (aqueles que podem ser preenchidos ou não, pois não são obrigatórios).

pwm-24ago-midlets_image002.png

Figura 2. Tela de configuração do aplicativo MIDlet

Após ter feito isso, o KToolbar vai gerar um diretório chamado MIDletExemplo, com uma seqüência padrão de sub-diretórios – bin, lib, res, src e classes. No diretório bin ele criará um arquivo MIDletExemplo.jad e, futuramente, um aplicativo empacotado no formato JAR (depois que compilarmos nossos fontes Java compatíveis com MIDP). O diretório lib é onde estarão as bibliotecas que seu MIDlet, por ventura, necessite; o diretório src contêm os fontes Java (J2ME) que implementarão nossa aplicação MIDlet; o diretório classes, onde estão os bytecodes dos seus arquivos fonte Java; e o diretórios res (resources) serve como repositório de todas as coisas que não se encaixem nas áreas acima, como, por exemplo, imagens, arquivos mid, etc., que a sua aplicação móvel utilize na criação da interface com o usuário.

 

J2ME na prática – cuidados ao carregar recursos exclusivos de certos aparelhos

Certos recursos em aparelhos móveis, notadamente opções de interface, não são definidas nem na especificação MIDP nem na CLDC. Isso vem do fato de que certos recursos não foram declarados fundamentais para que fossem incluídos na especificação padrão, decisão fundamental para que as aplicações desenvolvidas usando a especificação J2ME causassem o menor impacto possível em desempenho, e a KVM (implementação de referência da especificação J2ME) pudesse ser carregada em aparelhos com mínima capacidade de memória e processamento.

Portanto, quando se deseja usar um recurso proprietário de algum aparelho, é recomendável pensar um pouco na portabilidade da aplicação. Por exemplo, se a sua aplicação precisa fazer uso de um alarme de vibração, popularmente conhecido como vibracall, as especificações MIDP e CLDC mais antigas não implementam esse recurso. Então é necessário usar bibliotecas e classes específicas do aparelho para o qual será destinada a sua aplicação. As linhas de códigos a seguir exemplificam um pouco o que pode ser feito para permitir que uma aplicação que use o vibracall possa executar em diversos aparelhos (com ou sem esse recurso em específico):

 

void vibrar() {

   try {

    // Vibrar a 100% durante 200 milisegundos

    DeviceControl.startVibra(100, 200);

   } catch(IllegalStateException ise) {

    // Uma exceção IllegalStateException é lançada se o dispositivo não tem

    // suporte a vibração. Nada mais pode ser feito, então apenas ignore.

   }

 }

 

O método vibrar() faz uso da classe com.nokia.mid.ui.DeviceControl, proprietária da Nokia (ou seja, só funcionará em aparelhos com middleware Nokia que tenham essa biblioteca implementada). Caso a função de notificação ao usuário por vibração não funcionar, o método startVibra lança uma exceção chamada IllegalStateException, que avisa sobre um estado ilegal da aplicação. A resposta padrão e recomendada a uma exceção desse tipo, nessa situação, é não fazer nada, e continuar com a execução normal da aplicação.

No caso da função com.nokia.mid.ui.DeviceControl.startVibra() acima, ela mesma faz o controle se o recurso necessário (biblioteca vibracall) está presente, lançando uma exceção apropriada, caso não seja possível encontrar tal recurso (IllegalStateException).  Muitas vezes, já no momento de carga da definição da classe necessária, usando o método forName() da classe Class, é possível tomar uma decisão apropriada, caso a classe não seja encontrada, ou seja, quando a exceção ClassNotFoundException for lançada durante a carga. Por exemplo:

 

boolean nokiaSound = false; // desligado por default

try {

  Class.forName("com.nokia.mid.sound.Sound");

  nokiaSound = true;

}

catch (ClassNotFoundException cnfe) {

  // Esta exceção é lançada se o dispositivo

  // não tem ou não consegue carregar a classe com.nokia.mid.sound.Sound.

}

 

O trecho de código acima declara uma variável booleana nokiaSound, que serve como um indicador de status, sobre se a biblioteca de sons proprietária da Nokia puder ser carregada ou não. A variável nokiaSound recebe valor true, caso a biblioteca seja carregada com sucesso, ou então permanece com o  valor inicial false, se o método estático forName(String className) da classe java.lang.Class lançar uma exceção ClassNotFoundException durante a carga.

 

Rodando a aplicação MIDlet exemplo

Depois de termos criado a aplicação e a configurado, podemos então criar os fontes Java que irão implementar o funcionamento do nosso “MIDletExemplo”. Usando um editor de textos padrão, criamos um arquivo MIDletExemplo.java, que conterá as listagens 1 e 2 (a classe CampoTexto não poderá ser declarada pública, uma vez que MIDletExemplo já é a classe pública do nosso arquivo MIDletExemplo.java, portanto a ausência do especificador de acesso public na declaração da classe CampoTexto). Copie o arquivo MIDletExemplo.java para o subdiretório src da sua aplicação (MIDletExemplo), no diretório apps do diretório de instalação do seu WTK.

Ao clicar no botão Build, a aplicação é compilada para o sub-diretório classes da sua aplicação. Caso a compilação tenha sido feita com sucesso (ou seja, os arquivos-fonte Java não contenham erro), os arquivos MIDletExemplo.class e CampoTexto.class são então criados nesse diretório classes, e a mensagem “Build complete” é impressa na janela principal do Ktoolbar. Após isso, é possível clicar no botão Run do KToolbar, que abrirá o emulador MIDP, e mostrará o nome da sua aplicação (MIDletExemplo) numa lista de opções. Clique no botão Launch do emulador e espere que a tela principal seja carregada. Você verá um componente de entrada de texto onde você poderá digitar uma string. Ao clicar no item de menu abreAlerta, uma janela Alert será aberta com uma mensagem, e depois fechará automaticamente num intervalo de 2 segundos. Essa aplicação exemplo demonstra apenas o uso de alguns recursos de projeto de interfaces com usuários wireless.

Abaixo, as listagens com os códigos, respectivamente, do MIDlet (MIDletExemplo.java), que é a aplicação principal (veja a Listagem 1), e do componente de UI para entrada de dados (classe CampoTexto – veja a Listagem 2).

 

Listagem 1. Um MIDlet exemplo

import javax.microedition.midlet.MIDlet;

import javax.microedition.lcdui.*;

 

public class MIDletExemplo extends MIDlet {

  private Form formulario;

  private Displayable displayable;

 

  public MIDletExemplo() {}

 

  public void startApp() {

    this.displayable = Display.getDisplay(this).getCurrent();

    if (this.displayable == null) {

      // Criando o Form

      formulario = new Form("FormSimples");

      StringItem strItemDigiteNome = new StringItem("digitaNome", "Digite seu nome");

      // Nosso componente de GUI, especializado de TextField

      CampoTexto searchEdit = new CampoTexto("Nome: ", this);

      // Adicionando o componente ao Form

      formulario.append(searchEdit);

      showScreen(formulario);

    }

    else {

       showScreen(this.displayable);

    }

  }

 

  public void exitRequest() {

    destroyApp(false);

    notifyDestroyed();

  }

 

  public void pauseApp() {}

 

  public void destroyApp(boolean unconditional) {

    // identifica os atributos a serem recolhidos pelo garbage collector

    this.formulario = null;

    this.displayable = null;

  }

 

  public void showScreen(Displayable disp) {

    Display.getDisplay(this).setCurrent(disp);

  }

}

 

Listagem 2. Um componente de entrada de dados usando a MIDP

class CampoTexto extends TextField implements CommandListener {

  private MIDletExemplo midlet;

  public CampoTexto(String caption, MIDletExemplo midlet) {

    super(caption, "", 60, TextField.ANY);

    this.midlet = midlet;

    addCommand(new Command("sair", Command.EXIT, 1));

    addCommand(new Command("abreAlerta", Command.SCREEN, 2));

    setCommandListener(this);

  }

 

  public void commandAction(Command command, Item item) {

    if (command.getLabel().equals("sair")) {

      midlet.exitRequest();

    }

    else if (command.getLabel().equals("abreAlerta")) {

      Alert a = new Alert("Mensagem de alerta", "Olá usuário " +getString()+"!", null, null);

      a.setTimeout(2000);

      midlet.showScreen(a);

    }

  }

}

 

A Figura 3 mostra uma interação típica com o MIDletExemplo.

 

 pwm-24ago-midlets_image003.png pwm-24ago-midlets_image004.png

Figura 3. Telas do aplicativo MIDlet executando no emulador WTK

Funcionamento do MIDlet

A nossa classe especializada de javax.microedition.midlet.MIDlet define métodos que respondem a eventos relativos ao ciclo de vida da aplicação. Por exemplo, os métodos startApp(), pauseApp() e destroyApp() precisam ser implementados caso você queira que algum processamento de resposta ocorra quando um desses eventos de ciclo de vida do MIDlet ocorrerem. Enfim, qualquer aplicação séria em J2ME deve implementar um tratamento adequado a esses eventos (contenção e controle de recursos alocados pelo MIDlet – devemos lembrar que estamos desenvolvendo para um dispositivo com pouco poder de processamento e memória, e devemos nos preocupar com a alocação excessiva de objetos).

Em J2ME, tudo que pode ser apresentado na tela do aparelho herda, em algum nível, da classe abstrata javax.microedition.lcdui.Displayable. Essa classe é que define o que pode ser apresentado, ou visualizado, no display do dispositivo. Ou seja, gráficos, componentes de interface, objetos de apresentação, etc. Usando o método estático getDisplay(MIDlet midlet) da classe javax.microedition.lcdui.Display (funciona como um “pattern factory”), é possível obter uma instância do display daquele MIDlet em específico passado como parâmetro na função getDisplay(MIDlet midlet). Esse método retorna um objeto Display, que é a instância atual do display para aquele MIDlet. Com essa instância, você pode usar os métodos void setCurrent(Displayable displayable), ou Displayable getCurrent(), da classe Display, para alterar o Displayable que está sendo visualizado no momento, ou obter o Displayable sendo visualizado no momento, respectivamente.

Para a implementação do nosso componente de entrada de dados (classe CampoTexto), fizemos uso de um conceito bastante conhecido para os desenvolvedores acostumados com programação orientada a eventos: as interfaces com sufixo Listener no pacote javax.microedition.lcdui, da especificação MIDP (presentes desde a versão 1.0 do MID Profile). No exemplo proposto, nossa classe CampoTexto implementa a interface javax.microedition.lcdui.ItemCommandListener. Essa interface define um método commandAction(Command command, Item item), que é chamado pelo framework MIDP sempre que uma iteração do usuário com o MIDlet chamar por um dos objetos Command definidos no construtor da classe CampoTexto. Definimos apenas 2 comandos: um para abrir a janela estilo Alert (tag abreAlerta), e outro para fechar a aplicação (tag sair). O comando abreAlerta cria uma instância de javax.microedition.lcdui.Alert, e define um timeout para que essa janela seja fechada em 2000 milisegundos (2 segundos) após aberta. O comando sair chama o método exitRequest(), declarado na classe MIDletExemplo. Essas instâncias de Command aparecem como itens de opção no canto inferior do display do dispositivo (esse posicionamento dos Commands varia também de aparelho para aparelho, mas normalmente fica na porção inferior da tela). No construtor de CampoTexto, definimos qual o nosso Listener para os Commands, que é a própria classe CampoTexto (lembremos que ela implementa a interface ItemCommandListener, e portanto declara o método commandAction(Command command, Item item).

A classe CampoTexto, como é um campo de entrada da UI, herda da super-classe TextField, onde ela faz uso dos atributos e métodos dessa classe para criar um componente de entrada de dados, semelhante a uma caixa de texto, onde é possível entrar com strings de informação, e eventualmente enviar essas informações a um módulo do sistema onde essa entrada possa ser tratada e processada.

Abaixo, apenas para ilustrar, um diagrama da hierarquia de classes de interface com usuário (UI) do MID Profile (Figura 4). Podemos perceber que as classes Canvas e Screen são herdeiras diretas da classe Displayable, ou seja, são as classes principais para apresentação e interface com usuário - um Canvas permite a criação de uma área de desenho livre e manipulação de eventos de baixo nível (como o tratamento de ações do teclado do aparelho, por exemplo), e Screen é a classe topo da hierarquia de componentes para entrada de dados do usuário e criação de formulários (GUI):

 pwm-24ago-midlets_image005.png

 

Figura 4. Hierarquia de classes de UI do MIDP

Integração com IDEs

Para facilitar o desenvolvimento de aplicações móveis, existem alguns plug-ins, ou extensões, que podem ser instaladas nas distribuições em uso. O Borland™ JBuilder, por exemplo, tem uma extensão chamada MobileSet que, quando instalada, permite que se configure e execute aplicações MIDlet de dentro do JBuilder (a URL onde a extensão pode ser baixada está presente na sessão de Links dessa matéria). O interessante é a integração do JBuilder MobileSet com diversos SDKs, como por exemplo, o da Nokia™.

Para quem usa a IDE Eclipse, ou é adepto de softwares IDE livres, há um plug-in bastante interessante para desenvolvimento wireless com J2ME: o EclipseME – Eclipse J2ME Plug-in. Com ele, é possível criar projetos J2ME de dentro do Eclipse; editar arquivos JAD de configuração dos MIDlets; instalar, escolher e carregar um emulador específico para a aplicação, etc. Verificar na sessão Links o endereço para obter o plug-in EclipseME.

Aprofundando o seu conhecimento em J2ME

Para finalizar, terminamos dizendo que apenas a prática leva à perfeição (ou quase isso...). Existe um número muito grande de ferramentas que auxiliam o desenvolvedor J2ME na tarefa de projetar, implementar e testar a sua aplicação: vimos apenas algumas alternativas, e nos fixamos na solução oficial e mais conhecida, que é a ferramenta WTK da Sun. Infelizmente, a abordagem a todas as alternativas possíveis de ajuda ao desenvolvedor foge ao escopo da matéria, mas esperamos que essa seja apenas o início de uma interessante interação, que trará importantes benefícios a quem desejar entrar nessa aventura de descobertas que é o mundo do desenvolvimento wireless.

 

Links

java.sun.com/j2me

Referência básica da tecnologia J2ME (Java 2 Micro Edition).

forum.nokia.com

Fórum de discussões da Nokia, sobre desenvolvimento para dispositivos wireless; site bastante interessante, com muitas informações, tanto para o desenvolvedor wireless iniciante como para o avançado.

borland.com/mobile/jbuilder

Acesse a página acima para obter o SDK do Borland JBuilder Mobile Edition, que atualiza o Borland JBuilder para desenvolver e executar aplicações móveis com J2ME.

eclipseme.sourceforge.net

Link para o EclipseME - Eclipse J2ME Plug-in

ncsp.forum.nokia.com/downloads/nokia/documents/Java_MIDP_App_Dev_Guide_v1_0.pdf

"Nokia MIDP Application Developer’s Guide for Nokia Devices"

ncsp.forum.nokia.com/downloads/nokia/documents/How_to_Create_MIDlets_v1_1.pdf

"Creating MIDlets with JBuilder or Sun ONE Studio and Nokia Developer’s Suite for J2ME"

 

Rosfran Lins Borges (rosfran.borges@indt.org.br) é programador certificado Java, consultor certificado RUP (Rational™ Unified Process), e ocupa o cargo de Engenheiro de Software no Instituto Nokia de Tecnologia (INdT), em Brasília/DF. Trabalha com J2EE, J2ME, C e C++, em projetos de sistemas heterogêneos de integração de aplicações wireless com soluções cliente-servidor, usando Symbian™, Java™, C++ e XML, sobre a família de protocolos TCP/IP e redes de telefonia móvel de terceira geração – 3G (GPRS)