明辉手游网中心:是一个免费提供流行视频软件教程、在线学习分享的学习平台!

Java嵌入式开发之二(中) [转自yesky]

[摘要]第四节 谈谈J2ME简表  虽然配置为一组通用设备提供了最小的 Java平台,但是应用程序开发者感兴趣的是为一个个别的设备生产应用程序,当他们只是使用配置的话,他们编写的应用程序就会有一些欠缺。 配置必须满足所有的设备的最小的要求, 用户界面、输入机制和数据持久性有高度地设备具体性,每一种设备都有...
第四节 谈谈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实例取回报价。
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数据库,通过把一个字节数组当成记录添加到数据库中的形式。