|
|
|
| 您的位置:首页>>J2ME开发>>简介使用Java编写Palm OS程序的解决方案(1) |
|
|
简介使用Java编写Palm OS程序的解决方案(1)
|
| 2005-08-13 来源:CSDN 作者:yanycw |
现在,使用Java语言为 Palm OS编写程序的领域还没有完全统一,并且也有许多程度上的差异,目前,市面上有好几种不同的可用的应用程序接口,每种应用程序接口都给出了一个到当前的Palm OS应用程序不同程度的访问权限。也许这其中大家最熟悉的是Sun微系统出品的产品;但是能够为Palm OS写程序的绝不只有这一种产品。本文这一部分并不是介绍使用Java编写Palm程序的教程--因为每种我们将要讨论的解决方案都有自己的要求和值得注意的地方--而是一篇向开发者概括介绍开发工具的的文章,我们将纵观这一领域,找出在使用 Java语言开发 Palm OS应用程序时,你应该使用什么工具以及你又能够得到什么。
一、Sun的解决方案: KVM、 Configuration和 Profile
KVM是 Kilobyte Virtual Machine (千字节虚拟机),那么命名是因为它的内存大小是以千字节来量度,而不是像 Java虚拟机那样需要兆字节。 因为有这么苛刻的内存要求, KVM的功能只是完整 JVM的的子集。 你可以从 Javasoft站点上找到全部的信息,但是值得注意的是它遗漏了映射(reflection)、 JNI和自定义类装载器以及一个可变的安全机制。
Sun已经制订一个计划,提供了 configuration和 profile来满足设备程序设计的需要。 configuration是一个应用程序接口,是设计来提供一个基础,用于一类广泛的一般的设备,所有的这些设备都有相似的特性,比如说有限的内存,偶然性强的网络连接性,低电力消耗,可运行在电池上,所以,J2Me被设计得既一般又抽象。 现在 Java 2 Micro Edition(J2ME)可用的 configuration有 CLDC(Connected,Limited Device Configuration)和 CDC(Connected Device Configuration)两种,后者用于比 Palm功能更强大的设备,这就超出了我们讨论的范围;而前者,代表有限连接设备配置,是像PDA,双通道呼叫器以及移动电话。 CLDC包括一个J2SE中的类的子集,但是有一些重要的差别,例如,因为小型设备中的虚拟机使用的无用单元收集机制,CLDC的 java.lang.Object不包含 finalize方法,你应当记住,这个应用程序接口中的某个特定的类可能出现但是它的某个方法却没有出现。请参考应用程序接口文档,这样的话你就会知道什么时候该用什么configuration了。
对于许多刚开始使用 CLDC开发程序的朋友,感到奇怪的是 CLDC不支持浮点数。 这是 KVM默认的实现, KVM是使用 C编写的,它可以被移植到许多平台上,它不支持浮点运算,这是因为我们所面对的硬件一般是小型设备,有的还是使用8位的处理器,这些处理器有可能不支持浮点运算。
profile是特殊的具体的,它的目标是一个比configuration更具体的设备的类,包括用户界面和事件处理元素,这在 configuration中是没有出现。 现在, Palm OS或 PDA没有公开可用的 profile。
Java Community Process有一个已经开发了一段时间的 PDA Profile, 开发者们仍然在等待一个新的 PDA profile版本。与此同时,想要遵循 KVM/Sun解决方案开发者的应当做什么呢? CLDC版本包括一个可以用作 Palm OS的 最原始的profile的类的最小的集合, 据悉, Sun不赞同使用这些类开发任何商业程序,他们也不计划对这个应用程序接口做任何更新。 但是如果没有 PDA profile,开发者也可以使用这些类库。 通常我们所知的是Kjava,它包含了许多 GUI类: CheckBox、 RadioButton、 List等等。除了这些,还有 Spotlet类,它被用于处理事件以及 Palm OS捕获手写笔的输入和键盘按下的事件等等。
下面是一个使用 kjava来显示简单的文本字符串和按钮的类: import com.sun.kjava.*;
public class HelloKjava extends Spotlet { private static Button OKButton; public static Graphics g = Graphics.getGraphics(); file://取得Graphics对象
public static void main(String args[]) { HelloKjava hk = new HelloKjava(); }
public HelloKjava() file://HelloKjava类的构造方法 { OKButton = new Button("OK", 84, 140); register(NO_EVENT_OPTIONS); drawScreen(); } public void penDown(int x, int y) { if (OKButton.pressed(x,y)) { System.exit(1); } } public void drawScreen() { g.clearScreen(); file://清除屏幕 g.drawString("Hello KJava",20, 10); file://把字符串画在屏幕上 OKButton.paint(); } }
还有一个类 com.sun.kjava.Database,它在一种到达 Palm数据库应用程序接口的方法。 这就是说,它是非常原始的并且不提供访问存在Palm数据库中的任何内容完全的权限。它只允许设置和获得字节数组; 它不允许键入访问,除了通过记录标识号 (是一个整数 )。 因为数据库只能理解字节数组,给你的数据意味着你需要把这些字节数组解析成有含义的字段。
简介
简介使用Java编写Palm OS程序的解决方案(2)
二、Kawt的解决方案
Kawt也是 KVM的一个 Abstract Window Toolkit(抽象窗口工具包),Kaw为Java程序员提供了一个更加常见的应用程序接口集合,例如,它使用通用布局管理器 (除了 GridBag)来在屏幕上放置组件,此外它还允许你设置那些组件的监听者,换言之,Kawt中没有包括 Spotlet机制。按钮、面板、标签以及文本框和其他的 AWT类都可用,而且,还可以有自定义类: FtpShel,TabbedPane和 GifLoader,还有一个类 java.io.File,它是一个使用标准的 Palm数据库文件储存资料的目录或文件结构的抽象类。
使用 Kawt,我们编写出来的程序如下所示: import java.awt.*; import java.awt.event.*;
public class HelloKawt extends Frame implements ActionListener { Button OKBtn = new Button("OK"); Label lbl = new Label("Hello Palm");
public static void main(String args[]) { new HelloKawt(); }
public HelloKawt() { OKBtn.addActionListener(this); this.add("South", OKBtn); this.add("Center", lbl); pack(); this.show(); }
public void actionPerformed(ActionEvent ae) { System.exit(1); } }
虽然 Kawt提供了一个比 kjava更好的类的集合,但是它实际上是基于 kjava的,因此,它缺少数据库类。对于开发 Palm程序来说,这是一个相当严重的问题。 通常来说,任何商用应用程序都需要把数据储存在设备上,随后还要与台式机同步化, kjava.Database的同步化有点问题,因为它不包含 HotSync软件期待的分类,它也不允许访问每个包含最初记录的 "本地 " palm数据库文件的属性位,即使使用了 PDA Profile版本,这些也不可能解决,因为 profile的目标是一般的 PDA而不是特别的 Palm OS。 然而, Kawt团队毕竟也做了一件出色的工作,它使刚开始写Palm程序的程序员很容易使用Java编程。
三、IBM解决方案
IBM有自己的虚拟机,叫J9---它在许多方面都优于 KVM,Visual Age Micro Edition支持 J9,我们大家都知道, Visual Age Micro Edition是一个来自 Object Technology International的 IDE,而 Object Technology International又是 IBM拥有的子公司。 而 VAME是一个完整的开发工具,它可以给对 Palm OS应用程序接口完全的访问权限, 然而,这需要付出一些代价。 虽然 VAME是一种 Java工具,它所提供的东西都是使用Palm应用程序接口的本地 C方法的包装。 也就是说, VAME中调用的方法和你在 C中看到的方法完全相同。虽然理解你的应用程序所要运行的操作系统并不是一件坏事,但这需要你非常了解开发 Palm的 C应用程序接口的方法特征,如果你只是一名Java开发者这就成了问题了。这个是一个缺点,开发VAME的工程师似乎发觉到了这一点,并尝试着去改进。
下面是一个使用 VAME编写的例程: import com.ibm.oti.palmos.*; import com.ibm.oti.palmos.util.OSX;
public class HelloJ9 implements OSConsts {
public static void main(String[] args) {
CharPtr title = new CharPtr("IBM Vame Demo"); EventType event = new EventType();
try { FormType form = OS.FrmNewForm(0, title, 0, 0, 160, 160, 0, 0, 0, 0); OS.FrmSetActiveForm(form); OS.FrmDrawForm(form);
OSX.WinDrawChars("Hello J9!", 5, 30);
while(true) { OS.EvtGetEvent( event, -1 ); if (OS.SysHandleEvent( event )==0) { if (event.getEType() == appStopEvent) { OS.FrmEraseForm(form); OS.FrmDeleteForm(form); return; } } }
} finally { title.dispose(); event.dispose(); OS.FrmCloseAllForms(); } } }
正如你所看到的,这个程序与前几个例子都不太一样。 如果你能够越过这个障碍,你的应用程序的性能将远远优于一个基于 KVM的应用程序。 VAME其他与众不同的优点就是它可以访问所有的本地应用程序接口调用,使用一个管道,你可以同步创建任何 Palm数据库。
四、Waba/SuperWaba 解决方案
Waba是另外一种虚拟机。 在风格上, Waba有点像 Kjava和 Kawt的中间品。 它包含了比 kjava更多的 GUI组件,使用了坐标位置来在屏幕上放置组件,而不是像 kawt是使用布局管理器。Waba的优点是它的速度,它的确比 KVM快了很多;而且,如果你认为你的应用程序可能不仅仅是只定位于 Palm OS, 你也可以使用Waba,因为Waba也可以在 Windows CE上运行。 Waba还有一种扩展,叫 Superwaba,它提供了更多的功能。
这里有一个使用 Waba编写的小型应用程序,它使用一个附加的类来设置标题: import waba.ui.*; import waba.fx.*;
public class HelloWaba extends MainWindow {
Button closeButton;
public HelloWaba() { Title title = new Title("HelloWaba"); title.setRect(0, 0, this.width, 15); add(title);
closeButton = new Button("Close"); closeButton.setRect(0, this.height - 15, 44, 15); add(closeButton); }
public void onEvent(Event event) { if (event.type == ControlEvent.PRESSED) { if (event.target == closeButton) exit(0); } } }
Waba还有许多优点:使用剪贴板拷贝和粘贴的能力,访问系统键盘以便更容易输入文本,而且还有一个类,封装了一些虚拟机细节,允许你确定虚拟机正在运行的平台以及 ROM的版本。
五、总结
使用 Java编写 Palm OS应用程序的解决方案取决于好几个因素: 你的目标是否只是 Palm OS; 对于开发来说,速度和容易度那个更重要; 我们现在离最后决定使用什么解决方案开发 Palm程序还很远, 因为这一领域将来还会发生巨大的变化。以后的文章中,我要详细介绍使用J2ME与Waba来编写可运用于Palm OS或其它小型设备的应用程序。
J2ME之谜
第一节 引言 J2ME概述
第一节 引言 J2ME概述
到目前为止,大部分人都已非常熟悉 Java 2平台,以及 Sun如何把 Java技术分成三个版本 (标准版、袖珍版以及企业版),Sun 在1999年6月时推出了 Java 2袖珍版 (J2ME)来满足消费电子和嵌入设备的需要。J2ME是为了那些使用有限的能源、有限的网络连接 (常常是无线连接)以及有限图形用户界面能力的设备开发的。它最初的目标是 16位或 32位处理器,16 MHz时钟频率, 512K或更少内存的设备。乍一看之下, J2ME就像一个没有绑定明显主题的松散的应用程序接口和技术规范。我们想通过说它不是什么东西的方法来描述它,它不是一组用于台式机 Java应用程序规范,如果你再观察仔细一些,你会发现所有的 J2ME组件都围绕一个中心,这些中心被称为configuration(配置 ,Sun的市场营销资料也称它们 design centers,设计中心),它们中间的每一个都是用于消费电子和嵌入设备的特别的类。
Connected limited device configuration(有限连接设备配置,简称 CLDC ) 这个配置定义了 Java应用程序接口以及支持手持设备的技术,就像 Sun的文档中所描述的那样, " devices that you hold in your hand(你握在手中的设备) " Palm序列手持设备可能是这一领域的设备的最好的例子,特别是它有开发 CLDC的功能以及 Palm设备运行期系统可用。 Connected device configuration(连接设备配置 CDC ) 这个配置定义支持象 Sun文档中所说, " devices that you plug into plug into the wall(你插入墙的设备)的设备的应用程序接口和技术,这样的设备的一个例子可能就是机顶盒。
这两种配置不同的地方就在于它们应用于的装置的能力, CLDC设备的处理器能力有限 (与台式机系统比较 ),并且存储器大小一般也只在128 KB到 512 KB之间, 与此同时, CDC系统就不同了,它可能有 32位或 64位处理器,以及有限的存储容量,不过它的下限也得超过512K。 它遵循的原则就是,每个不同的能力硬件的配置都将被不同的虚拟机支持。 基于 CDC的系统使用一个功能强劲的虚拟机,而基于 CLDC系统的使用 KVM (我过会儿会介绍)。
每个配置代表一种低水平的,基本的应用程序接口,在这两个相似基础之上是 profile(简表),用于特殊设备的额外的应用程序接口。 我想通过看一张来自SUN提供的文档中的图表 (参见图 1 )来解释这其中的关系。 图一解释 配置和简表的体系结构 J2ME的体系结构被横向地分成三层,纵向分成两部分。配置包括一个控制配置核心类的虚拟机, 具体的 简表位于每个配置之上。
J2ME现在定义两个配置, Connected Device configuration(连接设备配置 CDC )和限制性更强的 Connected Limited Device Configuration (有限连接设备配置)。 简表的实现是 Java应用程序接口的一个集合,用于适应被定义配置的应用程序接口提供的服务,简表是一个完整的运行环境,一个在简表上执行的应用程序不需要额外的支持类。
J2ME没有定义满足这两种配置的标准化用户接口,Sun也承认现在的消费设备多种多样,用户界面也各不一样,所以定义一个可用于所有用户的界面是一场失败的战争。 J2ME中的用户界面定义在简表中。
J2ME之谜
第二节 J2ME的体系结构
第二节 J2ME的体系结构
现在个人计算机系统的数量和种类已经发展到无法控制的地步,请你想一想,你编写的程序运行在“信息家电”舞台的情景吧,这些信息家电包括呼叫器,行动电话,像Palm这样的个人数字助手(PDA),电视机顶盒,POS终端以及其他的消费电子设备。现在全世界上光是手提电话生产商就有许多,更不用说别的家电设备了,而且每一种家电设备又有不同的特性和界面。所以,你可以想到, Java应用程序的轻便性以及能够解决开发这么许多不同的设备程序的能力,使大家对J2ME有很大的期许。当然,为了更好的开发这些信息家电,就要求把Java的精髓压缩进一个非常小的程序包中,这就是J2ME。
J2ME是一种通过许多部件和规范的技术, 这众多的部件和规范帮助 J2ME来满足这众多的消费产品的不同的需要。和所有的爪哇程式语言技术一样,在它的核心属于一种虚拟机。 就像使用所有 Java技术一样,J2ME的核心也在一种虚拟机中。 最初,用于 J2ME应用程序虚拟机的被称作 Kilobyte virtual machine或简称 KVM。就像它名称的含义, KVM比较小,通常只有 128K或更少。这比起我们通常了解和使用的 Java 2标准版 Java虚拟机 ( JVM )的 32 MB来说就小得多了。
用于连接虚拟机的是一系列配置和简表,它们提供了用于特定 J2ME环境的类应用程序接口(见图二)。 每个配置和简表处理一般或具体的消费产品,配置和简表规范是由多种多样的设备生产商和用户共同开发并建立的。配置是用于一组通用设备的最小的 Java平台, 常常归为一种横向的设备分组,相对来说,横向分组设备是那些共享相同的内存安排,通信带宽,能量需求以及用户能力的设备,一般认为配置能够提供这众多的设备的所有需求。
图二解释: J2ME层次 Java虚拟机是 J2ME技术的核心,但是配置和简表提供特殊环境的类应用程序接口。配置是用于一组通用设备的最小的 Java平台,而简表则为具体的设备家族或特别的应用程序提供更具体的能力。
J2ME领域的新的开发者常常被这些事实困惑的, 事实上, Sun的第一个配置(现在只是一种配置的引用实现 )带有称为 KVM的虚拟机引用实现, KVM满足配置的虚拟机的必要条件。然而, Sun的 KVM也可以被另外一个虚拟机所代替,现在, 正是因为配置和虚拟机结合得有点紧密,因此导致了这么多的混乱。
另一方面,简表完善了 配置,为某个具体的设备家族或某个具体的工业片段应用程序提供更高的性能。 换言之, 简表为具体的纵向市场的设备比如说行动电话提供更多的性能。这里的关键就是 简表必须完善 配置, 没有 配置和虚拟机提供核心类应用程序接口和运行期环境的话,简表也不会工作。
通常,简表为一种给定的垂直分组设备提供用户界面、输入法、持久性机制。这类 简表被认为是发展这些设备应用程序的完整的工具包。我们见到最多的应用程序简表的例子就移动电话简表和个人数字助手(PDA)简表,其他简表为范围宽广的设备提供非常特殊的功能或应用程序可移植性,这方面的例子就是提供远程方法调用 ( RMI )功能的简表和提供统一银行事务的简表。
虚拟机、 配置、 简表…你是不是已经被搞迷糊了? 如果这样的话,我们就来简化一下 J2ME体系结构吧。 如果你想为小型信息家电编写 Java应用程序的话,你就需要两个前提:一个 配置和至少一个 简表。 现在, 一般是配置捆绑了虚拟机和一套针对你的平台所能够用的横向分组设备的Java类库。其次,你至少还需要一个 简表来为你的平台提供附加的 Java类,这个 简表通常会为你的设备提供用户界面、输入和数据库类。有了这两个前提,你就了使用 Java为你的设备编写应用程序的基本的J2ME环境。
J2ME之谜
第三节 详细谈谈J2ME配置
第三节 详细谈谈J2ME配置
J2ME可以在好几个不同的配置中进行配置。 就像先前提到的,每个配置为一组通用设备提供最小的 Java平台,到目前为止,只有两种配置规范。通过 Java规范定义的这两种配置是 Connected Limited Device Configuration (有限连接设备配置, CLDC )和 Connected Device Configuration (连接设备配置 CDC )。
CLDC是为使用较小的存储容量的设备设计的 (参见图3 )。 CLDC用于内存在128到 512K之间的消费电子设备, 这一类别中典型代表的设备包含呼叫器、行动电话、PDA和POS终端;而另一方面, CDC用于比 PC机小但是具有比 512K内存多的设备,这一类设备包括互联网络电视系统、机顶盒、POS系统、汽车导航以及娱乐系统。一般来说, CDC使小型设备只要具有少量的资源,至少比台式机要少的资源就能进行Java编程,而CLDC使小型设备所拥有的资源只要比一张智能卡多一点就可以进行Java编程了。
图二解释 设备覆盖的范围 J2ME有两个配置CLDC和 CDC,CLDC是为使用较小的存储容量的设备设计的,而CDC用于比 PC机小但是具有比 512K内存多的设备。
除了在容量大小和能力上对虚拟机规定了必要条件,配置还规定了类应用程序接口要包含常见的 java.io、 java.net、 java.util和 java.lang包,配置可能还要包括其他需要的程序包。
CLDC
CLDC起源可以追溯到1999年JavaOne大会上介绍的Sun的第一个袖珍版 Java和第一个 KVM以及相关的类库,虽然 CLDC和所有的配置都满足成为虚拟机的条件,可它本身还不是虚拟机,CLDC的引用实现只是包含在当前的分布中的 KVM。
根据规范中所说,运行 CLDC的设备应该有 512K或更少的内存空间、一个有限的电源供给 (通常是使用电池)、有限的或断断续续的网络连接性 ( 9600 bps或更少 )以及多样化的用户界面甚至没有用户界面。 通常说来,这个配置是为个人化的、移动的、有限连接信息设备而设计,比如呼叫器、移动电话和 PDA等。
与 J2SE相比, CLDC缺少下列所说的这些特征:
AWT(抽象窗口开发包), Swing或其他图形库
用户定义类装载器
类实例的最终化
弱的引用
RMI
Reflection(映射)
CLDC有四个包: java.lang、 java.util、 java.io和 javax.microedition。 除了 microedition包以外,其他的这几个包都是J2SE包的核心子集,CLDC采用这些J2SE类库,但是把其中一些在微型设备中用不到类、属性、方法去掉了。因此 CLDC类库有许多细微的差别。 如果您想研究J2SE和 CLDC类库之间的差别,请参阅相关文档,在此就不详细说明了。
想要理解为什么CLDC去除这么多J2SE中重要的类和特征,请回想一下与 CLDC相关的两条基本原理。首先,它只有 512K的内存空间, 而像RMI和映射需要的内存太大了。 其次,配置必须满足为一组通用设备提供最小的 Java平台。 在个人移动信息设备领域中,许多系统都不能支持 J2SE中的众多的高级特征。 例如,许多消费电子产品不能支持浮点数; 因此 Float(浮点类)和 Double(双精度类)就被删除了。 再看另外一个例子,许多系统没有或不提供访问一个文件系统的功能或权限。 因此与文件有关的类也被丢弃了。又如,错误处理是一个代价非常高的过程处理,在许多消费电子设备中,故障恢复是很难的甚至是不可能的。 所以在 CLDC中,许多错误处理类也被删除了。
java.microedition程序包提供了一个一般的结构来替代许多 J2SE网络输入/输出类。 CLDC一般连接器结构还定义了一个 Connector类,允许许多不同类型的连接能够使用静态方法,下表列出使用同一个Connector类创建和打开五种不同类型的连接的方法:
HTTP Connector.open("http://www.xyz.com");
套接字 Connector.open("socket://111.222.111.222:9000");
通讯端口 Connector.open("comm:1;baudrate=9600");
数据报 Connector.open("datagram://111.222.111.222");
文件 Connector.open("file:/xyz.dat");
一般连接器结构提供给应用程序开发者一个到通用低水平硬件的简单的映射表。成功执行 open语句将返回一个实现一般连接界面的对象。
CDC
CDC涵盖了个人电脑与有至少 512K内存的小型设备之间的中间地带。现在,这一类设备通常是共享的、固定的 (不用移动)网络连接信息设备,像电视机机顶盒,网络电视系统、互联网电话与汽车导航/娱乐系统等等。
首先,CDC基于 J2SE 1.3应用程序接口,包含所有定义在CLDC规范(包括 javax.microedition程序包)中的Java语言应用程序接口。与CLDC相比, CLDC所有缺少的特性和类在 CDC中都被补齐,包含映射、最终化、所有的错误处理类、浮点数、属性、输入/输出 ( File、 FileInputStream等等 )和弱的引用。 一般说来, CDC中预期的类包括一个J2SE子集和一个完整的 CLDC超集,如图4中所示:
图4 :J2SE、CLDC和CDC的关系
就像使用所有的配置一样,CDC有基层虚拟机的具体的必要条件。 根据 CDC规范,基层虚拟机必须提供实现完整的 Java虚拟机的支持 。 如果虚拟机实现有一个用于激活设备的本地方法的界面,它必须兼容 JNI 1.1版本。 如果虚拟机实现有一个调试界面,它必须兼容 Java虚拟机调试界面 ( JVMDI )规范。 如果虚拟机有一个简表界面,它必须兼容 Java虚拟机简表界面 ( JVMPI )规范。 可见,为了实现这些功能,CDC肯定会变得很大,就不能称其为K虚拟机了,因此,我们通常称用于CDC的虚拟机为 CVM,这里的 C代表 compact、connected、consumer。
J2ME之谜
第四节 谈谈J2ME简表
第四节 谈谈J2ME简表
虽然配置为一组通用设备提供了最小的 Java平台,但是应用程序开发者感兴趣的是为一个个别的设备生产应用程序,当他们只是使用配置的话,他们编写的应用程序就会有一些欠缺。 配置必须满足所有的设备的最小的要求, 用户界面、输入机制和数据持久性有高度地设备具体性,每一种设备都有自己的用户界面、输入机制和数据存储方法,这些往往不在配置所满足的最小要求的范围之内。
简表为相同消费电子设备的不同的生产商提供了标准化的 Java类库, 事实上,虽然配置规范的开发由 Sun领导,但是许多简表规范仍将继续由特殊设备的供应商领导。 比如说, Motorola领导了行动电话和呼叫器简表规范的开发,又如 Palm 领导 PDA简表的开发。
现在,五个已知简表已经有了规范, 记住,每个简表的责任都是为了完善配置的不足,下表列出了这五个简表: 简 表 完善配置 Mobile information devices profile (MIDP) 移动电话和呼叫器 CLDC Personal digital assistant profile Palm和Handspring的PDA 设备 CLDC Foundation profile 用于所有不需要GUI的CDC设备的标准简表 CDC Personal profile 替代PersonalJava的Foundation完善的简表 CDC RMI profile 提供RMI的Foundation完善的简表 CDC 现在我想谈一谈另一个Java类库集,它现在差不多可以被认为是另一个简表了。当Sun为Palm开发第一个KVM时,他们需要一组类来 开发Palm的演示程序。这套类库被封装进 com.sun.kjava程序包, 在 CLDC早期的开发中,这些类被广泛的使用来测试和演示 J2ME。因为 kjava是唯一的允许应用程序开发者使用 J2ME和 KVM开发应用程序的类,所以它就被广泛使用了。甚至到了今天,一个用于 PDA或更特殊一点的 Palm的简表多已经在开发中,许多开发者仍然希望使用 kjava类来开发 PDA应用程序。尽管 kjava类不被支持,并且仅仅用于设计测试程序或演示程序,并且它们将被一个即将到来的简表所替代,但是开发者们仍然热衷于使用它来开发。
MIDP
Mobile Information Device Profile(移动信息设备简表 ,简称 MIDP ),第一个实现的简表,补充了 CLDC并且提供应用程序语义和控件、用户界面、持久存储器、网络和用于移动电话的计时器、双通道呼叫器和其他无线电设备。 因为 MIDP和 CLDC两者都有引用实现,我们可以使用一个例程来研究一下这个简表。
下面的例子是一个允许用户输入代表想知道的基金报价的代号的例子。应用程序然后通过 HTTP接到一个金融网站,获得基金报价,把价格储存在一个数据库,然后把价格返回给用户。 // 到如需要的J2ME类 import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import javax.microedition.rms.*;
// 扩展MIDlet类来构建我们的自定义MIDlet public class FundTracker extends MIDlet implements CommandListener {
file://显示管理者变量 private Display display = null; file://MIDlet的表单变量 private RequestForm reqForm = null;
file://MIDlet构建器 public FundTracker () { display = Display.getDisplay(this); reqForm = new RequestForm("Fund Tracker"); reqForm.initForm(); reqForm.setCommandListener(this); }
file://开始 MIDlet 应用程序 protected void startApp() { display.setCurrent(reqForm); }
file://暂停 Midlet protected void pauseApp() { }
file://销毁Midlet protected void destroyApp(boolean unconditional) { }
file://通过监听者响应命令 public void commandAction(Command c, Displayable s) { if (c == reqForm.getExitCommand()) { destroyApp(false); notifyDestroyed(); return; } if ((c == reqForm.getGetCommand()) && (reqForm.getSymField().getString().length() > 0)) { getAndDisplayQuote(); } else { reqForm.getMsgString().setText("Symbol required"); } }
file://储存由#分开的成对的基金字符串和报价字符串 private void storeQuote (String fund, String newQuote) {
file://数据库变量
RecordStore quoteDB = null;
try { quoteDB = RecordStore.openRecordStore( "FundQuotes", true); byte[] data = (fund + "#" + newQuote).getBytes(); int size = data.length; quoteDB.addRecord(data, 0, size); quoteDB.closeRecordStore(); } catch (Exception recordException) { System.out.println("Unable to store quote and/or use Fund Quote database."); } }
file://通过QuoteService类取回提交的代号表示的基金报价 private void getAndDisplayQuote(){ String fundSymbol = reqForm.getSymField().getString(); if (fundSymbol.length() > 0) { String theQuote = QuoteService.getQuote(fundSymbol); if (theQuote != null) { storeQuote(fundSymbol, theQuote); reqForm.getMsgString().setText(theQuote); } else reqForm.getMsgString().setText("No quote" + '\n' + "Check Symbol"); } } }
MIDP应用程序称为 MIDlet, 为了创建一个 MIDlet,你必须写一个扩展基本 MIDlet类的类 (就像我们在上面代码段中列出的那样)。 这有点类似常见的 applet或 servlet。 MIDlets独有的东西是把多个 MIDlet组成一个 MIDlet套件的能力。 这就允许 MIDlet在一个单独的 JVM环境中共享资源,比如一个数据库等等。 事实上,我们上面给出的例子还包括一个 MIDlet ( RetrieveQuote,见上段程序),用于取回所报价格。 当MIDlet被请求时, MIDlet通过构造程序实例化,然后调用实例的 startApp()方法。
在 FundTracker例子中, MIDlet的用户界面或显示是由 Display类的一个实例管理的。 对于每个 MIDlet,只有一个显示管理器实例。 所有可以显示的项目,像屏幕或画布(canvas),通过这个管理器都能够成为可见的。因为行动电话和呼叫器能力的多样化,又因为用于这些设备的应用程序类型的差异, MIDP规范提供了两种类型的用户界面。一个可移植性稍差、明确设备、低水平的应用程序接口,允许图形元素精确的控制和放置。 这个接口类型是用于应用程序特性比较典型的设备特别设计的,比如电子游戏。 一个可移植性稍好的、抽象的、高级的 GUI应用程序接口,提供来用于商业应用程序。
我们的例程使用的是高级的应用程序接口和典型的用户界面组件 (文本框,列表等等 ),是这类界面通用的。比如说,实际的表单和所有的小组件在一个单独的文件中都已定义。 就像在代码段一中列出的那样,当 MIDlet创建时,一个表单的实例与 MIDlet关联。 在调用 MIDlet startApp()方法的时候,通过 Display对象显示表单。 使用一个用于表单的类,允许我们在我们简单的报价检索应用程序中重新使用这个表单 ( RetrieveQuote )。为了清晰性和风格,我们通过一个单独的类来定义报价服务。 为了演示一般连接器结构的能力,我们的报价服务类通过一个 Connector实例取回报价。
J2ME之谜
第四节 谈谈J2ME简表(2)
MIDP要求平台设备提供一个机制用来储存简单的数据记录,通过正常的平台事件,比如重新启动和电池更新维护系统的完整性。 MIDP称一个持久数据库为 RecordStore。 在我们的示例中, MIDlet打开并添加一条记录到 " MutualFundQuotes " RecordStore。 正如我们的演示程序,能添加到 RecordStore中的唯一一种类型的记录是字节数组。 相同的 RecordStore是一个资源,它可以通过套件共享。 根据 MIDP规范, 当 MIDlet从平台中删除后,RecordStore也会被从平台中删除。
PDA简表
Palm公司是开发PDA简表规范的领头人, 这个简表也是完善了 CLDC,在相当长的一段时间内,它都将是 kjava类程序包的替代品。 Java规范建议这个 profile至少应当提供两个核心功能片段: 一个用户界面显示工具包,适合于 "有限的尺寸和深度显示 "和一个持久数据存储器机制。 显示工具包应该是抽象窗口工具包的一个子集, 而持久机制将为应用程序、数据、配置/环境信息提供简单的数据存储。
Foundation简表
下面三种简表不是非常常见, 这三种简表的职责都是为了完善 CDC。 Personal和 RMI简表实际上是 Foundation简表的扩展。 Foundation简表的任务是担任一个基础简表,便于以后开发出来的提供图形用户接口、 网络等功能的简表附着在它之上。 除了用于基础简表, Foundation简表还提供完整网络的支持,不管有没有使用图形用户接口。
Personal简表
在当前的规范需求下, Personal简表提供下一代 PersonalJava环境。这个简表允诺,提供互联网连接性和 Web保真度以及一个能够运行 Java applets的 GUI。
RMI简表
回想一下 CDC配置为共享的、固定网络连接信息设备提供最小的 Java环境。 RMI简表将通过提供 Java到 Java的RMI来协助提供更好的网络连接性。 通过使用 J2SE ( 1.2.x或更高版本的 ) RMI,这个简表将允许这些网络设备与其他系统应用程序交互操作 (这个系统不必也运行 J2ME )。
kjava类
正如前面提到的那样, kjava类是最初提供的一个供测试用的类,在 Palm设备上运行早期的 KVM和配置版本。 它们将被 PDA简表代替。 kjava类扩展了 CLDC并且提供一个图形用户接口、 Palm数据库访问,简单集合类和一个三角法计算器。
在代码段2中,我使用 com.sun.kjava重写了 MIDP FundTracker程序,让它在 Palm上工作。 和前面的程序一样,这个简单的程序允许用户输入一个公基金代号并从WWW上的金融报价服务商那里取回报价。
kjava应用程序被称作 spotlet。 事实上,一个应用程序可以由很多 spotlet组成,但是在任何时间只有一个 spotlet可以显示在 Palm屏幕上。 在我们的例子中,我们创建一个基本 spotlet-- RequestFormSpotlet.java,为我们的两个 spotlets子类提供用户界面。代码段 2扩展了基本的 RequestFormSpotlet以便得到并储存一个报价。 RetrieveSpotlet也扩展了基本 RequestFormSpotlet并允许储存的报价被取回(见图)
代码段2 import com.sun.kjava.*;
public final class FundSpotlet extends RequestFormSpotlet {
public static void main (String args[]) { new FundSpotlet().draw(); }
private void draw() { initForm(); setTitle("Fund Quote Requested"); }
public void penDown(int x, int y){ if (getExitButton().pressed(x,y)){ getGraphic().playSound(Graphics.SOUND_CONFIRMATION); System.exit(0); } if (getSymField().pressed(x,y)) getSymField().setFocus(); if (getGetButton().pressed(x,y)) { quoteRequested(); } }
private void storeQuote (String fund, String newQuote) {
int dbType = 0x46554e44; int dbCreator = 0x43415454; com.sun.kjava.Database quoteDB;
try { quoteDB = new com.sun.kjava.Database(dbType, dbCreator, com.sun.kjava.Database.READWRITE); if (!quoteDB .isOpen()) {
com.sun.kjava.Database.create(0, "MutualFundQuotes", dbCreator, dbType, false); quoteDB = new com.sun.kjava.Database(dbType, dbCreator, com.sun.kjava.Database.READWRITE); } byte[] data = (fund + "#" + newQuote).getBytes(); quoteDB.addRecord(data); quoteDB.close(); } catch (Exception recordException) { System.out.println("Unable to store quote and/or use Mutual Fund Quote database."); }
}
private void getAndDisplayQuote() { String fundSymbol = getSymField().getText(); if (fundSymbol.length() > 0) { String theQuote = QuoteService.getQuote(fundSymbol); if (theQuote != null) { storeQuote(fundSymbol, theQuote); message(theQuote); } else message("No quote. Check Symbol"); } }
private void quoteRequested() { message(""); getGraphic().playSound(Graphics.SOUND_STARTUP); if ((getSymField().getText().length() > 0)) { getAndDisplayQuote(); } else { message("Symbol required!"); } }
}
在 RequestFormSpotlet程序中,类似于 MIDP中的 Display对象,单独的 Graphics管理许多 spotlet用户界面显示。它考虑到了屏幕会被清除,显示边界会被建立。 不象 MIDlet,没有屏幕或画布对象来让我们添加用户界面小组件, 取而代之的是按钮、文本字段等等,直接描画在 spotlet上。 paint()方法利用图形环境从独一无二的 Graphics在屏幕上显示小组件。
我们的MIDP程序的 QuoteService类的大部分可以重新使用。 因为 kjava没有象 MIDP中HttpConnection这样特定的连接器界面,所以我们必须利用更多标准的一般的连接器结构表单获取 HTTP链接。 为了做到这一点,使用代码段 3中的代码替换 getQuotePage()方法。注意注意使用 Connector,就像在 MIDP中我们使用 HttpConnection一样。
代码段3 private static String getQuotePage(String symbolString) { StringBuffer quotePage = new StringBuffer(); int ch; try { InputStream in = Connector.openInputStream ( "testhttp://someurl/some_application?page=++&mode=fund&symbol="+ symbolString); while ((ch = in.read()) > 0) { quotePage.append((char)ch); } in.close(); return quotePage.toString(); } catch (IOException ex) { System.out.println("Exception reading quote from HTTP Connection"); return null; } }
Palm设备广泛利用数据库, 你的 Palm中的通讯簿、备忘录和记事本应用程序都与数据库有关。 kjava程序包提供了一个非常小的 Database类,不仅可以创建并保持应用程序数据,而且可以访问现有的数据库。 如果你熟悉 Palm数据库,你可能会对 kjava Database类提供的功能和信息感到失望。 然而,请再次记住, kjava只是一个演示的版本。
在我们的例子中,我们的 spotlet访问一个 Palm数据库 (如果不存在的话,则创建一个新的数据库)来储存公基金报价。每个 Palm数据库都必须有名字、创建者 ID (一个 Palm登记的唯一的标识号 ) 和一个指定到某个单独应用程序的类型号。 试图打开数据库要通过尝试创建一个带有 ID信息的数据库实例来实现。 就象 MIDP RecordStore,记录被添加进 kjava数据库,通过把一个字节数组当成记录添加到数据库中的形式。
J2ME之谜
第五节 再谈谈一些J2ME规范
第五节 再谈谈一些J2ME规范
在 J2ME内还有很多子规范, J2ME的重要的部分如下:PersonalJava、K虚拟机 (KVM)、Java嵌入服务器以及 PersonalJava的两个扩展规范: JavaPhone和 JavaTV应用程序接口。 你可以想象, JavaPhone是一个定位于无线电智能电话和互联网络可视电话的应用程序接口,而 JavaTV则满足机顶盒市场的需求。
下面我想详细的谈一谈以上的规范:
1、PersonalJava
PersonalJava应用程序环境目标是 Web连接消费设备----常常执行来自网络的小应用程序。问题是 PersonalJava如何适合 J2ME的配置和简表方案。 答案是 PersonalJava将被包容进 Connected Device Configuration中,最终将被定义为 Personal简表,即前面所谈到的Personal简表。
另一方面,有一段时间将有两个 Java应用程序接口为嵌入开发世界服务: PersonalJava和 EmbeddedJava。 PersonalJava偎依在 J2ME大伞之下, 可为什么 EmbeddedJava不呢? EmbeddedJava不和 PersonalJava同在 J2ME内,是因为在 PersonalJava和 EmbeddedJava应用程序之间有一个基本的差别。 PersonalJava应用程序期望连接到某类网络中下载并执行小应用程序。 按照这种观点, PersonalJava设备就是一般用途的消费设备; 它们的能力可以被扩展。
相比之下, EmbeddedJava设备则惨了点。 它们执行的功能都非常具体的,基本没有必要提供下载新的代码到 EmbeddedJava设备的能力。 Hence, PersonalJava设备使用可扩展 Java应用程序接口; 而EmbeddedJava设备则没有,因为没有必要使用。
PersonalJava可以以两种形式得到: 由原码形式的,提供给那些对把PersonalJava移植到其他设备感兴趣的开发者,那些已经把 PersonalJava移植到某个具体的操作系统和处理机的组织提供二进制形式的 PersonalJava环境。有兴趣探索 PersonalJava的开发者如果没有二进制平台也可以使用 PersonalJava模拟环境 ( PJEE )。 这个模拟器运行于 Solaris/SPARC或 Windows,并且在许多配置中可用。 这些多种多样的配置基于“ look and feel”和类库支持 (环境是否提供 PersonalJava规范中规定的最低限度的或最大的类库)。PJEE包括类文件,一个应用程序 launcher和一个 appletviewer (两者都是为了调试功能并使其最优化)和其它的附带的文件 (例如字体叙述文件)。
J2ME家族的另一位成员 JavaCheck实用程序,提供了 PersonalJava的补充支持。 你把应用程序传过 JavaCheck,它将告诉你你的应用程序在一个 PersonalJava环境中能否顺利地执行。 JavaCheck检查类之间的依赖关系,如果应用程序调用了一个在 PersonalJava不可用的应用程序接口,它就会给出一个警报信号。 (据我所知,目前有两种JavaCheck的版本可用,一个是用于检验 PersonalJava 1.0版应用程序,另一个用于检验 1.1.x版程序。 当前的 PersonalJava应用程序接口规范是 1.2,用于这一版本的 JavaCheck还没有。 读者请去Sun相关网站去看看( http : file://java.sun.com/products/personaljava)。
2、KVM
前面我也说过,KVM是用于 J2ME平台最小的虚拟机,并且是用于CLDC配置的虚拟机。可是J2ME应用程序并不一定非要使用 KVM,J2ME技术可以使用任何虚拟机,不过至少应当有 KVM这样的功能。
为了满足基于KVM的设备一般只有狭小的内存空间和有限的处理能力的事实, KVM使用 C编写 (它不是现有的VM改进了的以后的产品)。 此外, KVM是模块化的, 也就是说,它是由模块构建的,当某个模块实现了预先设定的目标后,就可以很容易地把这一模块卸载。 可选的某块包括: 大的数据类型 ( long、 float和 double ),多维数组、类文件验证等。
KVM的本地界面以轻便性为原则构建,所以在KVM中任务切换不依赖硬件产生的记时器中断,因此在这种意思上来说不是抢先式。任务切换发生在虚拟机执行了一个预设编号的字节码之后。 并且, KVM的无用单元收集利用一个标记清扫(mark and sweep)算法来实现无用单元释放。 因此,对象引用是直接的,就像标准 Java一样。
当然,除了虚拟机以外还有许多可用的执行环境,在小型设备中,虚拟机必须要么被扩展,要么在附加工具协助下提供一个更加完整的运行期环境,正是这个原因, KVM需要附带的工具,比如说, JavaCodeCompact工具提供了预链接和预加载类, 允许Java类被直接地链接进虚拟机中。((设备上所有的应用程序使用的类 can直接地嵌入虚拟机。)
KVM一个可选的附件就是 Java Application Manager ( Java应用程序管理器,简称 JAM )。JAM的工作就是处理下载、安装、执行和卸载 CLDC设备上的应用程序的细节问题,因为资源有限,在CLDC设备上有可能不存在这些功能。JAM也处理更新安装应用程序的操作。(如果更新过程失败,它甚至可以重新使用旧的应用程序。 )
3、Java Embedded Server(Java嵌入服务器)
Java Embedded Server( Java嵌入服务器,简称 JES),在 PersonalJava基础上建立,是一个用于嵌入式网络设备的运行期环境。为了理解 JES,你必须理解两个核心概念:服务和服务空间结构。后者是前者的容器。服务程序是运行于一个 JES服务器上的组件化程序;服务空间结构是为服务程序提供生命周期 支持的环境。
技术上说,服务程序是界面的实现,事实上,它是一个实现特定活动的Java类集合。比如说,假如把 JES配置为一个家庭的气候控制系统的服务器,可以把从模数转换器读到的温度数据放进一个数据组件程序中。我就可以称这个组件为ReadThermostats服务程序。
在 JES的领域,服务的封装媒介称为 bundle。简单地说,bundle就是一个带有特殊内容的JAR文件。服务程序和bundle之间有一对一关系,一个bundle带有一个服务程序。服务程序和 bundle之间有一对一关系,一个 bundle带有一个服务程序。可这也不一定,一个 bundle可以设置多个服务程序索引 (注意, JES提供的所有的核心服务,每个 bundle中只有一个 )。
正如前面提到的那样,服务空间的一项工作就是管理服务程序的生命周期,这个工作的很大的部分包括解决服务隶属关系。bundle内容的一个重要的部分是bundle服务的依赖信息。所以,当服务空间打开一个bundle安装它的服务时,服务空间就可以确定外部需要什么服务。而且,一个服务的依赖关系并不是静止不变的,它们可以随某些事件改变。比如说当服务程序更新时的变化就是一个很好的例子。一个服务的新的版本可以添加或去除依赖关系。服务空间跟踪并解决这样的动态依赖关系。如果服务空间处理所有服务程序的生命周期,这就暗示了服务空间被赋予知晓一切的能力,那就是说,它能够推论结构、依赖、安装的细微差别等所有它负责的服务。服务空间通过在 bundle内伴随服务的 Java代码模块处理一些任务,这些模块被称作 wizard(向导)。JES向导是根据它们完成的任务命名的:
Dependencies -向导告诉调用者一个bundle依赖关系是什么。
Installer-向导处理bundle中服务的安装和删除操作。
Activator -向导知道如何启动和终止服务。
Updater -向导控件更新bundle中的服务。(更新向导不仅知道更新一个服务,而且知道在何时和什么情况下更新服务。 )
About -这个向导,就像它名称意味的那样,返回关于 bundle内容的信息。
Dispatcher -这是一种元向导(meta-wizard)。服务空间调用dispatcher向导定位一个bundle的其他向导。
当一个 JES服务器启动的时候,服务空间并不是完全没有启动服务。JES定义一组核心服务(可选),这些都是任何 JES服务器的组成部分。这些核心服务包含:
HTTP服务
日志 -记录错误和事件日志 日期 -精确到秒的日期/时间服务 连接管理器 -提供网络服务和Socket绑定,也处理连接接收。
线程管理器 -管理服务器提供的线程。thread管理器支持线程池并允许有效使用线程上界的规范。
计划程序 -提供未来的事件计划安排 (可用于告诉服务器某某动作必须在某某事件发生 )
RMI
SNMP
控制台 -提供远程管理服务器功能
基于 HTTP的远程应用程序接口实现
基于 RMI的远程应用程序接口实现 如果你把服务空间结构当成 JavaBean中的容器的话, JES就变得容易理解了。在这种类比关系中,服务程序就相当 JavaBean。那么,正象组件容器提供一个环境供 JavaBeans实例化、运行一样,服务空间就是以实例化的服务的聚集地。服务空间管理安装、实例化、执行、终止以及卸载服务;它也提供应用程序接口供服务交互作用。
开发一个简单的KJava应用程序示例
使用J2ME进行开发一个简单的KJava应用程序示例(1)
无论学习什么新事物,都讲究循序渐进。学习J2ME也不例外,在此我想先介绍一下使用J2ME开发Palm上的一个小的应用程序,再深入探讨开发更加复杂的应用程序,好,那我么就开始吧。
第一节 获得 J2ME
你可以从Sun网站上下载到 J2ME CLDC文件。第一个文件是 j2me_cldc_-1_0-src.winsol.zip,它包括所有开发 CLDC应用程序时需要的类库。除了包括类库以外,它还包括源代码以及 Windows和 UNIX下的可执行代码,用于 MIDP规定的 Java虚拟机引用实现。看了前几篇文章的读者肯定都知道,这里提到的Java虚拟机就是 K虚拟机 ( KVM ),有了这个文件,在开发过程中,你就可以在个人电脑上调试程序,而不用把这些程序下载到你的手持设备上。
第二个文件是 j2me_cldc-1_0-src-palm_overlay.zip,它包括一个用于运行 Palm操作系统的设备的 KVM的实现,以及把.class文件通过一个 Java编译程序生成可执行 Palm文件的工具。注意,这是一个用于 Palm操作系统的 CLDC个别实现。如果使用针对其它的设备的实现的话,你的 Java应用程序也可以在其他设备上运行。
为了开发用于 Palm OS设备的应用程序,你必需在你的计算机上安装这两个Zip文件。在本文中,我假设你已经在 C盘中安装了 CLDC文件夹。注意,为了开发 CLDC应用程序,你并不需要一个特定的 Java编译程序。你可以使用 J2SE带有的编译程序,唯一的差别就是,你必须在编译的时候更换成J2ME类库所在的路径。你还要使用下载到的 CLDC中带有的特定软件来处理生成的 .class文件。
第二节 运行文档附带的应用程序示例
你从Sun网站上下载的文件中包含了许多示例应用程序的源程序以及编译好的版本,你可以在你的台式机上,使用 KVM来运行这些示例应用程序。运行这些应用程序可以使你对一个 CLDC应用程序有一个感性认识。在运行这些程序之前,你必要启动一个命令行界面,然后输入下列命令: set cldc_classpath = c:;.
set bin = %bin%;c:
cd
好,现在你已经设置了环境变量并进入了保存示例应用程序的目录,你就可以开始运行它们了。比如说,为了运行 UITest程序,输入:kvm -classpath %cldc_classpath% UITest
你也可以看看 Pong这个游戏程序,请在命令行输入下面的命令:kvm -classpath %cldc_classpath% Pong
是不是挺好玩,你可以试一试运行每个示例应用程序,稍后,我们还要使用相同的方法来运行我们在台式机中开发的应用程序。
开发一个简单的KJava应用程序示例
使用J2ME进行开发一个简单的KJava应用程序示例(2)
第三节 构建一个 Palm应用程序
好,现在你对 J2ME的程序有一点感性认识了吧?现在让我们做一些实事吧,我将介绍如何构建一个 运行于 Palm OS设备上的 Java应用程序。首先,虽然J2ME是Java技术,但这并非意谓着你可以使用现有的 Java应用程序,重新编译它们然后把它们运行于新的设备上。在前面几章中我已经谈过,J2SE和J2EE使用的Java虚拟机中的许多关键特性已经从J2ME虚拟机中删除了,因为设备的资源有限。
J2ME带的 Java虚拟机(KVM)缺乏浮点数支持;J2ME应用程序与 J2SE、 J2EE应用程序的另外一个重要的差别是缺乏优先型多任务,虽然它不是 Java规范中所述的必要条件,但是几乎你的 J2SE、 J2EE应用程序运行的所有机器都支持优先型多任务。这意味着 CPU在多个 Java线程之间共享而不必在你的程序中添加任何特殊的代码,而 J2ME使用的设备则往往没有这种功能,为了确保多线程能够工作,你必须调用 Thread.yield()方法。
使用 CLDC简表的另一个值得注意的方面是J2ME类库缺少许多 J2SE类库中的类。在构建应用程序时,必须使用这有限制的类库。当你下载到CLDC文件时,你可以仔细考察你获得的文件,弄清楚哪一个类包含在CLDC规范中。你必须对付的最后一个问题是 CLDC类库内部缺少访问用户界面元素--按钮、菜单、图形。不使用 Palm的用户界面,就不大可能为 Palm OS设备开发应用程序, Sun已经解决了这个问题--使用一个单独的类库 com.sun.kjava来提供给你访问基层 Palm用户界面的权限。下面这个示例程序就使用类库创建窗口、按钮和对话框。不过请注意,kjava类库既不是 MIDP配置也不是 CLDC简表的官方部分,它很有可能在未来的版本中改变或消失。这就意味着你使用 kjava类库写的任何程序,一旦发行新的J2ME版本你就不得不修改这个程序以适应新的J2ME版本。但是现在,它还是你开发使用Palm用户界面的应用程序的唯一选择。 import lang.*; import com.sun.kjava.*;
public class HelloWorld extends Spotlet implements DialogOwner {
private Button quitButton; private Button aboutButton;
private TextBox welcomeTextBox;
private final String welcomeString = "Hello World "; private final String aboutTitleString = "About Hello World"; private final String aboutString = "HelloWorld J2ME CLDC Application";
public HelloWorld() { register(WANT_SYSTEM_KEYS);
welcomeTextBox = new TextBox(welcomeString, 10, 10, 140, 130); aboutButton = new Button("About", 75, 140); aboutButton.setEnabled(true); quitButton = new Button("Quit", 125, 140); quitButton.setEnabled(true); paint(); }
public void dialogDismissed(String title) { Graphics.clearScreen(); register(WANT_SYSTEM_KEYS); paint(); }
public void paint() { welcomeTextBox.paint(); aboutButton.paint(); quitButton.paint(); }
public void penDown(int x, int y) { if (aboutButton.pressed(x, y)) { Dialog aboutDialog = new Dialog(this, aboutTitleString, aboutString, "OK"); aboutDialog.showDialog(); } if (quitButton.pressed(x, y)) System.exit(0); }
public static void main(String args[]) { new HelloWorld(); } }
开发一个简单的KJava应用程序示例
使用J2ME进行开发一个简单的KJava应用程序示例(3)
分析HelloWorld应用程序
上面的这个HelloWorld应用程序具有运行 Palm OS的设备上的 CLDC应用程序的基本特征。当你仔细考察一下这段代码,你会发现许多使用 kjava类库编译应用程序的特性。首先,这个程序扩展了 com.sun.kjava.spotlet类,使用 kjava,一个 spotlet就是任何可以得到焦点(focus)的类,那就是说,从系统中接收事件,比如手写笔的点触。在我们的例子中, 当手写笔点击About和Quit按钮时,HelloWorld应用程序需要响应,因此它需要获得焦点。你的应用程序可以包括任意多的从 spotlet中衍生的类,虽然在任何时间它们中间只有一个能够取得焦点。实际上,应用程序通过调用 register方法使用焦点,我们在 HelloWorld构造程序开始的部分和 dialogDismissed方法中都用了 register。
HelloWorld类实现了 DialogOwner接口。实现 DailogOwner接口的类是用于创建对话框的类。我们的应用程序创建了一个对话框来响应手写笔点击 About按钮的事件,为了实现DialogOwner接口,你的类必须包含一个dialogDismissed成员方法,为了实现 DialogOwner接口,你的类必须包含一个 dialogDismissed成员方法,这个方法在一个对话框被关闭的时间被调用。
HelloWorld构造程序在屏幕上创建三个界面元素:一个文本框和两个按钮。你马上就会发现 kjava和 J2SE AWT的一个重要的差别: kjava没有与 AWT自动布局机制等价的东西。你必须自己编码确定每个界面元素在屏幕上的位置。在我们的程序中,我们把文本框放在(10,10)和(140,130)之间;两个按钮放置在( 75,140)和(125,140)。
每当用户在装置上轻点手写笔时,都要调用HelloWorld的 penDown方法。我们通过调用每个按钮的 pressed方法确定这次点击是否发生在按钮的边界以内,如果按钮的pressed方法返回一个真值,意味着手写笔点击事件发生在按钮边界之内,这个按钮相对应的动作将发生。比如说如果点击了 About按钮,我们通过创建一个新的 Dialog对象创建 About对话框。要是点击了 Quit按钮,我们就终止这个程序。
最后, 当用户关闭对话框时,要调用 HelloWorld的 dialogDismissed方法。在我们的应用程序中,这个方法做的事情就是通过调用 register方法恢复焦点并调用 paint方法来刷新屏幕。
编译
编译一个 CLDC应用程序需要两步操作:首先你必须通过标准的 J2SE编译程序运行它们,不过使用 CLDC类库代替标准的 J2SE类库。然后,使用preverify程序把得到的.class文件转化成 KVM可读的 Java应用程序。
上面的示例程序如下面这样编译: javac -g:none -classpath %cldc_classpath% -d %temp% HelloWorld.java
preverify -classpath %cldc_classpath% -s %temp% -d .
一旦编译好后,就可以使用下面的命令来在你的台式机上运行这个程序:
kvm -classpath %cldc_classpath% HelloWorld
既然这个CLDC应用程序在计算机上可以运行,那么你也可以试着把它转换成Palm可执行文件。
在Palm上运行
为了把一个使用CLDC开发的.class文件转换成在Palm OS设备上可实际运行的文件,你需要使用j2me_cldc-1_0-src-palm_overlay.zip中的许多程序。首先,你必须把你的 .class文件转换成 Palm OS应用程序,所有的 Palm OS应用程序都有扩展名 .prc。通过使用 palm.database.MakePalmApp类把 .class文件转化成 .prc文件,使用下面这个命令行运行我们刚才写好的 HelloWorld.class文件: java palm.database.MakePalmApp -bootclasspath %cldc_classpath% HelloWorld
现在,在存放 HelloWorld.class的相同目录就有了 HelloWorld.prc文件。这个文件就是 Palm应用程序。你现在可以使用 Palm OS设备带的安装程序安装这个文件。除了把你的应用程序的.prc文件安装到 Palm OS设备上以外,你还要安装 kvm.prc,kvm.prc是 K虚拟机的一个实现,用于 Palm OS设备。
J2ME与MIDP开发
J2ME与MIDP开发(1)
在我前面的三篇文章中,我介绍了一些关于J2ME的基本的知识,在这篇文章中我想谈谈J2ME与MIDP开发的一些知识,其实在本系列的第二部分我门就已经接触到MIDP了,现在只是想深入探讨一下。MIDP是Mobile Information Devices Profile(移动信息设备简表)的简称,而遵照 MIDP和CLDC规范编写的 Java应用程序我们就称其为 MIDlet。
你可以从MIDP这个规范的英文名称的含义推测, MIDlet是定位于提供某种水平的网络连接性的移动设备。运行 MIDlet的设备也有好几个共同的属性:有限的屏幕大小,内存和处理能力,这个规范是设计来满足这些需求,典型的设备包含行动电话和呼叫器。
这篇文章将重点介绍安装和配置 CLDC和 MIDP软件,我们也将写一个简单的 MIDlet并学习在一个移动设备预览这个MIDlet的必需的步骤,最后再谈一谈如何给MIDlet打包。
CLDC定义了一个用于 Java虚拟机的规范和一组核心类库,CLDC本质上是一个 Java 2标准版 ( J2SE )的简化版本,是为了使用有限内存和资源的设备设计的。配置 (比如 CLDC )是设计来运行简表的,而MID简表是一个规范,它提供一套核心类库来编写那些用于移动设备的Java应用程序。一个简表定义类库,开发者们使用这些类库来为某一特定的设备或用于某一范围的设备编写应用程序。例如, MIDP定义的类是用于创建用户界面(文本框、表单等),处理用户输入以及使用 HTTP在一个网络上通讯。
第一节 开发MIDlet
下载软件
在你能写一个 MIDlet之前,你需要下载必需的软件: JDK,CLDC以及 MIDP。
• Java Development Kit ( JDK )-- 1.2版本以上
• Connected, Limited Device Configuration (CLDC)
• Mobile Information Device Profile (MIDP)
你也可能选择下载 J2ME规范,下载到的这个规范包括 MIDP应用程序接口,当你是初次开发 MIDlet时,它是一个非常好的参考。
安装软件
一、JDK
JDK已经默认了用于安装文件的目录,当然了,你也可以选择安装在一个你自己选定的路径。如果安装的 JDK版本是 1.3并且选择默认路径,那么 JDK将被安装到这个目录:c:\jdk1.3
你一定很好奇,为什么需要 JDK?因为 CLDC和 MIDP安装好后都不包括Java编译程序 javac.exe,很明显,没有编译程序就没有能力编译你的 Java代码,你也不可能有进步。
二、有限连接设备配置 ( CLDC )
解压你下载到硬盘上的.zip文件,我推荐路径为 C:\j2me。解压以后,c:\j2me路径的结构如下所示:解压以后,c:\j2me路径的结构如下所示:
c:\j2me | j2me_cldc
三、移动信息设备简表 ( MIDP )
同上,解压你下载到硬盘上的.zip文件,使用上面相同的目录C:\j2me,现在那个目录结构应该像:
C:\j2me | j2me_cldc midp-fcs
配置软件
一、更新 PATH
PATH环境变量是 Windows操作系统使用来定位可执行程序的,我们需要更新 PATH来指向 Java编译程序和 CLDC、 MIDP程序的路径。
(1)更新 JDK的PATH
a、Windows 2000或 Windows NT系统
• 从控制面板中选择系统
• 点击"高级",再点击"环境变量"
• 找到 PATH,点入,在最后添加JDK安装路径的\bin目录,假设你安装 JDK是 1.3版本并选择默认安装路径,你将添加:C:\jdk1.3
b、Windows 98或 Windows 95
如果使用的是Windows 98或 Windows 95系统,请在C盘跟目录下的Autoexec.bat文件的最后面加上以下两行: set path=c:\jdk1.3\bin;%path% set classpath=.;
(2)更新 CLDC路径
你还需要更新你的PATH环境变量来指向存放 CLDC可执行文件的目录。按照上面概述的相同的步骤来添加到PATH中:
C:\j2me\j2me_cldc\bin
(3)更新 MIDP路径
同上面那样,更新 PATH环境来指出存放 MIDP可执行文件的目录;这个文件是用于测试你的 MIDlet的移动电话模拟器。
按照上面概述的相同的步骤来添加到PATH中C:\j2me\midp-fcs\bin
二、更新 CLASSPATH环境变量
CLASSPATH告诉 Java编译程序到什么地方搜索那些不是 JDK平台本身附带的类库,在本例中,我们需要更新 CLASSPATH来指向MIDP类。你还需要有当前目录的引用("."),作为CLASSPATH的一部分,按照上面概述的相同的步骤,更新CLASSPATH: CLASSPATH=C:\j2me\midp-fcs\classes;. - 注意最后的点"."表示当前的工作目录。
三、添加SCREEN_DEPTH环境变量
MIDP含有一个测试 MIDlet用的移动设备模拟器,这个模拟器可以以有色模式运行,也可以运行于黑白两色构成的灰度梯度模式。为了指定颜色数,你可以添加环境变量 SCREEN_DEPTH。例如:
SCREEN_DEPTH=8
添加这个环境变量的方法与处理 PATH和 CLASSPATH变量的方法类似。
SCREEN_DEPTH值和颜色对应表
值 颜色数 1 2 2 4 4 16 8 256
J2ME与MIDP开发
J2ME与MIDP开发(2)
测试安装
在编写一个 MIDlet之前,让我们检查一下是否所有的软件都已正确地安装。
1. 进入命令行
2. 测试CLDC安装,键入preverify并按回车键。
3. 测试 MIDP安装,键入 midp并按回车键。应该弹出一个窗口,如下图所示:
4. 测试 JDK安装,键入 java -version并按回车键,屏幕将出现下面的样子。
开发一个MIDlet程序
在编写MIDlet程序之前我还要再说两句,前面我也说过了MIDP程序称为MIDlet,这可能因为所有的 MIDlet都是扩展 javax.microedition.midlet.MIDlet类 (正象 Java applet扩展 Applet类一样) 除了从键盘或点击设备上接受输入的信息以外, MIDLet类还提供用于激活、暂停和终结 MIDlet的接口,即分别是startApp()、pauseApp()和destroyApp() 方法。startApp()方法在概念上与 Java applet的 start()方法类似,当MIDlet启动时它被调用,而且在一个MIDlet暂停之后恢复时也被调用。
另外一个值得注意的类是javax.microedition.lcdui.Command类。这个类定义了好几个移动设备通常使用的语义类型: BACK、CANCEL、EXIT、HELP、ITEM、MENU、OK、SCREEN和STOP。通过 javax.microedition.lcdui.Displayable类(所有的 J2ME UI组件的父类)中的addCommand()方法把这些命令添加到用户界面上。addCommand()方法包括一个优先级参数,允许应用程序提示运行时刻环境应当按照什么顺序显示什么内容。在大多数环境中,如果两个相同类型的命令被使用相同的优先级水平添加的话,环境将显示一个菜单 " menu "选项并允许用户从多个命令选项中选择。
J2ME与MIDP开发
J2ME与MIDP开发(3)
大家是不是心里都痒痒的了,好,让我们开始编写一个非常简单的 MIDlet吧,这个 MIDlet将创建一个带有一则消息的文本框。我们还要添加一个命令按钮用于退出这个 MIDlet。
一、编写 Java源代码
创建一个新目录来保存你以后编写的MIDlet,例如 c:\midlets,在这个目录里再创建一个叫myMIDlet的目录,使用任何文本编辑器创建一个名为 simpleMIDlet.java的文件并输入下面这一段 Java源代码。把这个文件保存在c:\midlets\myMIDlet目录 (或者任何你选择的目录)。 代码段1 simpleMIDlet.java
import javax.microedition.midlet.*; import javax.microedition.lcdui.*;
public class simpleMIDlet extends MIDlet implements CommandListener { private Display display; // 引用MIDlet的Display 对象 private TextBox tbxMain; // Textbox 显示一条消息 private Command cmdExit; // 设定按钮用于退出MIDlet
// MIDlet构造程序 public simpleMIDlet() { display = Display.getDisplay(this);
cmdExit = new Command("Exit", Command.SCREEN, 1);
tbxMain = new TextBox("Simple MIDlet", "Welcome ", 50, 0); tbxMain.addCommand(cmdExit); tbxMain.setCommandListener(this); }
// 被应用程序管理器调用来启动MIDlet。 public void startApp() { display.setCurrent(tbxMain); }
// 一个必要的方法 public void pauseApp() { }
file://一个必要的方法 public void destroyApp(boolean unconditional) { }
file://检查一下是否选择了退出命令 public void commandAction(Command c, Displayable s) { if (c == cmdExit) { destroyApp(false); notifyDestroyed(); } } }
此时,先不必担心每行代码是做什么用的,把注意力放在开发这一整个环节中。
二、编译并预验证(preverify)
现在你必须编译这个 java源文件并且 preverify生成的.class文件。
1.编译源代码
进入命令行形式,进入你保存文件的项目目录,使用下面的命令编译程序。使用下面的命令编译程序。
avac -bootclasspath c:\j2me\midp-fcs\classes simpleMIDlet.java
选项 - bootclasspath C: \j2me\midp - fcs\classes指定了 Java自举(启动)类文件目录。我们必须自己指向midp类,否则javac会使用默认的JDK类库去编译MIDlet程序。不出问题的话,就能顺利地编译simpleMIDlet.java生成simpleMIDlet.class文件 (默认情况下,生成的.class位于 Java源文件所在的目录)。
2.预验证类文件。
preverify -classpath c:\j2me\midp-fcs\classes;. -d . simpleMIDlet
选项" -classpath C:\j2me\midp-fcs\classes;." 指定了到哪里去寻找用于预验证的.class文件。这包括需要用来做验证处理的 MIDP类 (通过 c:\j2me\midp-fcs\classes指定 )和你的类文件,它位于当前目录 (就是"."指定的)。
选项"-d." 告诉预验证器把验证过的类文件放在什么地方。这一点"." 指当前目录,即原始的类文件相同的位置。
注意:前面的 preverify命令行选项将用一个新的、预验证过的类文件覆盖原先的类文件。你可以分两个目录,一个用来保存通过编译的类文件,另一个用来保存通过预验证创建的类文件。但是没有经过预验证的类文件是不能被应用程序管理器载入的。
3、运行 MIDlet
我们现在准备在移动设备模拟器中运行 MIDlet,如果你现在还处在命令行方式,请输入 midp firstMIDlet
应该可以看到下面的输出结果:
J2ME与MIDP开发
J2ME与MIDP开发(4)
第二节 封装MIDlet
下面我想谈谈封装MIDlet的相关知识,即介绍一下 MIDlet套件以及Java档案和应用程序描述器文件,为了说明方便,我们还将写一个MIDlet程序并利用上面介绍的那个MIDlet程序,并创建JAR文件和JAD文件来封装这些程序。我们还要看着如何使用 Java程序包改变我们的开发过程。最后你将学习如何从一个Web服务器上访问 MIDlet。
MIDlet套件
虽然把MIDlet封装进 Java档案文件(JAR)并不一定必要,但这是发布 J2ME/MIDP应用程序最常见的方法。MIDlet套件是一个MIDlet中所有的文件以及作为 MIDlet一部分的必需的资源的集合。MIDlet套件由以下几部分组成:
1、附在JAR文件中的 Java类文件,
2、描述 JAR文件内容的清单文件
3、附在 JAR文件中的资源(如图象)和Java应用程序描述符文件(JAD)
4、应用程序管理器
应用程序管理器是一个移动设备上的软件程序,这个应用程序与具体的设备有关,并且由设备的生产商实现。它负责安装、运行以及从设备上删除 MIDlet,而提供错误处理支持。这个应用程序管理器同时还提供一个可选界面,允许用户启动、终止以及删除 MIDlet。
Java档案文件
一个商品化的、封装过应用程序通常由许多文件构成。除了 Java类以外,其他文件诸如图像和应用程序数据即通常所说的资源,也可能是这个程序包的一部分。你把所有这些信息捆绑进一个整体,就称为 JAR文件。
除了类和资源文件,一个 JAR文件还包括描述 JAR内容的清单文件。清单文件名为 manifest.mf,储存在 JAR文件本身中,下面这张表中列出定义在这个清单文件中的所有可用的属性。 表 1 属性 用途 MIDlet-Name MIDlet程序包的名称。例如“Game Pack” MIDlet-Version MIDlet的版本号 MIDlet-Vendor MIDlet的创建者或提供商 MIDlet-Icon 应用程序管理器把这个图标与 MIDlet-Name相关联,这是一个图形文件,以 PNG图象格式储存。 MIDlet-Description 描述 MIDlet的文本 MIDlet-Info-URL 可能提供更多MIDlet和/或供应商信息的 URL MIDlet- 这个属性包括三段信息: ??MIDlet名称 ??用于这个 MIDlet的图标(可选) ??应用程序管理器将调用来加载这个 MIDlet的类名 在我们的“ Game Pack”例子中,有两个条目: MIDlet-1: KOF, /images/kof.png, kof.kofMIDlet MIDlet-2: Golf, /images/golf.png, golfMIDlet MIDlet-Jar-URL JAR文件的 URL MIDlet-Jar-Size JAR文件的大小 MIDlet-Data-Size 持久数据存储必需的最小字节数 MicroEdition-Profile MIDlet需要哪一种 J2ME简表 MicroEdition-Configuration MIDlet需要哪一种 J2ME配置
这些属性并不是全部都需要,可是,没有下面列出的这六个,应用程序管理器就会拒绝加载这个 JAR。
MIDlet-Name
MIDlet-Version
MIDlet-Vendor
MIDlet-
MicroEdition-Profile
MicroEdition-Configuration
这里有一个简单的清单文件的例子:
MIDlet-Name: KOF2001
MIDlet-Version: 1.0
MIDlet-Vendor: NeoRage Corporation Inc.
MIDlet-1: kof, /images/kof.png, kof.kofMIDlet
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0
Java应用程序描述器文件(JAD)
虽然没有必要,你仍然可以在 JAR文件中包含一个 JAD文件,就像清单文件一样,这个文件也包含 MIDlet的信息。创建一个 JAD文件是基于两个原因。
1、向应用程序管理器提供信息,说明 JAR文件的内容,使用这些信息,就可以判断一个 MIDlet是否适合运行在这个设备上。例如,通过查看属性 MIDlet-Data-Size,应用程序管理器可以确定 MIDlet是否需要比设备可以提供的更多的内存。
2、提供一种方法,可以把参数传送到 MIDlet而不必更改 JAR文件,在本文的后半段我们将看一个这样的例子。
JAD文件使用表 1中相同的属性。如果你需要创建你自己的属性,也可以办得到,只要使用不以 MIDlet为开头的属性名就可以了,下面的 showProperties.jad文件就是自定义属性的例子。和清单文件一样,有某些属性必须被定义,如果这些属性不可用的话,应用程序管理器将不加载这个 MIDlet,它们是:
MIDlet-Name
MIDlet-Version
MIDlet-Vendor
MIDlet-
MIDlet-Jar-URL
MIDlet-Jar-Size
MIDlet-Name、MIDlet-Version和MIDlet-Vendor的值必须与 JAR中的清单文件中相同的属性的值一致。可能看出,如果在这两个文件有什么不同的话,申请管理器不也会加载这个 JAR。
除了这些属性以外,如果两个文件中的另外名称相同的属性,但是属性值不相同的,将优先采取应用程序描述器文件 ( JAD )属性。
MIDP 1.0规范没有规定 MIDlet-n属性是 JAD文件的必需属性。可是,没有这个属性,就没有办法在设备模拟器中预览 MIDlet。在两个文件中包含这个属性没有问题,并且事实上,那么做可以更清楚看出这些文件是怎样关联的。因此,出于完整性考虑,这里的所有离子都将在JAD文件中包含MIDlet-n属性。因此,出于完整性考虑,这里的全部例子都将在 JAD文件中包含 MIDlet-n属性。
下面是一个非常简单的例子:
MIDlet-Name: Note Pad
MIDlet-Version: 1.0
MIDlet-Vendor: ABC WorkGroup.
MIDlet-Jar-URL: http://www.abcworkgroup.com/MIDlets/notepad.jar
MIDlet-Jar-Size: 26248
MIDlet-1: NotePad, /images/NotePad.png, NotePad.Main
从MIDlet中访问 JAR/JAD属性
一个MIDlet程序可以访问所有的定义在清单文件(在JAR文件中)和JAD文件的属性。返回属性信息的方法及所在的完整的程序包名是javax.microedition.midlet.MIDlet.getAppProperty(String name)
下面是一个例子,从jar/jad文件中读出并打印属性值。
showProperties.jar中的 manifest.mf文件的内容如下: MIDlet-Name: Show Properties MIDlet MIDlet-Version: 1.0.1 MIDlet-Vendor: ABC WorkGroup. MIDlet-1: ShowProps, , showProperties MicroEdition-Profile: MIDP-1.0 MicroEdition-Configuration: CLDC-1.0 MIDlet-Description: A simple property list example MIDlet-Data-Size: 1500
showProperties.jad的内容: MIDlet-Name: Show Properties MIDlet MIDlet-Version: 1.0.1 MIDlet-Vendor: ABC WorkGroup. MIDlet-Jar-URL: file://showProperties.jar MIDlet-Jar-Size: 1132 MIDlet-1: ShowProps, , showProperties JadFile-Version: 1.5 MIDlet-Data-Size: 500
showProperties.java的源程序: import javax.microedition.midlet.*; public class showProperties extends MIDlet { public void startApp() throws MIDletStateChangeException { System.out.println("Vendor: " + getAppProperty("MIDlet-Vendor")); System.out.println("Description: " + getAppProperty("MIDlet-Description")); System.out.println("JadFile Version: " + getAppProperty("JadFile-Version")); System.out.println("MIDlet-Data-Size: " + getAppProperty("MIDlet-Data-Size")); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } }
下面这些是一些比较重要的地方:
manifest.mf文件作为 JAR文件 showProperties.jar的一部分储存的。
JAD文件showProperties.jad使用MIDlet-Jar-URL: file://showProperties.jar 引用showProperties.jar。
当你浏览这个 JAD文件的时候,它使用上面那个命令找出相关联的 JAR文件并读取清单文件的内容。
属性MIDlet-Name、MIDlet-Version和MIDlet-Vendor 既在 JAR中的清单文件中又在 JAD文件中,这些属性的值都必须完全相同。
MIDlet-Description属性来自清单文件,是可选的。
JadFile Version属性不在表 1中,因此它是一个自定义属性。因为 JAD文件内的属性可从MIDlet访问,所以你可以不用改变 JAR文件而添加属性到 JAD中。
属性 MIDlet-Data-Size在清单文件和 JAD文件中都有,就像前面指出的那样,当两个文件中有完全相同的属性时, JAD文件中的属性将使用。切记这不适用于MIDlet-Name、MIDlet-Version和MIDlet-Vendor。
J2ME与MIDP开发
J2ME与MIDP开发(5)
在 MIDlet套件中封装多个 MIDlet
在我们谈论如何封装多个 MIDlet之前,我们先得多写几个可用的MIDlet。下面有两个简单的 MIDlet。第一个显示一个带有简短消息的文本框组件。
MIDlet1.java源程序: import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class MIDlet1 extends MIDlet implements CommandListener { private Display display; // 引用Display对象 private TextBox tbxMain; // 显示消息的文本框 private Command cmdExit; // 退出MIDlet的命令 // 构造程序 public MIDlet1() { display = Display.getDisplay(this); cmdExit = new Command("Exit", Command.SCREEN, 1); tbxMain = new TextBox("MIDlet 1", "Welcome", 50, 0); tbxMain.addCommand(cmdExit); tbxMain.setCommandListener(this); } // 启动MIDlet时由应用程序管理器调用 public void startApp() { display.setCurrent(tbxMain); } // 一个必要的方法 public void pauseApp() { } // 一个必要的方法 public void destroyApp(boolean unconditional) { } file://检查一下是否选择Exit命令 public void commandAction(Command c, Displayable s) { if (c == cmdExit) { destroyApp(false); notifyDestroyed(); } } }
第二个MIDlet使用List组件显示消息(MIDlet2.java): import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class MIDlet2 extends MIDlet implements CommandListener { private Display display; file://引用Display对象 private List lstMain; private Command cmdExit; // 退出 MIDlet的命令 // 构造程序 public MIDlet2() { display = Display.getDisplay(this); cmdExit = new Command("Exit", Command.SCREEN, 1); lstMain = new List("MIDlet 2", Choice.IMPLICIT); lstMain.append("Welcome Back", null); lstMain.addCommand(cmdExit); lstMain.setCommandListener(this); } file://启动MIDlet时由应用程序管理器调用 public void startApp() { display.setCurrent(lstMain); } file://一个必要的方法 public void pauseApp() { } file://一个必要的方法 public void destroyApp(boolean unconditional) { } file://检查一下是否选择Exit命令 public void commandAction(Command c, Displayable s) { if (c == cmdExit) { destroyApp(false); notifyDestroyed(); } } }
第一个程序名为 MIDlet1.java,第二个程序名为 MIDlet2.java。在你保存这些文件的目录里,运行下列命令编译并预验证这些文件。 javac -bootclasspath c:mefcs*.java preverify -classpath c:mefcs;. -d . MIDlet1 MIDlet2 jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png
创建 JAR文件
创建一个新文件,取名为 manifest.txt,然后输入如下内容: MIDlet-Name: MIDlet Examples MIDlet-Version: 1.0 MIDlet-Vendor: My Corporation Inc. MIDlet-1: MIDlet1, /spin.png, MIDlet1 MIDlet-2: MIDlet2, /spin.png, MIDlet2 MicroEdition-Profile: MIDP-1.0 MicroEdition-Configuration: CLDC-1.0
运行下列命令创建一个 JAR文件:
jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png
这将创建一个名为 MIDlets.jar的 JAR文件,包括 manifest.txt文件和上面两个类文件。
注意: JAR中的清单文件名应是 manifest.mf。
创建 JAD文件
创建一个新文件,取名 MIDlets.jad: MIDlet-Name: MIDlet Examples MIDlet-Version: 1.0 MIDlet-Vendor: My Corporation Inc. MIDlet-Description: Two simple examples to show how to compile and run a MIDlet MIDlet-Jar-URL: http://localhost/MIDlets.jar MIDlet-Jar-Size: 2604 MIDlet-1: MIDlet1, /spin.png, MIDlet1 MIDlet-2: MIDlet2, /spin.png, MIDlet2
注意这两个 MIDlet的引用: MIDlet-1: MIDlet1, /spin.png, MIDlet1
MIDlet-2: MIDlet2, /spin.png
|
|
|
|