本文主要介绍midp的基本概念。因为注意到国内的java站点介绍j2me的还比较少,所以就写了本文。如果有什么不妥的地方,欢迎您email我,讨论商榷。
如您要转贴,请保留原出处,并勿做删改。谢谢。
本文是“j2me的基本介绍”系列文章的后续,在基础篇中,将主要介绍midp的组织结构,和midlet的lifecycle,并通过一个实例,编写一个midlet程序。
本文的内容如下:
1。midp中的类
2。midlet的lifecycle
3。a midlet program
4。.jar 与.jad
5。put it together.
-----------------
0。mid(mobile information device )的特性。
由于mid这类设备,在屏幕、内存、处理器等问题上有诸多限制,在手机或是pda等mid上开发应用程序必须要考虑一些技术上的特殊点。
下面给出一些设备的特性:
显示(display):96×54 (最小屏幕尺寸),1bit(最小色深,单色)
输入设备: “one-handed keyboard”(指itu-t手机键盘)“two-handedkeyboard” (指标准键盘,即qwerty键盘)触摸屏。
内存:128kb-midp组件。
8kb-应用程序生成的persistent data(关于persistent data,我会在将来讲rms时,详细说明,这里有个概念就行了)
32kb-java runtime环境。
网络: 双向的,无线的,间断的,带宽有限的网络
内核(kernel):至少要能运行kvm
还有很多软件上的特性,如读写non-volatile内存(就是掉电后不会失去内容的内存,如flash)。读写无线设备接口的api,等等。
除了上诉技术上的问题,你还得注意你的程序要简单易用且稳定可靠。尤其是可靠性,你开发的是通讯设备,用户是不能忍受程序有什么纰漏而影响到通话的。 你要牢记这一点。
1。midp的类库
如前文所述,sun在cldc之上定义了midp(mobile information device pro-file)层,用以提供对ui、永久存储介质(persistinace storage)、和网络等更高层的(相对于cldc)支持。那么,让我们来具体看看midp的类库。midp由四个javax.microedition包组成,它们包括:
javax.microedition.rms—–关于永久存储介质(注:rms是record management system的缩写)
javax.microedition.midlet–定义了midlet的框架,以及midlet与环境的交互。
javax.microedition.io——网络支持
javax.microedition.lcdui—ui(user interface)(注:ui分为high-level和low-level两种api。)
注:如果在加上语言和实用类(java.lang和java.util)则有六个。
2。midplet
midp中定义的应用程序称为midlet。任何一个midlet都是javax.microedition.midlet.midlet的子类,必须继承自javax.microedition.midlet.midlet。这很显而易见。我们在j2se中编过applet,applet就必须继承自java.applet.applet。是不是很类似。请看下图,说明了midlet的继承体系。
┌─────────────────┐
│javax.microedition.midlet.midlet│
└─────────────────┘
↓
┌──────┐
│ mymidlet │
└──────┘
图1 midlet的继承体系
3.编译一个简单的midlet,并执行。
下面我先给出一个简单的helloworld程序,然后进行分析。
===============================源程序==================================
//helloworld.java,一个最简单的midlet程序。
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class helloworld extends midlet implements commandlistener {
private command exitcommand;
private textbox tb;
public helloworld(){
exitcommand =new command("exit",command.exit,1);
tb =new textbox("hello midlet","hello,world!",15,0);
tb.addcommand(exitcommand);
tb.setcommandlistener(this);
}
protected void startapp(){
display.getdisplay(this).setcurrent(tb);
}
protected void pauseapp(){
}
protected void destroyapp(boolean u){
}
public void commandaction(command c,displayable d){
if (c ==exitcommand){
destroyapp(false);
notifydestroyed();
}
}
}
===============================源程序完================================
该程序显示“helloworld”字符串。程序本身非常简单,如果你熟悉javaapplet编程的话,你会发现与applet很类似。好,我们先把它编译,运行一下看看。
编译之前的准备:
硬件:因为是java,所以内存最少有128mb以上,cpu最好是pii或更高。
平台:最好是win2000,win98的中文显示会有问题,解决起来比较麻烦。linux我没有试过,英文我想应该都没什么问题,但中文显示我估计可能会有些麻烦如果有试过的朋友,请一定告诉我。
sdk:你需要有(下述软件都可在sun网站上免费下载)
1。java 2 sdk 1.3或以上。
2。j2me wireless toolkit 1.0.3
以下可选:
sun的ide:forte for java。(如果你上的是宽带,或不是自己付网费的话 ^-^)
下载好后,先安装jdk1.3,(具体关于安装和设置我就不详述了,想来大家都很清楚。如果您不清楚,请参考相应资料。)在安装j2me wireless toolkit 1.0.3,它会自动找到您的jdk1.3,并作相应设置。如果您不用命令行的话,环境变量也不用设置直接可在图形界面上运行,非常方便。关于环境变量的设置请自己参考手册。
编译的步骤:
如果你按上述已经安装好jdk和j2mewtk,请按以下步骤编译,实际上是非常简单的:
(注:下述默任jdk安装在c:\jdk1.3,j2me wirless toolkit 安装在c:\j2mewtk\)
1. 开始->程序->j2me wirless toolkit 1.0.3->ktoolbar
2. 这时会出现"j2me wirless toolkit"窗口,点"new project"按键,在projectname项填:helloworld;在midlet class name填:helloworld。点击creat project。
3. 这时会出现setting for project对话窗,采取默认即可。点击ok。
4. 这时请注意,因为没有down sun的ide,所以你要手工把你事先编辑好的helloworld.java放置在c:\j2mewtk\apps\helloworld\src\目录下。这时,按“build” 键,如果一切正常,将提示编译完毕。这时在device下拉选单中选定你想要的设备,再按“run”键,终于大功告成。你可以多选几个不同设备,感受一下,不错吧。
4.midlet的lifecycle
在上一节里,我们已经成功编译并运行了一个简单的midlet程序。现在,让我们来分析一下midlet的结构,和其lifecycle。
通过对源程序的观察,我们可以发现midlet程序的运行是由startapp(),pauseapp()和destroyapp()这3个方法控制的。它们在javax.microedition.midlet.midlet中定义。所有的midlet都必须有这3个方法。顾名思义startapp()方法用于标志一个midlet的开始执行。不过这里要注意一点,与helloworld程序的constrctor不同。startapp()不光是在初始化完一个midlet时执行,只要该midlet被从paused态激活(变为active态),startapp()就会被调用。pauseapp()方法标志着midlet进入pause态。而destroyapp()方法标志着midlet进入destroyed态。(注意:这里严格的讲应该说成:方法被调用并成功返回标志着…)
看完上面的描述,大家可能会满头雾水,又是方法,又是状态的,什么跟什么吗?这还得从midlet的执行机制讲起。midlet的执行是通过application managementsoftware来管理的。这玩意儿是处在操作系统级别上来管理midlet运行的底层机制的总称,所谓midlet state(midlet状态)就是它一手操办,控制管理的。midletstate确保了ams随时可以消灭该midlet,同时midlet也有办法进入一个pause态,并可再次激活。midlet state 分为paused,active,destroyed三种。当ams创生一个新的midlet实体时,对应于midlet,表现为其constructor被调用,进入paused状态。当所有的准备工作都做好后,ams判断现在midlet可以运行了,于是调用midlet.startapp()方法。进入active态。当ams决定要把midlet转入paused态,就会调用midlet.pauseapp()方法,midlet就会暂停执行,通常paused态会用于释放所占资源。当ams判断midlet不再需要,就会调用midlet.destroyapp(),midlet被消灭。请注意我上述是站在ams的角度在谈ams如何控制midlet的状态改变。程序员也可请求midlet的状态的变换,通过调用resumerequest,notifypaused,notifydestroyed这三个方法。
例如,我在上一节给出的例子中有如下程序片段:
…
public void commandaction(command c,displayable d){
if (c ==exitcommand){
destroyapp(false);
notifydestroyed();
}
…
这里先把destroyapp()的unconditional值置为false,抛出一个midletstatechangeexception 异常,表示midlet这时还不想被destroy。notitydestroyed()通知amsmidlet进入destroyed态。具体的细节请参阅midp api文档。
下面给出一个最简单的midlet流程:
===========================flowmidlet.java================================
import javax.microedition.midlet.*;
public class flowmidlet extends midlet {
public void startapp() {
system.out.println( "in startapp…" );
pauseapp();
}
public void pauseapp() {
system.out.println( "in pauseapp…" );
destroyapp( true );
}
public void destroyapp( boolean unconditional) {
system.out.println( "in destroyapp…" );
}
}
===========================flowmidlet.java完===============================
关于midlet状态的改变可以用下图表示:
destoryapp()
+———————–>————————–+
| |
new() +========+ startapp() +========+ destroyapp() +===========+
—–>| paused |————->| active |—————>| destroyed |
+========+ +========+ +===========+
| pauseapp() |
+———<————+
图1 midlet的状态转变
这里还要说几句闲话,关于ams,其作用不止是控制midlet的运行状态。它实际上际上负责了midlet的整个运行机制。关于ams进一步的描述,请参见王森老师的文章-“利用java撰写手机应用-java application manager篇”(《程序员》,12期,2001)。注意其中jam就是ams。
