网管联盟 | 网管论坛 | 网管u家 | 网管博客 | 网管软件 | 网管求职 | 小游戏 | 网管搜索 | 网管原创 | 网管聚合 | 网管读摘 | 网管焦点 | 世界素材 | 会员投稿 | 会员中心 
中国网管联盟
Windows Linux Cisco 网络技术 数据库 黑客攻防 DotNet Java PHP 认证 新闻资讯 服务器 存储资讯 网络设备 网管学堂 技术专题 焦点 网吧频道
 当前位置: > bitsCN.com > JAVA > J2ME > 无线开发 > J2ME编程实践之联网开发  

J2ME编程实践之联网开发

2006-02-28  作者:BitsCN整理  来源:中国网管联盟  点评 投稿 收藏

  由于无线设备所能支持的网络协议非常有限,仅限于HTTP,Socket,UDP等几种协议,不同的厂家可能还支持其他网络协议,但是,MIDP 1.0规范规定,HTTP协议是必须实现的协议,而其他协议的实现都是可选的。因此,为了能在不同类型的手机上移植,我们尽量采用HTTP作为网络连接的首选协议,这样还能重用服务器端的代码。但是,由于HTTP是一个基于文本的效率较低的协议,因此,必须仔细考虑手机和服务器端的通信内容,尽可能地提高效率。

网管u家www.bitscn.net

  对于MIDP应用程序,应当尽量做到:

网管论坛bbs_bitsCN_com

  1.发送请求时,附加一个User-Agent头,传入MIDP和自身版本号,以便服务器能识别此请求来自MIDP应用程序,并且根据版本号发送相应的相应。 网管论坛bbs_bitsCN_com

  2.连接服务器时,显示一个下载进度条使用户能看到下载进度,并能随时中断连接。 网管有家www.bitscn.net

  3.由于无线网络连接速度还很慢,因此有必要将某些数据缓存起来,可以存储在内存中,也可以放到RMS中。

网管u家www.bitscn.net

  对于服务器端而言,其输出响应应当尽量做到: 网管u家bitscn.net

  1. 明确设置Content-Length字段,以便MIDP应用程序能读取HTTP头并判断自身是否有能力处理此长度的数据,如果不能,可以直接关闭连接而不必继续读取HTTP正文。

中国网管联盟bitsCN.com

  2. 服务器不应当发送HTML内容,因为MIDP应用程序很难解析HTML,XML虽然能够解析,但是耗费CPU和内存资源,因此,应当发送紧凑的二进制内容,用DataOutputStream直接写入并设置Content-Type为application/octet-stream。 网管网www.bitscn.com

  3. 尽量不要重定向URL,这样会导致MIDP应用程序再次连接服务器,增加了用户的等待时间和网络流量。

网管下载dl.bitscn.com

  4. 如果发生异常,例如请求的资源未找到,或者身份验证失败,通常,服务器会向浏览器发送一个显示出错的页面,可能还包括一个用户登录的Form,但是,向MIDP发送错误页面毫无意义,应当直接发送一个404或401错误,这样MIDP应用程序就可以直接读取HTTP头的响应码获取错误信息而不必继续读取相应内容。 网管u家u.bitsCN.com

  5. 由于服务器的计算能力远远超过手机客户端,因此,针对不同客户端版本发送不同响应的任务应该在服务器端完成。例如,根据客户端传送的User-Agent头确定客户端版本。这样,低版本的客户端不必升级也能继续使用。

网管联盟bitsCN@com

  MIDP的联网框架定义了多种协议的网络连接,但是每个厂商都必须实现HTTP连接,在MIDP 2.0中还增加了必须实现的HTTPS连接。因此,要保证MIDP应用程序能在不同厂商的手机平台上移植,最好只使用HTTP连接。虽然HTTP是一个基于文本的效率较低的协议,但是由于使用特别广泛,大多数服务器应用的前端都是基于HTTP的Web页面,因此能最大限度地复用服务器端的代码。只要控制好缓存,仍然有不错的速度。

网管网www.bitscn.com

  SUN的MIDP库提供了javax.microediton.io包,能非常容易地实现HTTP连接。但是要注意,由于网络有很大的延时,必须把联网操作放入一个单独的线程中,以避免主线程阻塞导致用户界面停止响应。事实上,MIDP运行环境根本就不允许在主线程中操作网络连接。因此,我们必须实现一个灵活的HTTP联网模块,能让用户非常直观地看到当前上传和下载的进度,并且能够随时取消连接。 网管论坛bbs_bitsCN_com

  一个完整的HTTP连接为:用户通过某个命令发起连接请求,然后系统给出一个等待屏幕提示正在连接,当连接正常结束后,前进到下一个屏幕并处理下载的数据。如果连接过程出现异常,将给用户提示并返回到前一个屏幕。用户在等待过程中能够随时取消并返回前一个屏幕。 网管bitscn_com

  我们设计一个HttpThread线程类负责在后台连接服务器,HttpListener接口实现Observer(观察者)模式,以便HttpThread能提示观察者下载开始、下载结束、更新进度条等。HttpListener接口如下: 网管有家www.bitscn.net

public interface HttpListener {

void onSetSize(int size);

void onFinish(byte[] data, int size);

void onProgress(int percent);

void onError(int code, String message);

} 网管下载dl.bitscn.com

  实现HttpListener接口的是继承自Form的一个HttpWaitUI屏幕,它显示一个进度条和一些提示信息,并允许用户随时中断连接: 网管论坛bbs_bitsCN_com

public class HttpWaitUI extends Form implements CommandListener,

网管有家www.bitscn.net

HttpListener {

private Gauge gauge;

private Command cancel;

private HttpThread downloader;

private Displayable displayable;

public HttpWaitUI(String url, Displayable displayable) {

super(\"Connecting\");

this.gauge = new Gauge(\"Progress\", false, 100, 0);

this.cancel = new Command(\"Cancel\", Command.CANCEL, 0);

append(gauge);

addCommand(cancel);

setCommandListener(this);

downloader = new HttpThread(url, this);

downloader.start();

}

public void commandAction(Command c, Displayable d) {

if(c==cancel) {

downloader.cancel();

ControllerMIDlet.goBack();

}

}

public void onFinish(byte[] buffer, int size) { … }

public void onError(int code, String message) { … }

public void onProgress(int percent) { … }

public void onSetSize(int size) { … }

} 网管论坛bbs_bitsCN_com

网管有家bitscn.net

  HttpThread是负责处理Http连接的线程类,它接受一个URL和HttpListener: 网管bitscn_com

class HttpThread extends Thread {

private static final int MAX_LENGTH = 20 * 1024; // 20K

private boolean cancel = false;

private String url;

private byte[] buffer = null;

private HttpListener listener;

public HttpThread(String url, HttpListener listener) {

this.url = url;

this.listener = listener;

}

public void cancel() { cancel = true; }

网管u家u.bitsCN.com

  使用GET获取内容 网管联盟bitsCN_com

  我们先讨论最简单的GET请求。GET请求只需向服务器发送一个URL,然后取得服务器响应即可。在HttpThread的run()方法中实现如下:

中国网管联盟bitsCN.com

public void run() {

HttpConnection hc = null;

InputStream input = null;

try {

hc = (HttpConnection)Connector.open(url);

hc.setRequestMethod(HttpConnection.GET); // 默认即为GET

hc.setRequestProperty(\"User-Agent\", USER_AGENT);

// get response code:

int code = hc.getResponseCode();

if(code!=HttpConnection.HTTP_OK) {

listener.onError(code, hc.getResponseMessage());

return;

}

// get size:

int size = (int)hc.getLength();

网管朋友网www_bitscn_net

// 返回响应大小,或者-1如果大小无法确定

listener.onSetSize(size);

// 开始读响应:

input = hc.openInputStream();

int percent = 0; // percentage

int tmp_percent = 0;

int index = 0; // buffer index

int reads; // each byte

if(size!=(-1))

buffer = new byte[size]; // 响应大小已知,确定缓冲区大小

else

buffer = new byte[MAX_LENGTH];

网管有家www.bitscn.net

// 响应大小未知,设定一个固定大小的缓冲区

while(!cancel) {

int len = buffer.length - index;

len = len>128 ? 128 : len;

reads = input.read(buffer, index, len);

if(reads<=0)

break;

index += reads;

if(size>0) { // 更新进度

tmp_percent = index * 100 / size;

if(tmp_percent!=percent) {

percent = tmp_percent;

listener.onProgress(percent);

}

}

}

if(!cancel && input.available()>0) // 缓冲区已满,无法继续读取

listener.onError(601, \"Buffer overflow.\");

if(!cancel) {

if(size!=(-1) && index!=size)

listener.onError(102, \"Content-Length does not match.\");

else

listener.onFinish(buffer, index);

}

}

catch(IOException ioe) {

listener.onError(101, \"IOException: \" + ioe.getMessage());

}

finally { // 清理资源

if(input!=null)

try { input.close(); } catch(IOException ioe) {}

if(hc!=null)

网管朋友网www_bitscn_net


try { hc.close(); } catch(IOException ioe) {}

}

}

网管u家www.bitscn.net

网管朋友网www_bitscn_net

  当下载完毕后,HttpWaitUI就获得了来自服务器的数据,要传递给下一个屏幕处理,HttpWaitUI必须包含对此屏幕的引用并通过一个setData(DataInputStream input)方法让下一个屏幕能非常方便地读取数据。因此,定义一个DataHandler接口: 网管u家www.bitscn.net

public interface DataHandler {

void setData(DataInputStream input) throws IOException;

} 网管联盟bitsCN@com

  HttpWaitUI响应HttpThread的onFinish事件并调用下一个屏幕的setData方法将数据传递给它并显示下一个屏幕:

网管bitscn_com

public void onFinish(byte[] buffer, int size) {

byte[] data = buffer;

if(size!=buffer.length) {

data = new byte[size];

System.arraycopy(data, 0, buffer, 0, size);

}

DataInputStream input = null;

try {

input = new DataInputStream(new ByteArrayInputStream(data));

if(displayable instanceof DataHandler)

((DataHandler)displayable).setData(input);

else

System.err.println(\"[WARNING]

网管u家www.bitscn.net

Displayable object cannot handle data.\");

ControllerMIDlet.replace(displayable);

}

catch(IOException ioe) { … }

}

网管有家www.bitscn.net

网管u家u.bitsCN.com

  网管联盟bitsCN_com

网管u家u.bitscn@com

[1] [2] 下一页  

网管u家u.bitsCN.com

TAGs开发   联网   实践   编程   连接   服务器   HTTP   if   MIDP    
 上一篇:使用Yahoo Service实现天气预报   下一篇:J2ME中使用Socket开发联网程序
相关文章列表
J2ME编程实践之联网开发 评论:
loading.. 评论加载中…
评论:请自觉遵守互联网相关政策法规,评论不得超过250字。

验证码: 注册用户
本类热门排行:
1.Java中利用通讯API编写短信软件
最新推荐文章:
1.J2ME中使用缓存将屏幕内容存储为Image
2.Push信息自动启动JAVA移动程序
3.用J2ME为手机DIY一个顶牛牛游戏
4.浅析手机游戏开发与应用的发展趋势
5.确保J2ME无线移动商业应用程序的安全性
6.详解面向3G的传输网络
7.无线通信技术CDPD vs GPRS大比拼
8.当Java遇上WAP时
9.无线应用系统
10.J2ME学习--了解MIDlet的生命周期(图)
网管论坛交流:
·大家来开心一下吧---看了会很开心的东西-
·中国人不可不知道的知识
·@@小鹏◎◎小鹏同志与某位女明星亲密接触
·◎◎小鹏◎◎发现不明生物,居然正在交配
·[图文]^^^版主是什么?????
·泡论坛的女人是好女人
·做个“水性杨花”的女人
·献给mm俱乐部的所有mm
·深圳一集团企业电脑基础应用培训教程
·■■■■十一遊玩照■■■■■