CLDC/MIDP的基本结构 粗略的说j2me把设备分为两类,一种是联接设备( connected device),一种是有限联接设备(Connected, Limited Device)。前一种对应于那些有电源的,电力充裕,较大的设备。例如:电视机,冰箱等,后一种对应于主要使用电池,小型的设备,例如:手机,pda等。 这里我主要只涉及第二种,有限联接设备(Connected, Limited Device)。sun把J2me的实现分为两层:configuration 和 profile。configuration包括虚拟机(virtual machine),核心的类库与API。configuration层定义一个java虚拟机的特性与java类库的最小子集。也就是说,configuration层提供了开发人员一个最基础,最核心的Java平台。因为j2me把设备分为两类:联接设备(connected device)和有限联接设备(Connected, Limited Device)。对应这两种设备就有了两种J2ME configuration。分别为CDC(Connected Device Configuration)和CLDC(Connected, Limited Device Configuration)。这里请注意,CDC使用经典的javaVM,而CLDC使用的是KVM(The K Virtual Machine)。KVM是sun专门为使用16/32位RISC/CISC微处理器或控制器,并其可用内存为160kb~512kb的的设备而开发的。KVM比较小,通常只有128K或更少。 Profile层也包含一组API,主要针对于特定的某一族系的设备而定义。profile层在特定的configuration层上实现,而我们程序员则负责在特定的profile上编写应用程序。对于手机,pda等Connected, Limited Device。它们的profile层称为MIDP(Mobile Information Device Profile)。于是MIDP与CLDC合在一起就构成了一个完整的J2ME架构。顺便说一句,对于MIDP上的应用程序sun也有独特的叫法,它们被称为MIDlet。你是不是觉得有点眼。想想java中的applet。下图显示了开发手机应用的结构。图2 CLDC/MIDP的结构 深入理解CLDC | 深入理解CLDC/MIDP CLDC的目的 CLDC的安全性 低端的基于虚拟机的安全性由下载时对class文件的审核(verification)步骤来保证。(如果你写过并编译过MIDlet程序,就会知道这一步是必须的。这里有一个概念就行了,我会在后面讲述如何创建MIDlet程序时,详细介绍具体的步骤)。基于应用程序的安全性通过使每个应用程序分别运行在相对独立的封闭环境中来保证并且处于被保护的系统package中的类不能被应用程序重载(overridded)。 MIDP对应的设备特性 | MIDP对应的设备特性 由于MID这类设备,在屏幕、内存、处理器等问题上有诸多限制,在手机或是PDA等MID上开发应用程序必须要考虑一些技术上的特殊点。 下面给出一些MID设备的特性: 还有很多软件上的特性,如读写non-volatile内存(就是掉电后不会失去内容的内存,如flash)。读写无线设备接口的API,等等。除了上诉技术上的问题,你还得注意你的程序要简单易用且稳定可靠。尤其是可靠性,你开发的是通讯设备,用户是不能忍受程序有什么纰漏而影响到通话的。你要牢记这一点。 MIDP的类库API 如前文所述,sun在CLDC之上定义了MIDP(Mobile Information Device Pro-file)层,用以提供对UI、永久存储介质(persistinace storage)、和网络等更高层的(相对于CLDC)支持。那么,让我们来具体看看MIDP的类库。 MIDP由四个javax.microedition包组成,它们包括: 注:如果在加上语言和实用类(java.lang和java.util)则有六个。 | 对于Java语言支持的特殊方面 | 对于Java语言支持的特殊方面 CLDC总的来说是与Java语言完全兼容的,但需注意以下几点: 不支持浮点数据类型(即没有float和double)(这实际上主要是由于CLDC所面向的设备,其硬件因其内存限制或是基于安全性的考虑不支持浮点运算) 不支持类实例(class instance)的终结(finalization),即不存Object.finalize()方法。(注:finalization指的是java中提供的有别与garbage collection的另外的一种对象清理方法。具体可参看侯捷老师译的Bruce Eckel的《Thinking in Java 第二版》,可以在www.jjhou.com中下载)有限的错误处理,即大部分Java.lang.Error的子类都未被支持。与此相反,CLDC包括了相当完备的异常(exception)类。 对于Java虚拟机(Java Virtual Machine)支持的特殊的方面 实质上CLDC在其严格的内存限制下达到了对Java虚拟机相当程度的兼容性。不过还是有下列不同点: 类文件审核过程(classfiles Verification) CLDC要求其下层的虚拟机能够辨别并拒绝非法的class文件。但由于CLDC本身面向小内存消耗的小型设备这一前提。其类文件检测机制与J2SE中定义的标准类文件审核机制还有所不同。请注意看下图: 图3 CLDC的类审核机制 请注意上图所示CLDC中的预审核(preverification)过程。这是CLDC区别于通常的类文件审核过程的关键。如上图所示,当源程序被编译后,必须被预审核器预审核,然后才能被下载到目标设备上去。之所以有这一步骤,主要是为了减轻KVM中审核器的负担,加快审核速度。就像我前文提到的,这是出于对CLDC支持的硬件的考虑(毕竟手机和PDA并没有我们PC机那样奔腾的“芯”呀!^-^)。这里记住这个概念就行了。具体的操作方法我会在以后讲述编写MIDlet程序时介绍。 CLDC的类库API | CLDC的类库API 如果不严格的说,CLDC的类库是J2SE的一个小的子集,有以下这种近似关系成立,即J2SE包含CDC包含CLDC。但要注意CLDC并未完全包含于J2SE,它还包括一些专门针对无线设施的类。所以可以把CLDC的类库简要划分为两部分:从J2SE继承的类和CLDC专有的类。 1. 从J2SE继承的类 这部分包括三个package,即java.lang,java.util和java.io。注意即使这些从J2SE继承的的类,也是大大“缩了水”的。例如java.util的类与接口由J2SE的47个缩减到10个。另外两个也有相应缩减。 系统类From java.lang:Object, Class, Runtime, System, Thread, Runnable,String, StringBuffer, Throwable数据类型类From java.lang:Boolean, Byte, Short, Integer, Long, Character容器类(container class)From java.util:Vector, Stack, Hashtable, EnumerationI/O 类From java.iInputStream, OutputStream, ByteArrayInputStream,ByteArrayOutputStream, DataInput, DataOutput,DataInputStream, DataOutputStream, Reader, Writer,InputStreamReader, OutputStreamWriter, PrintStream日期与时间类From java.util:Calendar, Date, TimeZone附加的实用类java.util.Random, java.lang.Math异常类(Exception Classes)From java.lang:Exception, ClassNotFoundException,IllegalAccessException, InstantiationException,InterruptedException, RuntimeException,ArithmeticException, ArrayStoreException,ClassCastException, IllegalArgumentException,IllegalThreadStateException, NumberFormatException,IllegalMonitorStateException, IndexOutOfBoundsException,ArrayIndexOutOfBoundsException,StringIndexOutOfBoundsException,NegativeArraySizeException, NullPointerException,SecurityExceptionFrom java.util:EmptyStackException, NoSuchElementExceptionFrom java.iEOFException, IOException, InterruptedException,UnsupportedEncodingException, UTFDataFormatException错误类From java.lang:Error, VirtualMachineError, OutOfMemoryError2. CLDC专有的类 这里sun提供了javax.microedition.io包。用它来提供与外界沟通的桥梁。(注:就像在J2SE中我们利用java.net.*)注意,所有的连接都由javax.microedition.Connector创建。例如:你可以打开一个http连接通过Connector.open("http://www.chinajavaworld.com")javax.microedition.io的接口包括:Connection, InputConnection, OutputConnection,StreamConnection, ContentConnection, DatagramConnection,StreamConnectionNotifier这里再说明一点,实际上你也可以看出,CLDC所包括的类库,并不足以开发应用程序。例如,没有UI界面的支持等。这也正是CLDC的设计理念。CLDC本身就从未想过要解决所有的问题。这些问题要靠其上层的Profile-MIDP来解决。例如javax.microedition.lcdui就是定义在MIDP中的UI包。 | 编写并运行一个MIDlet | 编写并运行一个MIDlet MIDPlet简介 MIDP中定义的应用程序称为MIDlet。任何一个MIDlet都是javax.microedition.midlet.MIDlet的子类,必须继承自javax.microedition.midlet.MIDlet。这很显而易见。我们在J2SE中编过Applet,Applet就必须继承自java.applet.Applet。是不是很类似。请看下图,说明了MIDlet的继承体系。图4 MIDlet的继承体系 一个简单的MIDlet //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很类似。好,我们先把它编译,运行一下看看。 | 编译之前的准备 | 编译之前的准备: -
-
-
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"按键,在Project name项填:HelloWorld;在MIDLet Class Name填:HelloWorld。点击Creat project。 3. 这时会出现Setting for project对话窗,采取默认即可。点击ok。 这时请注意,因为没有down sun的IDE,所以你要手工把你事先编辑好的HelloWorld.java放置在c:j2mewtkappsHelloWorldsrc目录下。这时,按“Build”键,如果一切正常,将提示编译完毕。这时在device下拉选单中选定你想要的设备,再按“run”键,终于大功告成。你可以多选几个不同设备,感受一下,不错吧。 MIDlet的lifecycle | 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 Management software来管理的。这玩意儿是处在操作系统级别上来管理MIDlet运行的底层机制的总称,所谓MIDlet state(MIDlet状态)就是它一手操办,控制管理的。MIDlet state确保了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这三个方法。 我们的HelloWorld程序先把destroyApp()的unconditional值置为false,抛出一个MIDletStateChangeException 异常,表示MIDlet这时还不想被destroy。notityDestroyed()通知AMSMIDlet进入destroyed态。具体的细节请参阅MIDP API文档。 下面给出一个MIDlet的最简单的状态流程: //FlowMIDlet.java MIDlet的最简单的状态流程 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..." );} } | MIDlet的状态的改变可以用下图表示: 这里还要说几句闲话,关于AMS,其作用不止是控制MIDlet的运行状态。它实际上际上负责了MIDlet的整个运行机制。关于AMS进一步的描述,请参见王森老师的文章-“利用Java撰写手机应用-Java Application Manager篇”(《程序员》,12期,2001)。注意其中JAM就是AMS。 | | | | |