Comunicação paralela com servidor em aplicações J2ME com HttpConnection usando componente reutilizável
Estarei apresentando neste artigo uma das melhores práticas para fazer a comunicação com o servidor usando HttpConnection em aplicações móveis J2ME, iniciando a conexão com apenas uma linha de código. Ensinarei a criar uma classe reutilizável responsável por toda a comunicação com o servidor, deixando sua aplicação mais lógica, enxuta e melhor estruturada. Você poderá inclusive disparar várias conexões paralelas, e ainda assim, ao receber os dados, terá o controle de qual conexão se trata. Poderá facilmente cancelar a requisição, caso queira. Se aplicar as informações deste artigo em seus projetos, você passará a se preocupar apenas com as regras de negócio, apenas trabalhará com a informação em si, despreocupando-se com quaisquer detalhes quanto à comunicação com o servidor.
No final do artigo você poderá baixar os arquivos do componente de conexão reutilizável, bem como uma aplicação de exemplo que mostra como usar o componente corretamente.
Explicarei brevemente, de início, o funcionamento básico. Como sabemos, uma requisição HttpConnection deve operar numa thread separada, caso contrário a aplicação ficaria travada enquanto sua aplicação estivesse se comunicando com o servidor.
Usuário entra na aplicação, e a tela é mostrada. Usuário clica em Baixar Imagem. Um diálogo é mostrado permitindo que o usuário cancele a requisição a qualquer momento. A tela chama um método estático do componente de requisição, passando a URL e outras informações, iniciando a requisição, e fica aguardando o término. Essa tela implementa o listener que será executado quando a requisição estiver concluida. Quando a requisição estiver concluída, o componente chama o listener na tela, informando que a requisição terminou, e passando os dados. A tela mostra os dados/imagem, e oculta o diálogo de cancelamento da requisição que estava ativo. O usuário fica feliz vendo a imagem vinda do site.
O método estático do componente que inicia a requisição, pede vários parâmetros, como a URL, se é POST ou GET, os parâmetros, o timeout, o objeto que está implementando o listener de resposta da requisição que no nosso exemplo é a própria tela, o id da conexão para que se possa identificá-la facilmente na resposta do listener. Quando esse método é chamado, ele devolve uma instância do componente, e já inicia a thread de conexão por conta própria. É aconselhável que a tela guarde a referência ao componente de requisição, para o caso de o usuário desejar cancelar a requisição. Enquanto a requisição está ativa, fica também ativa um diálogo permitindo que o usuário cancele a conexão. A thread da requisição envia/recebe todos os dados do servidor, e quando termina, chama um listener na tela que iniciou a conexão, avisando-a de que a conexão terminou, devolvendo os dados retornado pela requisição à tela para serem tratados.
Seguindo o conceito acima, criaremos as seguintes classes/interface:
Aplicacao - MIDlet responsável por iniciar a tela.
Tela - Tela que extende a classe Form que será mostrada ao usuário. A tela que será responsável tanto por iniciar a conexão, quanto por receber os dados retornados pela requisição e fazer algo com eles.
RequisicaoHttp - Classe que extende a Thread, e será responsável por todo o processo de comunicação com o servidor, controle de erros, timeout, leitura e envio de dados etc. No final da requisição essa classe chamará o listener da tela, avisando-a de que a requisição terminou. Para ficar mais fácil de usar nosso componente, criaremos um método estático que criará um objeto dessa classe, preparará as propriedades, e iniciará a conexão, de forma que a tela tenha que usar apenas uma linha de código para fazer uma requisição.
ConexaoHttpListener - Interface que terá um método para ser implementandos pela tela. Esse método na tela será chamado quando a requisição for finalizada, para que a tela saiba que a requisição terminou e faça algo com os dados retornados.
Exemplo de início de uma requisição depois que estiver tudo pronto:
public void commandAction(Command comando, Displayable tela) {
if (comando == comandoInicia)
RequisicaoHttp requisicaoHttp = RequisicaoHttp.iniciaRequisicao(”http://devmobile.blog.br/feed/”,
“parametro1=bh”, RequisicaoHttp.POST, this, 0, 20000);
}
Esse método estático cria uma instância do componente, define suas propriedades passadas como parâmetro, e inicia a thread de requisição. Por fim, retorna o próprio objeto instanciado, caso a tela queira guardá-lo numa variável.
Para que a tela receba a resposta da finalização da conexão ela deve implementar a interface que criaremos HttpReqListener. Essa interface terá apenas um método declarado, que informará a tela se a requisição ocorreu tudo bem, os dados retornados pelo servidor e a mensagem de erro caso tenha ocorrido algum erro.
Veja como ficaria um exemplo de implementação desse listener:
public void requisicaoConcluida(boolean sucesso, String mensagemErro, byte[] dadosRecebidos, int id) {
if (sucesso) {
String dados = new String(dadosRecebidos);
textField.setString(dados);
} else {
Alert alert = new Alert(mensagemErro);
AplicacaoMIDlet.app.display.setCurrent(alert, this);
}
}
E se quiséssemos permitir que o usuário cancele a requisição depois que ela tiver começado, garantindo que todos os objetos e threads serão fechados corretamente? Isso é fácil, pois o componente está preparada para isso. Basta chamar o método cancelaRequisicao() do objeto da requisição. Para isso, é recomendável que antes de iniciar a requisição, seja mostrada um diálogo ao usuário, avisando-o para aguardar a requisição, com um comando para o caso de ele querer cancelar. Quando esse comando for clicado, seria executado algo como:
public void commandAction(Command comando, Displayable tela) {
if (comando == comandoCancelar) {
//Usuário pressionou o comando Cancelar, na tela de cancelamento de requisição.
//Cancela a requisição.
requisicaoHttp.cancelaRequisicao();
//Mostra a tela padrão, removendo a tela de diálogo.
AplicacaoMIDlet.app.display.setCurrent(this);
}
}
E como poderíamos fazer 3 conexões paralelas, ao mesmo tempo, que retornem informações diferentes com tratamentos diferentes em suas respostas? Quando iniciamos as 3 requisições, definirmos um ID diferentes para cada uma. Esse ID ajudará a identificar a requisição na resposta. Veja:
public void commandAction(Command comando, Displayable tela) {
if (comando == comandoInicia) {
//Requisição do HTML com previsão do tempo, ID = 0
RequisicaoHttp requisicaoHttp = RequisicaoHttp.iniciaRequisicao(”http://devmobile.blog.br”,
null, RequisicaoHttp.POST, this, 0, 20000);
//Requisição do XML com opções, ID = 1
RequisicaoHttp requisicaoHttp = RequisicaoHttp.iniciaRequisicao(”http://devmobile.blog.br”,
null, RequisicaoHttp.POST, this, 1, 20000);
//Requisição do logo, ID = 2
RequisicaoHttp requisicaoHttp = RequisicaoHttp.iniciaRequisicao(”http://devmobile.blog.br”,
null, RequisicaoHttp.POST, this, 2, 20000);
}
}
Para identificar a resposta, que poderá vir sem ordem:
public void requisicaoConcluida(boolean sucesso, String mensagemErro, byte[] dadosRecebidos, int id) {
if (sucesso) {
if (id == 0) { //HTML
String html = new String(dadosRecebidos);
textField.setString(dados);
} else if (id == 1) { //XML
String xml = new String(dadosRecebidos);
textField.setString(dados);
} else if (id == 2) { //Imagem
Image image = Image.createImage(dadosRecebidos, 0, dadosRecebidos.length);
insert(0, new ImageItem(null, image, Item.LAYOUT_CENTER, “Img”, Item.PLAIN));
} else
} else {
Alert alert = new Alert(mensagemErro);
AplicacaoMIDlet.app.display.setCurrent(alert, this);
}
}
Pronto! Facilmente criamos uma requisição totalmente responsável, com controle de timeout, controle de erros, definição de cabeçalhos, etc.
Baixe o exemplo completo, bem comentado, que mostra como usar corretamente o componente, como controlar os erros, como permitir que o usuário cancele a requisição, e muito mais.
Exemplo de requisição Http em J2ME HttpConnection
Baixe os 2 arquivos do componente e use em suas aplicações.
Componente reutilizável para conexão em J2ME usando HttpConnection
Se alguém tiver mais alguma idéia para melhorar o componente, pode postar aqui.
Bons códigos!
Sobre o Autor
Nelson é desenvolvedor há 12 anos. Hoje desenvolve aplicações Web e Móveis na Abacomm Brasil cuidando do desenvolvimento server-side J2EE, banco de dados, design de aplicações móveis, e desenvolvimento móvel usando várias plataformas como BlackBerry, J2ME, FlashLite, Android, etc. Para conversar com o autor use o e-mail, MSN e GTalk npereirajr@gmail.com.

Renato Custódio:
Muito bom o artigo, parabéns!
17 Abril 2008, 10:17 amWalter Alves Chagas Junior:
Parabens colega. Seu blog é tudo de bom!!!!
17 Abril 2008, 6:55 pmBarreto:
Fizeste um excelente artigo. Vai ajudar muita gente a entender sobre j2me Httpconnection.
Valeu
18 Abril 2008, 10:21 amAntônio Júnior:
Excelente artigo, tirou muitas dúvidas que eu tinha com relação ao HttpConnection. Agora se não for pedir muito, será que você poderia diponibilizar a aplicação servidora que você usou no exemplo?
Abraços!!
18 Abril 2008, 6:39 pmJavaME: Generic Connection Framework « wpjr2’s Weblog:
[…] DevMobile […]
5 Maio 2008, 11:26 amONILSON:
Gostei muito do seu artigo,sou iniciante em j2me,atualmente estou quase fechando um projeto com a universidade do meu estado para desenvolver um sistema usando j2me,bom eu gostaria de saber se existe mais fontes de informação sobre a tecnologia j2me na internet ( sites brasileiros)…
abraços valeu !!!
20 Maio 2008, 6:36 pmNelson Pereira Junior:
Tem sim, mas não são específicos. Vou citar 2: javafree.com.br e guj.com.br.
21 Maio 2008, 7:27 amCláudia:
Muitooooo bom! Eu estava justamente precisando de uma explicação assim sobre requisição. Estou começando a estudar sobre jme, e achei o artigo muito esclarecedor!
Obrigada!
21 Maio 2008, 9:39 pmCaio:
Muito bom kra, estou fazendo uma aplicação em j2me, esse post vai me ajudar muito…uma sugestão para proximos post ( uma classe para ler arquivos xml em j2me)
26 Maio 2008, 9:09 pmsobrinho:
parabens pelo tutorial de alto nivel.
Preciso fazer o caminho inverso, enviar strings para o servlet via request.getParameter() e armazenar em banco.
qual a melhor abordagem no midlet pois no servlet ta relativamente facil.
muito obrigado e parabens.
31 Julho 2008, 7:11 amsobrinho:
parabens,
embora aborde de forma profissional um exemplo trivial vc mostrou muito bem a importancia dos patterns.
sugiro extender ou reescrever um exemplo que aborde threads automaticas pois e cada vez mais comuns aplicativos operando continuamente em threads independentes tais maquinas conversando com maquinas.
abs
1 Agosto 2008, 8:35 pmAusli Sena:
Você foi sensacional com seu exemplo, falta apenas o passo a passo do server com JDBC… Abraços
5 Janeiro 2009, 1:01 pmTecoAvila:
Show de Bola, excelente artigo !!
Obrigado.
27 Março 2009, 2:06 pmMobilidade é tudo » Arquivo do Blog » Facilitando a comunciação HTTP no Java ME:
[…] acaso, descobri algumas linhas de códigos que podem facilitar nossa vida, e muito. O post “Comunicação paralela com servidor em aplicações J2ME com HttpConnection usando componente reutil…“, do blog DevMobile, fala sobre duas classes utilitárias que permitem o acesso a um servidor […]
15 Julho 2009, 7:33 pmMarcos:
Isso é gambiarra! Aprende a usar Web Services!
29 Setembro 2009, 8:03 pmJUNIOR FAE:
Realmente teu artigo esta muito bom. Gostaria de saber se vc ja implementou alguma coisa usando um http://ftp. Pegando um arquivo do celular e enviando para um servidor ftp e na mesma conexao baixando outro.
Abraços e parabéns!
JUNIOR FAE
6 Outubro 2009, 3:10 pmNelson:
FTP? Não! Não faz qualquer sentido uma aplicação se comunicar com um servidor via http://FTP. Se você precisa enviar dados para um servidor, você deve criar uma aplicação no lado servidor, em PHP ou Servlet, para enviar e receber os dados do JME e gravar num banco, por exemplo.
11 Dezembro 2009, 8:18 amNelson:
Marcos, isso não é gambiarra. Usar WebServices não é recomendado usar em aplicações móveis. É custoso para o servidor e extremamente custoso para o mobile. WebServices foi concebido para ser usado num modelo de aplicações B2B, não B2C como é o caso de uma aplicação móvel.
11 Dezembro 2009, 8:23 amValdir:
Parabéns, excelente artigo. Irá ajudar muito quem precisa, me ajudou bastante.
31 Janeiro 2010, 3:11 pm