Figura Demonstrativa

Olá pessoal! Já está na hora de começarmos a interagir com nossos MIDlets. Mas como fazemos isso utilizando a MIDP?

A API MIDP processa eventos através do uso da classe Command, que encapsula a forma como o usuário se comunica com a aplicação. Esse encapsulamento é feito através do registro de listeners, muito parecido com o processamento de eventos do Java AWT. Resumidamente pense em um Command como um botão do controle remoto da sua televisão: assim que você aperta um botão ela troca de canal; você não sabe e nem te interessa como ela faz isso, só interessa o resultado (isso do ponto de vista do usuário, mas interessa como é feito através do ponto de vista de nós programadores).

Para utilizar um Command, os objetos MIDP que estiverem interessados a interagir com eventos devem implementar a interface CommandListener, que provê o método commandAction. Dentro desse método é definido o que irá acontecer assim que uma instância de um Command for acionada, ou seja, é onde definimos o comportamento que as classes que se utilizam de Commands irão assumir. Voltando a associação com o controle remoto, o método commandAction é onde iremos definir que canal será escolhido, ou seja, o comportamento que será assumido pela tecla assim que for pressionada.

Commands podem se adicionados a qualquer objeto Displayable com exceção de instancias da classe Alert. Eles são organizados como botões ou entradas em um sistema de menu (ver figura abaixo). [1]

Commands em um Displayable

Figura 1

Um Command possui três atributos que são passados quando ele é instanciado:

  • Label: O nome com o qual o Command será apresentado ao usuário
  • Type: Uma constante que indica a espécie do comando, tanto para a aplicação quanto para a UI do MIDP em tempo de execução. Pode apresentar informação adicional (como um ícone) sobre o Command. Os principais tipos podem ser vistos na tabela 1. Alguns tipos especiais são mapeados diretamente para as teclas apropriadas do dispositivo, como BACK, CANCEL, etc.
  • Priority: um int que indica a importância do Command em relação aos outro Commands na UI. Quanto menor o valor, maior a prioridade (0 é mais importante que 1, por exemplo).
Tabela 1
Command Type Description Descrição
BACK Retorna para a tela anterior
CANCEL Reposta negativa padrão para um diálogo
EXIT Sai da aplicação
HELP Requisita ajuda
ITEM Exibe um pequeno hint sobre um item selecionado
OK Resposta de confirmação padrão a um diálogo
SCREEN Um commando definido e mostrado pela própria aplicação
STOP Pára uma operação em execução

Explicado tudo isso, vamos para a prática. Crie um novo MIDlet e chame-o de RemoteControlMIDlet e adicione a interface CommandListener.

Selecionando uma interface

Selecionando a interface CommandListener

As figuras utilizadas no MIDlet exemplo são apenas um enfeite e uma forma de não fugir da comparação com o controle remoto ;).

Olhe o código completo abaixo:

import java.io.IOException;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.StringItem;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class CommandExampleMIDlet extends MIDlet implements CommandListener
{

	private Display display;
	private Form channelOne;
	private Form channelTwo;
	private Form channelThree;

	private Command cmdGoSBT;
	private Command cmdGoGlobo;
	private Command cmdGoRecord;

	private Image plimimg;
	private Image supernaturalimg;
	private Image csiimg;

	public CommandExampleMIDlet()
	{
		display = Display.getDisplay(this);

		try
		{
			plimimg = Image.createImage("/plim-plim.jpg");
			supernaturalimg = Image.createImage("/supernatural.jpg");
			csiimg = Image.createImage("/csi.jpg");
		} catch (IOException e) {
			// TODO: handle exception
		}

		cmdGoGlobo = new Command("Globo", Command.SCREEN, 0);
		cmdGoSBT = new Command("SBT", Command.SCREEN, 1);
		cmdGoRecord = new Command("Record", Command.SCREEN, 2);

		channelOne = configureScreen(channelOne, "Globo", new StringItem(null, "Plim-plim"), cmdGoSBT, cmdGoRecord, plimimg);
		channelTwo = configureScreen(channelTwo, "SBT", new StringItem(null, "Sobrenatural - Supernatural"), cmdGoGlobo, cmdGoRecord, supernaturalimg);
		channelThree = configureScreen(channelThree, "Record", new StringItem(null, "C.S.I. - Investigação Criminal"), cmdGoSBT, cmdGoGlobo, csiimg);
	}

	protected void destroyApp(boolean unconditional)
			throws MIDletStateChangeException
	{

	}

	protected void pauseApp()
	{

	}

	protected void startApp() throws MIDletStateChangeException
	{
		display.setCurrent(channelOne);
	}

	private Form configureScreen(Form fm, String title,
			StringItem text, Command cmd1, Command cmd2, Image img)
	{
		fm = new Form(title);

		fm.append(text);
		fm.append(img);
		fm.addCommand(cmd1);
		fm.addCommand(cmd2);
		fm.setCommandListener(this);

		return fm;
	}

	public void commandAction(Command c, Displayable d)
	{
		if (c == cmdGoSBT)
			display.setCurrent(channelTwo);
		else
			if (c == cmdGoGlobo)
				display.setCurrent(channelOne);
			else
				display.setCurrent(channelThree);
	}

}

Observe alguns screenshots do aplicativo funcionando:

Aplicativo Exemplo em Ação

Aplicativo Exemplo em Ação

Aplicativo Exemplo em Ação

Aplicativo Exemplo em Ação

Aplicativo Exemplo em Ação

Agora vamos as principais partes do código. No construtor do MIDlet são instanciados 3 Commands, cada um com seu Label, todos com o Type SCREEN e com prioridades diferentes. As prioridades diferentes são uma questão especial aqui, pois foi criado o método configureScreen que serve como um lugar comum para a configuração dos Forms utilizados. O ideal seria colocar prioridades diferentes apenas para os Commands que fazem parte da mesma instância de um determinado Displayable.

cmdGoFirstScreen = new Command("Globo", Command.SCREEN, 0);
cmdGoSecondScreen = new Command("SBT", Command.SCREEN, 1);
cmdGoThirdScreen = new Command("Record", Command.SCREEN, 2);

O método configureScreen, como já foi dito acima, serve como um lugar comum para a configuração dos Forms utilizados. O que nós podemos perceber de novidade nele é:

fm.addCommand(Command cmd)
fm.setCommandListener(this)

O primeiro comando adiciona um Command a nossa instância de Form para que o mesmo possa interagir com o usuário. O segundo comando faz com que os eventos disparados sejam capturados e tratados por nosso próprio MIDlet uma vez que ele é quem implementa a interface CommandListener. O outro método de nosso interesse é o actionListener:

public void commandAction(Command c, Displayable d)
{
	if (c == cmdGoSBT)
		display.setCurrent(channelTwo);
	else
		if (c == cmdGoGlobo)
			display.setCurrent(channelOne);
		else
			display.setCurrent(channelThree);
}

Ele é responsável por tratar os eventos capturados pelos listeners. Ele recebe dois parâmetros: um Command e seu respectivo “dono”, que sempre é uma instancia de Displayable. O resto é trivial: existe uma sequencia de testes if…else que perguntam qual o Command acionado e realizam a ação ao qual ele foi designado, que no nosso caso é simplesmente mudar de uma tela para outra.

Uma coisa interessante e importante a ser notada quando desenvolvemos para diverssos dispositivos diferentes é que a maneira como os Commands serão apresentados e por quais teclas eles serão disparados dependem do fabricante. Celulares da Motorola trantam os Commands de maneira diferente dos celulares da SonyEricsson e assim por diante.

Até a próxima.

Referências

[1] Wireless J2ME Plataform Programming

Beginning Java ME Platform.

Anúncios