Java资源网

| JAVA基础 | 环境配置 | JDBC | 线程技术 | Socket编程 | JavaMail | JAVA与XML | 设计模式 | 技术新闻 | Java认证 | 程序人生 软件下载
| JSP&Servlet | Spring | Struts | Hibernate | JBuilder | Eclipse | WebService | EJB技术 | J2ME开发 | 应用服务器 | JXTA | Ajax
Articles search文章搜索
   关键字:
   类 别:
       
New download 最新下载
· [组件]HTML Parser 1.5
· [教程]WebSphere Studio应用教程
· [组件]JDom 1.0
· [工具]Junit3.8.1
· [教程]EJB编程及J2EE系统架构和设计
· [教程]EJB教程
· [教程]J2EE Tutorial中文版
· [教程]Java编程思想2(英文)
· [教程]java编程思想(完整版)
· [教程]Java网络编程
New articles 最新文章
· 设计移动 Web 服务
· 解析XML的时候完全忽略DTD
· 理解XML Schema XML Schema 初步
· 标签库的深入研究
· 提升JSP应用程序的七大绝招
· 如何使用JDOM对XML文件进行操作
· 处理XML字符串中特殊字符
· 利用Digester把XML转换成为Java对象
· 使用WebService 和RMI远程协作
· 使用Axis开发Web Service程序
Articles top 热门文章
· Eclipse基础--plugin插件安装(6644)
· eclipse+tomcat+lomboz的安装配置说明(4774)
· Java程序员就业前景(4584)
· Windows下JAVA环境变量的设置祥解(3788)
· Tomcat下JSP、Servlet和JavaBean环境的配置(3716)
· 使用links方式安装Eclipse插件(3698)
· 一个老程序员的心理话(3533)
· linux下jdk的安装与配置(3459)
· 初学者入门:Structs中基本配置入门(3334)
· Eclipse 运行命令行参数大全(3084)
您的位置:首页>>J2ME开发>>创建基于MIDP的应用(下)
创建基于MIDP的应用(下)
2005-06-09   来源:yesky  作者:QQ新人类
  ChoiceGroup

  ShowStockList()方法用来由股票的Vector变量中得到Stock对象。然后它就会创建一个ChoiceGroup对象,该对象带有用户可以售卖的股票的一个列表。ChoiceGroup是你可以加入到一个Form screen的一个项目。它可组合成一个带有数目和选项的列表,不过它不是一个screen类型。在这个屏幕中,list被设置为EXCLUSIVE,因此用户每次只可以选择一个股票出售。

private Item showStockList(Vector stocks)
{
 Stock currentStock = null;

 _stockList = new ChoiceGroup("Choose stock", ChoiceGroup.EXCLUSIVE);

 for ( int i = 0; i < stocks.size(); i++)
 {
  currentStock = (Stock) stocks.elementAt(i);
  _stockList.append( currentStock.getSymbol(), null );
 }

 return _stockList;
}

  SelectStockScreen的commandAction()方法用来转移屏幕的控制,将用户选择股票售卖的屏幕转移到真正执行股票售卖的屏幕。这个方法由股票列表中接收当前选择的股票,并且将该字符串传送给SellStockScreen。


public void commandAction( Command c, Displayable d)
{
 if ( c == backCommand)
 {
  _controller.lastScreen();
 }
 else
 {
  // get the selected item
  int selectedIndex = _stockList.getSelectedIndex();

  String selectedStock = _stockList.getString( selectedIndex);

  // move on to the SellStockScreen
  SellStockScreen sellStockScreen =
  new SellStockScreen(_controller, selectedStock);

  _controller.nextScreen( sellStockScreen);
 }
}
  SellStockScreen

  SellStockScreen是用来显示一个信息,让用户可确认上次选择的股票买卖。如果用户选择“Next”按钮,该股票就会由数据库中移除。

  该对象的构造体将接收一个Controller类的引用,以及一个代表所售股票的String。这个屏幕将会访问StockDatabase对象得到数据库中相应股票数目的信息。然后它将通过使用displayScreen()方法来将该信息显示在屏幕上(我们上面已经讨论过该方法)。

public SellStockScreen(Controller controller, String selectedStock)
{
super("Sell "+ selectedStock, controller);

append("Selling " + selectedStock);

try
{
// determine how many shares the user has
_sellStock = _stockDB.getStock( selectedStock);

_symbol = _sellStock.getSymbol();
_numShares = _sellStock.getNumShares();

// display screen
super.displayScreen(_symbol, _numShares);

this.setCommandListener( this);

}
catch (StockException se)
{
System.out.println("EXCEPTION "+ se.getMessage() );
}
}

  CommandAction()方法将用来处理用户的交互。如果用户点击 “Next”按钮。StockDatabase将会售卖相应的股票。在这个例子中,SellStockScreen并不允许用户修改要售卖的股票数目。然后显示将会返回到WelcomeScreen。

public void commandAction( Command c, Displayable d)
{
if ( c == backCommand)
{
_controller.lastScreen();
}
else
{
// sell the shares
try
{
_stockDB.sellStock( _sellStock, _numShares);
}
catch (StockException se)
{
se.printStackTrace();
}

_controller.nextScreen( new WelcomeScreen( _controller) );
}
}
  Stock对象

  在这个例子中常常看到的Stock对象,它是一个包含有一个构造体和一套getXYZ()方法的简单对象。和我上面讨论的RecordStore架构一样,主要的方法是:

public Stock(String symbol, int numShares, int price)
{
 _symbol = symbol;
 _numShares = numShares;
 _price = price;
}

public String getSymbol(){ return _symbol; }
public int getNumShares(){ return _numShares; }
public int getPrice(){ return _price; }


  RMSStockStore

  讨论完该例子的应用层后,我将和你探讨一下数据存储层。在我以前的讨论中,数据存储仅是通过StockDatabase接口访问的。现在我将讨论一下实现该接口的对象。

  这个例子中的RMSStockStore对象用来处理所有和RecordStore相关的活动。该对象包含有一个到javax.microedition.rms.RecordStore对象的引用,它是MIDP API的一部分。

public class RMSStockStore implements RecordFilter, RecordComparator, _
  StockDatabase

  RMSStockStore对象的构造器将会初始化一个指向“共享”data store的RecordStore对象。如果不存在该data store,它将会创建一个。

public RMSStockStore()
{
try
{
String fileName = "shares";
recordStore = RecordStore.openRecordStore(fileName, true);
}
catch (RecordStoreException rse)
{
System.out.println(rse);
rse.printStackTrace();
}
}

  addStock()是该对象用来执行真正写入data store的一个内部方法。要注意的是,加入到record store时,要存储的数据必须从一个对象或者一系列的对象转变为一个byte数组。这个转换是通过StockStorage类来完成的,我将在下文继续讨论。转换为byte数组后,就可以调用addRecord()方法,将该数组传送到RecordStore对象中。

private void addStock(int shares, String symbolName, int price)
{
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 DataOutputStream outputStream = new DataOutputStream(baos);

 try {
  Stock outputStock = new Stock( symbolName, shares, price);

  StockStorage.writeStock( outputStock, outputStream);

 }
 catch (IOException ioe) {
  System.out.println(ioe);
  ioe.printStackTrace();
 }

 // Extract the byte array
 byte[] b = baos.toByteArray();

 // Add it to the record store
 try {
  recordStore.addRecord(b, 0, b.length);
 }
 catch (RecordStoreException rse) {
  System.out.println(rse);
  rse.printStackTrace();
 }
}

  getStockHelper()方法用来作为getStock()和getStocks()方法的一个助手。 getStockHelper()方法可列举出RecordStore返回的记录集。这样它就可以读取这些记录,并且将它加入到一个Vector中,然后传送回用户接口对象中。要注意到,StockStorage对象可用来将InputStream (byte array)转换为一个Stock对象。

private Vector getStockHelper(RecordEnumeration re)
{
 Vector stockVector = new Vector();

 try {
  while(re.hasNextElement())
  {
   int id = re.nextRecordId();
   ByteArrayInputStream bais =
   new ByteArrayInputStream(recordStore.getRecord(id));
   DataInputStream inputStream = new DataInputStream(bais);
   try {
    Stock stock = StockStorage.readStock(inputStream);

    stockVector.addElement( stock);
   }
   catch (EOFException eofe) {
    System.out.println(eofe);
    eofe.printStackTrace();
   }
  }
 }
 ...

 return stockVector;
}
  RecordStore

  在上面讨论的代码中,包含有javax.microedition.rms.RecordStore对象的引用。以下就是在这个例子中用到的该对象的方法子集:

  openRecordStore(): 用来打开/创建一个record store

  addRecord(): 用来在该store中加入一个记录

  enumerateRecords(): 用来遍历record store的记录

  getRecord(): 用来从record store中得到一个特定的记录

  deleteRecord(): 用来从record store中移除一个记录

  RecordStore为MIDP平台提供了一个方便而且灵活的存储系统,使用RecordStore,一个应用可存储各种的信息,由原始的数据类型到复杂的串行化对象。

  RecordComparator

  RMSStockStore对象实现了javax.microedition.rms.RecordComparator接口。在需要将通过store得到的数据进行排序时,该接口将会被传送到RecordStore。实现RecordComparator的对象必须实现其compare()方法,这个方法用来决定数据库中两个记录的排列顺序。

  在RMSStockStore对象包含的compare方法的实现中,将数据库中的两个记录作对比,在此是两只股票的记号。两个记录都通过InputStreams由byte数组转换为stock对象。每只股票的记号可以通过getSymbol()方法得到,然后使用String compareTo()方法进行对比。该方法返回三个可能的int,根据结果的不同,分别是代表少于、等于或者大于。

public int compare(byte[] rec1, byte[] rec2)
{
 ...
 try {
  // Extract the stocks.
  Stock stock1 = StockStorage.readStock(inputStream1);
  Stock stock2 = StockStorage.readStock(inputStream2);

  String symbol1 = stock1.getSymbol();
  String symbol2 = stock2.getSymbol();

  compareValue = symbol1.compareTo(symbol2);
 }
 ...

  根据返回值的不同,它们被返回到RecordStore,以便决定如何组织RecordEnumerator中的行。如果对于不同的查询有不同的标准的话,你可以使用多个RecordComparator对象。

...
// Sort by symbol name
if (compareValue < 0) {
 return RecordComparator.PRECEDES;
}
else if (compareValue > 0) {
 return RecordComparator.FOLLOWS;
}
else {
 return RecordComparator.EQUIVALENT;
}
}
  RecordFilter

  RMSStockStore对象实现javax.microedition.rms.RecordFilter接口。该接口需要实现一个称为matches()的方法。这个方法做为一个过滤器使用,可让RecordStore决定一个给定的字节数组是否符合当前的查询。在这个例子中,RecordFilter是用来从数据库中得到一个单一股票的值。因此。matches()必须用来确保仅有符合该股票的相应记录才被显示。

  下面的代码再次讲解了使用StockStorage()方法由InputStream中得到股票记录的方法。股票的名字通过使用getSymbol()方法由对象中得到。要注意的是返回的语句执行对比的处理,将存储为一个类变量的过滤器值和股票的名字作对比。

public boolean matches(byte[] candidate)
throws IllegalArgumentException
{
 // If no filter set, nothing can match it.
 if (this.symbolFilter == null) {
  return false;
 }

 ByteArrayInputStream bais = new ByteArrayInputStream(candidate);
 DataInputStream inputStream = new DataInputStream(bais);
 String name = null;

 try {

  Stock stock = StockStorage.readStock(inputStream);
  int shares = stock.getNumShares();
  name = stock.getSymbol();
 }
 ...
 return (this.symbolFilter.equals(name));
}

  仅有返回值为真的记录才会出现在查找结果集中。

  StockDatabase

  RMSStockStore对象实现了这个例子中定义的StockDatabase接口。这些方法使用helper方法和StockStorage对象来执行与它们名字相应的操作。

  buyStock()方法用来加入一只股票到RecordStore中。当用户加入一只股票时,就会由BuyStockScreen调用这个方法。

public void buyStock(String symbol, String shares, int price) throws StockException
{
 int numShares = 0;

 try
 {
  numShares = Integer.parseInt( shares);
 }
 catch( NumberFormatException nfe)
 {
  throw new StockException("Number of shares value is invalid", nfe);
 }

  buyStock()方法执行一些基本的字段验证,确保值存在而且有着正确的格式。

if ( numShares <= 0 || price <= 0 || symbol.length() == 0)
{
 throw new StockException("Invalid Data passed to RMS", null);
}

  这个例子限制用户只可输入一只股票。为此,buyStock()方法必须查找以决定给定的股票是否已经存在。

// check if there are existing shares
Stock stock = getStock( symbol);

  如果股票不存在,它就会将该股票加入到记录中。

if ( stock == null)
{
 // add the new shares
 addStock( numShares, symbol, price);
}

  如果该股票存在,第一个项目将会由数据库中移除,并且加入一个新的记录。要注意的是,你可以使用RecordStore.setRecord()方法来执行这两个步骤。我这样做的原因只是为了令例子简化。

else
{
sellStock( stock, stock.getNumShares() );

addStock( numShares + stock.getNumShares(), symbol, price);
}

  sellStock()方法被buyStock()方法和SellStockScreen调用。这个方法是用来由data store中移除一只股票的。

public void sellStock(Stock stock, int numShares) throws StockException

  symbolFilter的值被设置为要出售的股票记号。上文已经提过,RecordComparator使用这个值,在它的matches()方法中来决定哪个记录符合要求。

// delete entry from the database
this.symbolFilter = stock.getSymbol();

Stock retrievedStock = null;

  通过使用RecordFilter接口,RecordStore提供一个查询的机制。要获得记录的一个列表,可传送RecordFilter实例到enumerateRecords()方法中。这个过滤器将会确保只有包含有这个记号的记录才会返回。通过传送RecordComparator,RecordStore将会以要求的排序方式返回记录。在这个例子中,RMSRecordStore实现了RecordComparator和RecordFilter,因此它们被作为this传送。

try {
 RecordEnumeration re = recordStore.enumerateRecords(this, this, true);

 while(re.hasNextElement())
 {
  int id = re.nextRecordId();
  ByteArrayInputStream bais =
  new ByteArrayInputStream(recordStore.getRecord(id));
  DataInputStream inputStream = new DataInputStream(bais);
  try {
   retrievedStock = StockStorage.readStock(inputStream);

  要根据记录的id值来移除它

recordStore.deleteRecord( id);
...

  getStocks()方法用来得到用户所有股票的一个列表。该方法将返回股票对象的一个Vector,它被SelectUserScreen用来得到股票的列表。要注意到所传送的RecordFilter的值为null。这是确保所有数据库中的记录都被返回,而无需使用过滤器。

public Vector getStocks() throws StockException
{
 Vector stockVector = new Vector();

 try {
  // Enumerate the records using the comparator implemented
  // above to sort by game symbol.
   RecordEnumeration re = recordStore.enumerateRecords(null, this,
true);
  stockVector = getStockHelper(re);
 }
 catch (RecordStoreException rse) {
  System.out.println(rse);
  rse.printStackTrace();
}

  如果Vector是空的,就会抛出一个例外,因为如果用户以前没有购买过一只股票,是不能使用这个方法的。

if ( stockVector.size() == 0)
throw new StockException("No Stocks found in portfolio.");

return stockVector;
}
  StockStorage

  StockStorage对象是为了将Stock对象的存储封装到一个类中。所有其它的类都可接收和存储Stock对象到RecordStore中,而无需知道数据的存储格式。RecordStore本身也不知道Stock对象在数据库中的格式。如果你要存储购买股票的日期,你只需要修改StockStorage对象中的字段就可以了(无需对应用的其它部分作修改)。

  Stock对象被存储为:

  
字段 描述
Number of shares Integer字段
Symbol UTF
Cost Integer字段

  通过分离该对象的存储信息,其余的应用就无需关心最低级的细节。

  writeStock()方法将会由Stock对象中接收值,并且传送它们到OutputStream。

public static void writeStock(Stock stock, DataOutputStream outputStream)
throws IOException
{
 // Push the number of shares into a byte array.
 outputStream.writeInt( stock.getNumShares() );

 // Then push the stock name.
 outputStream.writeUTF( stock.getSymbol() );

 // push the stock price
 outputStream.writeInt( stock.getPrice() );
}

  readStock()方法将会由InputStrean中得到值,并且创建一个新的Stock对象,以留给应用操作之用。

public static Stock readStock(DataInputStream inputStream) throws IOException
{
 // read the number of shares
 int numShares = inputStream.readInt();

 // read the stock symbol
 String symbol = inputStream.readUTF();

 // read the stock price
 int price = inputStream.readInt();

 // return a new Stock object
 return new Stock( symbol, numShares, price);
}

  结论:

  本文介绍了在MIDP平台上创建应用时,你可以使用的不同组件。我集中介绍了两个组件:用户界面组件和data store组件。

  在这个例子中,我将这两个组件结合在一起,并且讨论了这些组件和其它MIDP平台上的组件的交互。

  在用户界面部分,我介绍了在MIDP设备上创建应用时,可使用的大部分UI组件。此外,我还介绍了一些便于进行MIDlet开发的概念,例如MVC方法,使用接口作封装,以及使用继承以作重用。

  在数据存储(data store)方面,我介绍了MIDP平台上用作数据存储应用的主要组件。任何基于数据存储的应用将使用一个或者多个RecordStore对象,并且实现一个或者多个RecordFilters 和 RecordComparators。这些都是数据存储应用的基本组件。此外,我还介绍了主要功能的封装---可减少数据存储格式的负担,同时可为UI开发者提供一个干净的API。

  对于这个简单的应用,你还可以作很多的改进,简化的原因主要是为了更好地理解其中的关键概念。在本系列的下一部分,我将会扩展这个应用,包括通过HTTP请求来得到股票信息和一个档案跟踪组件。

  --相关文章--
· 详细介绍手机游戏中的声音处理 (2007-04-17)
· 让JavaME程序实现真正Run Anywhere (2007-04-17)
· 端到端J2ME应用开发实例——介绍Smart Ticket (2007-04-17)
· 移动开发谁领风骚 J2ME开发工具面面观 (2007-04-17)
· 用NetBeans平台开发J2ME游戏实例讲解3 (2007-04-17)
· 用NetBeans平台开发J2ME游戏实例讲解2 (2007-04-17)

版权所有©2005-2006 JAVA资源网 渝ICP备05007591号 虚拟主机 | 关于我们 | 联系方式 | 广告业务 | 网站地图 | 友情链接