Serializando J2ME

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (0)  (0)

Este tutorial descreve os passos para utilização da persistência em dispositivos móveis, a API Record Management System (RMS) do MIDP.



Autor : Roberto Martins

robertomartins@pop.com.br

Este tutorial descreve os passos para utilização da persistência em dispositivos móveis, a API Record Management System (RMS) do MIDP de uma forma que traga uma certa simplicidade para os desenvolvedores construir suas aplicações.

Introdução

Desenvolver sistemas para dispositivos móveis requer mais que um amontoado de códigos. É importante saber como armazenar dados de forma simples nestes aparelhos, para um busca rápida de dados, por exemplo.Assim vendo inúmeros pedidos de iniciantes no desenvolvimento J2ME, resolvi participar desta oportunidade com este tutorial com um exemplo simples de serializar e armazenar objetos no um tanto complicado “RecordStore” Com este tutorial espero trazer a simplicidade do desenvolvimento aos iniciantes.

Apresentação

Antes de entender a serialização vamos então aos requisitos para o desenvolvimento, IDE's, SDK's entre outros.

Podemos começar inicialmente fazendo o download do JDK no site da SUN, após concluído download efetue a instalação.Após o término da instalação configure o CLASSPATH corretamente para disponibilizar as APIs padrões do Java para sua aplicação. Algo como CLASSPATH=C:\j2sdk(versao)\lib;.

Faça o download do WTK no site da SUN, após concluído download efetue a instalação no diretório padrão “\WTK(versão)”.

Faça o download do Eclipse em http://www.eclipse.org/downloads/index.php, dê preferência à versão 3.0, pois é a versão em que o plugin J2ME funciona corretamente.Após download descompacte o arquivo na raiz do diretório principal de seu micro(\eclipse).

Faça o download também do plugin J2ME para o Eclipse em http://www.plugineclipse.org. Após download descompacte arquivo em diretório temporário, neste diretório obtenha dentro da pasta “plugin” os arquivos existentes copie estes para a pasta plugins do diretório do Eclipse.

Finalmente Inicie o Eclipse com o “Eclipse.exe” existente no diretório eclipse, inicialmente o eclipse deverá solicitar a criação de um diretório de trabalho “workspace”, mantenha este diretório junto ao diretório \eclipse.

Com o IDE aberto, teremos uma tela de boas vindas do eclipse, feche a tela de boas vindas, selecione na barra de tarefas “Window >> Open Perpective >> Java, assim teremos a perspectiva que facilitando a visualização de pacotes.

Após este selecione “Window >>> Preferences, clique e “Plataform Components” na janela direita clique em “Wireless Toolkits >> Add Wireless Toolkit”.
            Indique o caminho onde foi efetuada a instalação do WTK. 
Finalmente reinicie o Eclipse, pronto assim teremos o nosso plugin J2ME perfeitamente instalado. Vamos seguir para a criação da nossa Agenda.

Agenda J2ME

  1. Criando projeto

Crie um novo projeto J2ME (File >> New Project >> J2ME >> J2ME Midlet Suíte >>  Next) com o nome de Agenda.

Crie os pacotes para a aplicação “br.com.webmobile”, clique com o direito no folder “src” e crie o pacote descrito acima.

Criar também os pacotes “entity, midlet, rms e view”, abaixo do pacote criado anteriormente.

Dentro do pacote “entity” criar a Midlet principal do aplicativo com o mesmo nome – Agenda.Java. (File >> New >> Other >> J2ME >> J2ME Midlet).

Para facilitar faça download do projeto em http://www.portalwebmobile.com.br/...

Copie os arquivos para o seu projeto

Vamos agora ao que interessa. A API RMS está localizada no pacote ax.microedition.rms e possui as seguintes classes e interfaces: RecordStore, RecordEnumeration, RecordComparator, RecordFilter e RecordLister. Um RecordStore é criado por um MIDlet, q por suas vez faz parte de uma suite de MIDlets. Isso significa, que para o MIDP 1.0, suites de MIDlets nao conseguem acessar RecordStores de suites diferentes, algo que já é diferente para o MIDP 2.0.

Vejamos algumas regras para o uso dos RecordStores:

* Os nomes dos RecordStores são Case Sensitive, devem ter entre 1 e 32 caracteres Unicode.
* Quando uma suite de MIDlets é removida, todos os RecordStores associados à ela são removidos.

Como abrir e criar RecordStores.

Código:

Este trecho de código faz parte da classe BaseRMS.

/**
 *
Responsável
pela abertura do RecordStore para leitura e gravação.
 * @throws Exception - Caso
algum erro ocorra.
 */
public void open() throws Exception {
      try {
          recordStore = RecordStore.openRecordStore(this.rmsName,true);
      } catch (Exception e) {
            throw new Exception(this.rmsName+"::open::"+e);
     
}
}

/**
 *
Responsável
pelo fechamento do RecordStore.
 * @throws Exception - Caso
algum erro ocorra.
 
*/
public void close
() throws Exception {
      if (recordStore != null) {
            try {
                  recordStore.closeRecordStore();
            } catch(Exception e) {
                  throw new Exception(this.rmsName+"::close::"+e);
           
}
      }
}

Como podemos ver, o método openRecordStore irá abrir o RecordStore de nome passado no atributo rmsName da classe BaseRMS do nosso projeto; se este já estiver aberto por outro MIDlet, uma referência será retornada. Se ele não existir e o segundo parâmetro for true, o RecordStore é criado. Se fosse falso, um RecordStoreException seria lançado.

Ao adicionar os dados ao RecordStore, um ID é retornado. Esse ID é um numero sequencial que inicia do número um.
Para se remover um RecordStore, usa-se o método estático deleteRecordStore. Antes de fazer a remoção, o RecordStore deve estar fechado, como foi feito no comando: recordStore.closeRecordStore();

Gravando informações.

Código:

Este trecho de código faz parte da classe PersistenceContato que estende a classe BaseRMS.

protected void storeData() throws Exception {
      int
id = this.getRecordStore().addRecord(this.data,0, data.length);
     
this.close();
}

Alguns outros métodos da classe RecordStore são:

* getLastModified: informa a data (retorna um long) da últuma modificação;
* getSize: retorna o tamanho ocupado (em bytes);
* getSizeAvailable: retorna o tamanho disponível (em bytes);
* getVersion: retorna o número da versão. Para cada operação realizada (inclusão, alteração, deleção) é atualizado o número de versão.
* addRecordListener e removeRecordListener: para gerenciar os eventos gerados com o RecordStore
* listRecordStores: método static que retorna um array de Strings com os nomes de todos os RecordStores dentro de uma suite de MIDlets.

Vamos então ver como foi implementado a persistência da nossa agenda, inicialmente foi criada uma classe abstrata base para a persistência, a classe “BaseRMS.java”  este classe defini a criação do RecordStore, abertura e fechamento do Record criado pela nosso aplicativo. Posteriormente foi criada a classe “PersistenceContato.java”, esta classe estende a classe “BaseRMS.java”  que possui ainda os métodos abstratos que devem ser subscritos pela classe que ira estende-la. Isto não e obrigatório, mas e interessante que se tenha uma classe que defina a assinatura dos métodos da persistência.

Métodos que devem ser subscritos na classe PersistenceContato.

Código:

Este trecho de código faz parte da classe BaseRMS.

protected abstract void loadData() throws Exception;
protected
abstract void storeData() throws Exception;
protected
abstract void updateData(int index) throws Exception;
protected
abstract void removeData(int index) throws Exception;
protected abstract void loadIndexData(int index) throws Exception;

Apresentamos no quadro 2 o método “storeData” da classe PersistenceContato, este subscrito e incluído o array de bytes “data” como atributo da classe, temos nesta classe também o atributo que damos nome ao RecordStore criado “RMS_CONTATO” e ainda um array de String “lista” para capturar o nome de cada contato que será visualizado na listagem da camada de apresentação.

Criando a camada de persistência.

Código:

Este trecho de código faz parte da classe PersistenceContato.

public class PersistenceContato extends BaseRMS{
      private
final static String RMS_
CONTATO = "CONTATO";
      private
byte[]
data;
      private String[]
lista
;
      public PersistenceContato(byte[] data
) {
            super(RMS_CONTATO
);
            this.data = data
;
            try {
                  this.open();
                  this.storeData();
            } catch (Exception e) {
                 
e.printStackTrace();
            }
      }

Bom, mas vamos mais fundo no assunto, o que precisamos entender e como transformar nossos dados em bytes de forma simples, para que possamos efetuar leituras e buscas no RecordStore.

Assim criamos uma interface “Serializable.java” que determina novamente a assinatura dos métodos e que seja efetuada a subscrição dos mesmos. Gostaria de esclarecer que estas classes foram criadas para facilitar a implementação de uma aplicação de aplicação de maior porte, pois este tutorial deve servir para que os leitores possam criar aplicações que sejam de seu interesse, e não somente uma simples agenda. Ainda que estas classes básicas servem para aplicações de sincronismo e leitura em desktop com JSE.

Vamos a um exemplo de um software de força de vendas ou controle de estoque, onde e preciso enviar os dados para uma base de dados externa ao móbile tendo em vista que os dispositivos atuais possuem pouca capacidade de armazenamento e preciso providenciar uma forma de sincronismo via http, por exemplo, enviando a um servidor em forma de bytes para que este fique com a carga de processamento dos dados,  tendo em vista que nossa aplicação tenha a melhor performance em sua utilização.

Assim estas classes devem servir de base para a criação de um aplicativo que se encarregue de processar estas informações.

 Vamos seguir com nosso tutorial, assim foi criada a classe “Contato.java”  que implementa a interface “Serializable.java” e assim implementamos os métodos de forma a serializar os atributos da classe.

Os métodos “serializar e deserializar” são mostrados no quadro 5, utiliza-se  ByteArrayOutputStream e DataOutputStream para a serialização de forma que todos os atributos tenham sidos transformados em bytes, o método retorna o array dos mesmos. Utilizamos “writeUTF” para a leitura de Strings que foram as formas dos nossos atributos, mas e possível criar atributos com outros variações de primitivas, “int , boolean , long , Char , etc..(veja API de DataOutputStream).

E para deserializar utilizamos ByteArrayInputStream e DataInputStream e assim deserializamos os dados e transformamos em Objetos para facilitar a manipulação.

Implementando “Serializable.java”.

Código:

Este trecho de código faz parte da classe Contato.

/**
*
Responsável
por serializar o objeto Contato, transformar em um array de
 * bytes
para que este seja armazenado em um RecorsStore.
 *
 * @return
byte[] data - Os dados do objeto
Contato serializado, um
rray    de
bytes
.
 * @see DataInputStream para
serializar outros tipos primitivos de dados.
 * @throws IOException, InterruptedException
 */
public byte[]
serializar() throws IOException, InterruptedException {
      ByteArrayOutputStream bOut = new ByteArrayOutputStream();
      DataOutputStream dOut = new DataOutputStream(bOut);
      dOut.writeUTF(this.
nome
);
      dOut.writeUTF(this.telefone
);
      dOut.writeUTF(this.email);
     
//retorna o array de dados
.
      return bOut.toByteArray();}

/**
*
Responsável
pela deserialização do objeto Contato, transformar em um
bjeto
 * completo
para que este possa ser manipulado normalmente dentro do
plicativo
.
 *
 * @see DataInputStream
para
serializar outros tipos primitivos de dados.
 * @throws IOException, InterruptedException
 */
public void deserializar(byte[] data
) throws IOException,    InterruptedException {
      ByteArrayInputStream bIn = new ByteArrayInputStream(data);
      DataInputStream dIn = new DataInputStream(bIn);
      this.
nome
= dIn.readUTF();
     
this.telefone = dIn.readUTF();
      this.email = dIn.readUTF();
}

Então estamos com as classes para persistência definidas, agora poderemos trabalhar na implementação do código na apresentação e manipulação destes dados.

Vamos inserir os dados via UI com usuário, a nosso Midlet deverá inicialmente quando de sua abertura chamar uma listagem com o nome dos contatos armazenados no RecordStore, não existindo contatos armazenados pode ainda mostrar um alerta ao usuário.

Assim na classe principal “Agenda.java” o método “startApp()” (quadro 6)  deve efetuar a chamada de uma lista com estes contatos, para isto foi criada a classe “ListarContatos.java” que e instanciada quando se inicia a nossa Midlet, a chamada do método “listaContatos()” (quadro 7) efetua as chamadas de outros métodos responsáveis pela leitura dos dados de contatos armazenados no RecordStore.

Código:

Este trecho de código faz parte da classe Agenda

protected void startApp() throws MIDletStateChangeException {
     
//iniciar aplicativo com a lista de contatos existentes
      //
cria uma instância da classe ListarContatos.
     
lista = new ListarContatos();
      //chamada do método listarContato, efetua o carregamento dos
        contatos cadastrados.
     
lista.listaContatos();
      lista.addCommand(this.novoCmd); //adiciona o botão
novo contato a        listagem de contatos.
      lista.addCommand(this.detalheCmd); //adiciona o botão
detalhe a        listagem de contatos.
      lista.addCommand(this.infoCmd); //adiciona o botão info a listagem
       de contatos.
      lista.setCommandListener(this); //adiciona o Listener a listagem
       para os eventos dos botões.
      Display.getDisplay(this).setCurrent(lista
.retornaTela());
}

Código:

Este trecho de código faz parte da classe ListarContato

/**
 *
Responsável
por efetuar as chamadas dos metodos para a
 * criação
da listagem de contatos.
 */
public void listaContatos() {
      //cria a instância da classe PersistenceContato     
        PersistenceContato
contatos = new PersistenceContato();
      // recebe a lista
com o nome dos contatos cadastrados no         RecordStore.
      list =
contatos.listaContatos();
      // carrega a
lista de nomes de contatos neste List.
      this.carregaListaContatos();
}

Seguindo o fluxo da implementação vamos até a classe “PersistenceContato.java”  para verificar o método “listarContato()” (quadro 8) , que em sua implementação efetua a chamada do método “loadData()” (quadro 8), este método e responsável por efetuar a leitura dos dados de cada contato armazenado.

Código:

Este trecho de código faz parte da classe PersistenceContato

public String[] listaContatos()    {
      try {
            this.loadData();
      } catch (Exception e) {
            e.printStackTrace();
      }
      return
lista;
}

protected void loadData() throws Exception {
      RecordEnumeration num;
      int cont = 0;
      num = this.getRecordStore().enumerateRecords(null,null,false);
     
lista = new String[num.numRecords()];
      while(num.hasPreviousElement())    {
           
data
= num.previousRecord();
           
Contato.getInstance().deserializar(data);
            this.lista[cont] =
Contato.getInstance().getNome();
            cont++;
      }
      this.
close
();
}

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Ficou com alguma dúvida?