网站导航免费论文 原创论文 论文搜索 原创论文 网学软件 学术大家 资料中心 会员中心 问题解答 原创论文 论文素材 设计下载 最新论文 下载排行 论文上传 在线投稿 联系我们
返回网学首页
网学联系
最新论文 推荐专题 热门论文 素材专题
当前位置: 网学 > 编程文档 > JSP > 正文
J2ME 101,第 3 部分: 深入记录管理系统
来源:Http://myeducs.cn 联系QQ:点击这里给我发消息 作者: 用户投稿 来源: 网络 发布时间: 12/11/29
下载{$ArticleTitle}原创论文样式

  数据存储和检索是应用程序开发的重要方面。存储什么样的数据取决于应用程序的类型和复杂度。在某些情况下,被存储的持久数据仅仅是应用程序用户的首选项信息。在另外一些情况下,您可能需要存储和管理一个联系信息库。在极端的情况下,您可能要为整个供应链数据设计一个数据存储方案。不论是哪一种情况,对于支持 MIDP 的设备来说只有一种通用的数据存储和管理方案,那就是记录管理系统 (RMS)。

  作为 J2ME 101 教程系列的补充系列两篇文章中的第一篇,本文将向您介绍 MIDP 持久存储系统的内部工作原理。我们将从 RMS 的概览开始,不过大部分内容(如同教程系列一样)更倾向于实际应用。并且,我们将会构建一些 MIDlet,帮助您了解如何从 RMS 中读取和写入数据记录,并了解这个功能非常全面而紧凑的数据管理系统的各种排序、搜索和检索选项。

  注意,本文假设您熟悉 J2ME 环境中的 MIDlet 开发。为了编译代码示例,系统上需要安装 J2ME 开发环境。请参阅 参考资料 部分,其中有 J2ME Wireless Toolkit(WTK)安装指南的超链接

  MIDP 中的记录管理

  简单地说,MIDP 记录管理系统(RMS)提供了一种跨多个 MIDlet 调用持久性地存储应用程序数据的手段。您可以把 RMS 记录存储看作一个简单的数据库,其中每一行都包括两列:一列用于存储惟一的行标识,另外一列存储代表记录中数据的一组字节。表 1 展示了一个简单的记录存储数据库。

  表 1. 一个记录存储数据库

记录 ID 数据
1字节数组
2字节数组
3字节数组
......

  惟一行标识是一个整型值。第一个条目的 ID 为 1,然后是 2,以此类推。一行被删除之后,它的行标识不会被重用。也就是说,如果表中有三行,ID 分别是 1,2 和 3,删除 ID 2 将把这个标识永久性地从记录存储中删除。如果我们向这个表中添加另外一行,那么该行的标识将会是 4。

  记录存储是用名称来标识的。记录存储的名称最多可以包含 32 个字符,并且所有字符都是大小写敏感的。同一个 MIDlet 套件(即打包在一起的一个或多个 MIDlet)中不会包含两个名称相同的记录存储。

  每个记录存储都有一个版本号和一个日期/时间戳。在添加、替换或删除一个记录时,这两个值都会被更新。

  创建一个记录存储

  没有用于创建记录存储的构造函数。相反,我们使用三个双功能的方法来创建和/或打开记录存储。清单 1 列出了这三个方法。

  清单 1. 创建和打开记录存储

RecordStore openRecordStore(String recordStoreName,
                boolean createIfNecessary)
RecordStore openRecordStore(String recordStoreName,
                boolean createIfNecessary,
                int authmode,
                boolean writable)
RecordStore openRecordStore(String recordStoreName,
                String vendorName,
                String suiteName)

  如果指定的记录存储存在,第一个方法将会打开它。如果指定的记录存储不存在,并且参数 createIfNecessary 被设为 true ,该方法可以创建一个新的(指定名称的)记录存储。第二个方法与第一个类似,只不过使用另外两个附加参数来指定记录存储的访问限制。第一个参数指定是否只有位于相同套件中的 MIDlet 才能访问这个记录存储。第二个参数指定有权访问记录存储的 MIDlet 是否可以创建一个新记录。最后一个方法提供了让 MIDlet 打开在另外的 MIDlet 套件中的记录存储的方法。

  RecordStore API

  有多个操纵记录存储的方法可供使用。涉及的范围从添加、删除、替换记录内容到枚举整个记录存储。清单 2 列出了所有可用的方法。

  清单 2. 记录存储方法

void closeRecordStore()
void deleteRecordStore(String recordStoreName)
String[] listRecordStores()
int addRecord(byte[] data, int offset, int numBytes)
void setRecord(int recordId, byte[] newData, int offset, int numBytes)
void deleteRecord (int recordId)
byte[] getRecord (int recordId)
int getRecord (int recordId, byte[] buffer, int offset)
int getRecordSize (int recordId)
int getNextRecordID()
int getNumRecords()
long getLastModified()
int getVersion()
String getName()
int getSize()
int getSizeAvailable()
RecordEnumeration enumerateRecords(RecordFilter filter,
                   RecordComparator comparator,
                   boolean keepUpdated)
void addRecordListener (RecordListener listener)
void removeRecordListener (RecordListener listener)
void setMode(int authmode, boolean writable)

  通过后面几节介绍的例子,您将会更多地了解 RecordStore API 和它的方法。

  ReadWrite MIDlet

  我们的第一个展示例子是 ReadWrite MIDlet。这个 MIDlet 的功能包括:创建记录存储、把多条记录写入持久存储中、读取这些记录、退出时删除记录存储。在查看下面的代码时,请注意这个 MIDlet 包含了几个“便利”方法,这些方法在使用 RMS 的过程中被反复使用。便利方法就是那些用来打开、关闭和删除记录存储的方法。

  请阅读 ReadWrite MIDlet的完整代码,下面我们将详细讨论它。

  关于代码的说明

  在继续讨论之前有几点值得一提。首先,就像前面解释过的,在这个例子中我们在调用 RecordStore.openRecordStore(REC_STORE, true) 时, createIfNecessary 参数传递的是 true 以创建一个新的记录存储。

  其次,当使用 writeRecord(String str) 向记录存储中写入数据时,我们首先把 Java 字符串参数转换成一个字节数组。然后把这个字节数组传递给 addRecord(rec, 0, rec.length) 方法以向记录存储中插入一条记录。

  最后,在 readRecords() 方法中,我们分配了一个字节数组用于存储从 RMS 中读取的记录数据。这需要我们在每次读取时都进行一个特定的检查,以保证数组的长度足够容纳数据。提取记录以后,我们就可以把内容输出到控制台。

  图 1 展示了 ReadWrite MIDlet 在 J2ME WTK 中运行时得到的输出。

  图 1. ReadWrite MIDlet 的记录输出

J2ME 101,第 3 部分: 深入记录管理系统

  读取和写入 Java 基本类型

  ReadWrite MIDlet 只能将文本字符串写入到记录存储中。在接下来的例子中,我们将增加存储和操纵整型、布尔型和字符串值的功能。我们还将添对加用 Java 流进行读写的支持。同前面的例子一样,我们将会写入几条记录,然后再从存储中将它们读出。

  像所有需要访问记录存储的 MIDlet 一样,我们首先使用 openRecordStore() 方法分配和打开(或创建)一个记录存储,如清单 3 所示。

  清单 3. 创建一个记录存储

private RecordStore rs = null;  // Record store
...
public void openRecStore()
{
   ...
   // Create record store if it does not exist
   rs = RecordStore.openRecordStore(REC_STORE, true);
   ...
}

  清单 4 显示了我们将会写入到记录存储中的基本数据类型。

  清单 4. Java 基本数据类型

public void writeTestData()
{
   boolean[] booleans = {true,false};
   int[] integers = {17 , 4};
   String[] strings = {"Golf", "Tennis"};
   writeStream(booleans, integers, strings);
}

  如果熟悉 Java 语言中流的用法,您会发现使用 MIDlet 与使用更传统的 Java 应用程序稍有不同。在 MIDlet 中使用流的步骤如下:

  分配流。

  写入数据。

  清空流。

  把流数据转移到数组中。

  把数组写入到记录存储。

  关闭流。

  清单 5 展示了如何使用流向 RMS 中写入数据:

  清单 5. 把流写入到记录存储

public void writeStream(boolean[] bData, int[] iData, String[] sData)
{
   try
   {
    // Write data into an internal byte array
    ByteArrayOutputStream strmBytes = new ByteArrayOutputStream();
    // Write Java data types into the above byte array
    DataOutputStream strmDataType = new DataOutputStream(strmBytes);
    byte[] record;
    for (int i = 0; i < sData.length; i++)
    {
     // Write Java data types
     strmDataType.writeBoolean(bData[i]);
     strmDataType.writeInt(iData[i]);
     strmDataType.writeUTF(sData[i]);
     // Clear any buffered data
     strmDataType.flush();
     // Get stream data into byte array and write record
     record = strmBytes.toByteArray();
     rs.addRecord(record, 0, record.length);
     // Toss any data in the internal array so writes
     // starts at beginning (of the internal array)
     strmBytes.reset();
    }
    strmBytes.close();
    strmDataType.close();
   }
   catch (Exception e)
   {
    db(e.toString());
   }
}

  然后,我们要从记录存储中读取数据。首先创建必要的输入流,然后遍历所有记录,把其中的内容存储到一个字节数组。通过访问数据输入流,我们从字节数组中读取每一个 Java 基本类型,并把相应的内容输出到控制台。如清单 6 所示。

  清单 6. 从记录存储中读取流

public void readStream()
{
   try
   {
    // Allocate space to hold each record
    byte[] recData = new byte[50];
    // Read from the specified byte array
    ByteArrayInputStream strmBytes = new ByteArrayInputStream(recData);
    // Read Java data types from the above byte array
    DataInputStream strmDataType = new DataInputStream(strmBytes);
    for (int i = 1; i <= rs.getNumRecords(); i++)
    {
     // Get data into the byte array
     rs.getRecord(i, recData, 0);
     // Read back the data types
     System.out.println("Record #" + i);
     System.out.println("Boolean: " + strmDataType.readBoolean());
     System.out.println("Integer: " + strmDataType.readInt());
     System.out.println("String: " + strmDataType.readUTF());
     System.out.println("--------------------");
     // Reset so read starts at beginning of array
     strmBytes.reset();
    }
    strmBytes.close();
    strmDataType.close();
   }
   catch (Exception e)
   {
    db(e.toString());
   }
}

  现在检查 ReadWritePrimitives MIDlet的源代码。请仔细研究,如果愿意的话,您也可以在自己的 WTK 模拟器中运行这段代码以查看输出。

  ReadWritePrimitives MIDlet 的控制台输出如图 2 所示。

  图 2. ReadWritePrimitives MIDlet 的输出

J2ME 101,第 3 部分: 深入记录管理系统

  RecordEnumeration API

  至此,我们已经使用一个简单的 for 循环遍历了记录存储。尽管这种技术已经足以满足我们的需求,在这一节,我们还是会扩展自己的代码,加入一个记录枚举器看看会有什么结果。在代码中加入一个记录枚举器的一个最大好处在于枚举器中包含搜索记录存储以及以排序的顺序提取记录的选项。

  清单 7 列出了 RecordEnumeration API 的方法。&#160

  清单 7. RecordEnumeration API

int numRecords()
byte[] nextRecord()
int nextRecordId()
byte[] previousRecord()
int previousRecordId()
boolean hasNextElement()
boolean haspreviousElement()
void keepUpdated(boolean keepUpdated)
boolean isKeptUpdated()
void rebuild()
void reset()
void destroy()

  为代码添加枚举功能非常简单,只需在一个打开的记录存储上创建一个 RecordEnumeration 对象并遍历所有记录即可。清单 8 展示了如何创建一个 RecordEnumeration 。前面两个参数(在本例中都是 null )指定在记录存储上进行搜索和/或排序的类。第三个参数是 API 中定义的 keepUpdated 标志。如果这个变量设置为 true ,当记录存储发生改变时,枚举结果集将被重新初始化。将这个参数设置为 false 则指定枚举忽略记录存储的更新。

  清单 8. 创建一个 RecordEnumeration

rs = RecordStore.openRecordStore(REC_STORE, true);
...
RecordEnumeration re = rs.enumerateRecords(null, null, false);
while (re.hasNextElement())
{
   // Get next record
   String str = new String(re.nextRecord());
   ...
}

  为什么需要记录枚举

  乍一看,枚举循环提供的功能与 for 循环提供的没什么不同,但实际上它提供了多得多的功能。除了提供一种搜索和排序的手段(我们马上将会看到),记录枚举还克服了 for 循环的最大弊端(尽管不是一眼就能看出来)。

  本文开头部分曾经提到记录 ID 不能在记录存储中被重用。因此,如果一个存储有三条记录,ID 分别为 1,2 和 3,当 ID 2 被删除时,存储中就只剩下 ID 1 和 3。如果不去考虑我们是如何遍历记录存储的,那么这不会是一个问题。清单 9 中的代码将改变您的想法。

  清单 9. 一个读取记录的典型 for 循环

byte[] recData = new byte[5];
int len;
for (int i = 1; i <= rs.getNumRecords(); i++)
{
   // Allocate more storage if necessary
   if (rs.getRecordSize(i) > recData.length)
    recData = new byte[rs.getRecordSize(i)];
   len = rs.getRecord(i, recData, 0);
}

  您可能已经发现了,代码的最后一行将会带来问题。尽管 getNumRecords() 可以返回正确的记录数(两条),但是 for 循环返回的变量 i 的值将会是 1 和 2。但是在存储中的记录 ID 是 1 和 3。当 i 等于 2 时对 rs.getRecord() 的调用将会失败,因为已经没有记录 ID 为 2 的记录了。这正是记录枚举可以发挥作用的地方,因为它不是根据 ID 来获取记录。

  RecordComparator API

  RecordEnumeration API 提供了使用枚举的基础,使得我们可以遍历 RMS 中所有条目。真正让我们可以按顺序从记录存储中提取数据的是 RecordComparator 接口。

  RecordComparator API 包括一个方法和三个预定义的返回值。该接口中惟一的方法接收两个参数,它们都是字节数组。在清单 10 中,您可以了解到这两个数组如何表示来自记录存储的记录。枚举调用 compare() 方法,把来自存储的两个记录的内容作为参数传递给该方法。枚举和我们的搜索代码将遍历整个记录存储,根据指定的搜索条件构建一个排序过的结果集。

  清单 10. RecordComparator API

int compare(byte[] rec1, byte[] rec2)
static int EQUIVALENT
static int FOLLOWS
static int PRECEDES

  清单 11 展示了一个实现了 Comparator 接口的简单类,它通过比较每条记录的字符串内容对记录进行排序。注意,返回值必须是预定义的值: EQUIVALENT , PRECEDES 或 FOLLOWS 。紧跟 comparator 类之后的代码创建了一个比较器的实例,并在创建记录枚举时将其作为一个参数。

  清单 11. 一个用于排序的 Comparator 类

//********************************************************
// Create comparator class for sorting
//********************************************************
public class comparator implements RecordComparator
{
   public int compare(byte[] rec1, byte[] rec2)
   {
    String str1 = new String(rec1), str2 = new String(rec2);
    int result = str1.compareTo(str2);
    if (result == 0)
     return RecordComparator.EQUIVALENT;
    else if (result < 0)
     return RecordComparator.PRECEDES;
    else
     return RecordComparator.FOLLOWS;
   }
}
...
//********************************************************
// How to Access the comparator using a record enumeration
//
// Note: Variable 'rs' is created outside the scope of
//    this method
//********************************************************
// Create a new comparator for sorting
comparator comp = new comparator();
// Reference the comparator when creating the result set
RecordEnumeration re = rs.enumerateRecords(null, comp, false);
// Retrieve each record in sorted order
while (re.hasNextElement())
{
   String str = new String(re.nextRecord());
   ...
}

  排序多种数据类型

  显然,对只包含字符串数据的记录进行排序非常简单。然而,对每条记录都包含不同数据类型的记录存储进行排序要复杂一些。例如,请回忆一下 清单 4,在这个例子中我们在每条记录中写入三种基本 Java 数据类型,它们分别是 boolean、integer 和 string。怎样才能根据其中特定的一种类型进行排序呢?为了做到这一点,比较器函数需要获取用于比较的适当字段,执行比较,然后向枚举器返回适当的值( EQUIVALENT , PRECEDES 或 FOLLOWS )。

  为了更好地理解这一过程,我们来编写一个根据整型进行排序的 MIDlet。首先,我们将更新 清单 4 中的 writeTestData() 方法,使记录存储中的每条记录既包含字符串数据,也包含整型数据,如下所示:

  清单 12. 用于排序的 Java 基本数据类型

public void writeTestData()
{
   String[] strings = {"Java", "J2ME", "C"};
   int[] integers = {2, 1, 3};
   writeStream(strings, integers);
}

  IntegerSort MIDlet 的输出如图 3 所示。注意,比较器函数(我们马上将会讲到)返回根据每条记录中整型值排序之后的多条记录。

  图 3. 根据整型值进行排序的记录

J2ME 101,第 3 部分: 深入记录管理系统

  构建一个比较器

  IntegerSort MIDlet 的代码(请参阅 完整的源代码)与前面的 MIDlet 在整体上差别不大。最大的改变是添加了 comparator 类(清单 13)以及抽取适当字段并进行实际排序的方法。以下是为 IntegerSort MIDlet 处理所有细节的 ComparatorInteger 类。

  清单 13. ComparatorInteger 类

/*--------------------------------------------------
* Compares two integers to determine sort order
* Each record passed in contains multiple Java data
* types - use only the integer data for sorting
*-------------------------------------------------*/
class ComparatorInteger implements RecordComparator
{
   private byte[] recData = new byte[10];
   // Read from a specified byte array
   private ByteArrayInputStream strmBytes = null;
   // Read Java data types from the above byte array
   private DataInputStream strmDataType = null;
   public void compareIntClose()
   {
    try
    {
     if (strmBytes != null)
      strmBytes.close();
     if (strmDataType != null)
      strmDataType.close();
    }
    catch (Exception e)
    {}
   }
   public int compare(byte[] rec1, byte[] rec2)
   {
    int x1, x2;
    try
    {
     // If either record is larger than our buffer, reallocate
     int maxsize = Math.max(rec1.length, rec2.length);
     if (maxsize > recData.length)
      recData = new byte[maxsize];
     // Read record #1
     // We want the integer from the record, which is
     // the second "field" thus we must read the
     // String first to get to the integer value
     strmBytes = new ByteArrayInputStream(rec1);
     strmDataType = new DataInputStream(strmBytes);
     strmDataType.readUTF();    // Read string
     x1 = strmDataType.readInt(); // Read integer
     // Read record #2
     strmBytes = new ByteArrayInputStream(rec2);
     strmDataType = new DataInputStream(strmBytes);
     strmDataType.readUTF();    // Read string
     x2 = strmDataType.readInt(); // Read integer
     // Compare record #1 and #2
     if (x1 == x2)
      return RecordComparator.EQUIVALENT;
     else if (x1 < x2)
      return RecordComparator.PRECEDES;
     else
      return RecordComparator.FOLLOWS;
    }
    catch (Exception e)
    {
     return RecordComparator.EQUIVALENT;
    }
   }

  请注意读取 Java 基本类型的代码。我们需要从每条记录中提取出整型值,这个值是每条记录的第二个“字段”。因此,我们只是读取字符串(UTF)值并将它丢到一边。第二次读取把整型值存储在一个本地变量中(x1 或 x2)。接着,比较这些值以确定正确的排序顺序。

  清单 14. 读取并排序 Java 基本类型

// Read record #1
...
strmDataType.readUTF();    // Read string
x1 = strmDataType.readInt(); // Read integer
// Read record #2
...
strmDataType.readUTF();    // Read string
x2 = strmDataType.readInt(); // Read integer
// Compare record #1 and #2
if (x1 == x2)
   return RecordComparator.EQUIVALENT;
else if (x1 < x2)
   return RecordComparator.PRECEDES;
else
   return RecordComparator.FOLLOWS;

  构建一个枚举器

  完成比较器的编写之后,我们来创建一个枚举器,其中引用 了 ComparatorInteger 类的一个实例。这个枚举器将使用比较器作为排序算法,从记录存储创建一个记录结果集。清单 15 列出了 readStream() 方法的一部分,该方法创建比较器和枚举器,遍历整个结果集并把记录内容显示在控制台上。

  清单 15. readStream() 方法

public void readStream()
{
  ...
   if (rs.getNumRecords() > 0)
   {
    // Create instance of the comparator
    ComparatorInteger comp = new ComparatorInteger();
    // Create enumerator, referencing the comparator
    RecordEnumeration re = rs.enumerateRecords(null, comp, false);
    // Loop through all elements in the result set
    int i = 1;
    while (re.hasNextElement())
    {
     // Get data into the byte array
     rs.getRecord(re.nextRecordId(), recData, 0);
     // Read back the data types
     System.out.println("Record #" + i++);
     System.out.println("String: " + strmDataType.readUTF());
     System.out.println("Integer: " + strmDataType.readInt());
     System.out.println("--------------------");
     // Reset so read starts at beginning of array
     strmBytes.reset();
    }
   ...
}

  RecordFilter API

  使用比较器进行排序是使用枚举器时的一种选择,另外一种选择是使用过滤器进行搜索。比较器和过滤器之间的一个微小差别在于 比较器 返回排序后的整个记录存储,而 过滤器 只返回那些满足指定条件的记录。如果同时使用比较器和过滤器,那么将会按照排序顺序返回满足搜索条件的记录。

  与 RecordComparator 类似, RecordFilter 也是通过在枚举器代码中增加一个方法 matches() 实现的。枚举器对存储中的每条记录调用 matches() 方法。根据返回的布尔值,每条记录要么成为结果集的成员,要么被归为不满足搜索条件的记录放弃。

  清单 16. RecordFilter API 的 matches() 方法

boolean matches(byte[] candidate)

  构建一个过滤器

  清单 17 展示了一个实现了 RecordFilter 接口的类。注意,搜索字符串被指定为 SearchFilter 构造函数的一个参数。这个字符串被保存在私有变量中,这样当枚举器调用 matches() 方法创建结果集的时候就可以访问这个字符串。在这个例子中,搜索字符串还被转换成小写字符,因此这个搜索 不是大小写敏感的。

  清单 17. 构建一个 RecordFilter

//********************************************************
// Create filter class for searching
//********************************************************
class SearchFilter implements RecordFilter
{
   private String searchText = null;
   public SearchFilter(String searchText)
   {
    // Text to find
    this.searchText = searchText.toLowerCase();
   }
   public boolean matches(byte[] candidate)
   {
    String str = new String(candidate).toLowerCase();
    // Does the text exist?
    if (searchText != null && str.indexOf(searchText) != -1)
     return true;
    else
     return false;
   }
}
...
//********************************************************
// How to access the filter using a record enumeration
//
// Note: Variable 'rs' is created outside the scope of
//    this method
//********************************************************
// Create search filter
SearchFilter search = new SearchFilter("abc");
// Reference filter when creating the result set
RecordEnumeration re = rs.enumerateRecords(search, null, false);
// If there is at least one record in result set, a match was found
if (re.numRecords() > 0)
{
   // At least one record in the result set, do something here...
   ...
}

  注意,本例中执行实际搜索的代码非常简单。我们使用 Java 字符串的 indexOf() 方法来查找指定的搜索字符串,并返回一个表明成功还是失败的布尔值。

  StringSearch MIDlet

  我们将构建最后一个 MIDlet 来展示到目前已经学过的内容(这里是 StringSearch MIDlet 的完整源代码)。除了可以在 RMS 中搜索记录,这个 MIDlet 还加强了用户界面。这一次,我们不再只使用控制台显示输出,还将显示一个提示用户输入文本字符串的 TextField 组件(您应该可以想起教程系列中的这部分内容!)。提出请求后,我们将在记录存储中搜索这个字符串。所有匹配的字符串都添加到显示中以显示搜索结果。

  清单 18 展示了将被写入到记录存储中的搜索字符串。

  清单 18. 记录存储中的条目

public void writeTestData()
{
   String[] strs = {
           "I think this would be a good time for a beer. (FDR)",
           "I'll make it a felony to drink small beer. (Shakespeare)",
           "They who drink beer will think beer. (Washington Irving)",
           "I would give all my fame for a pot of ale. (Shakespeare)"};
   writeRecords(strs);
}

  图 4 展示了有两个不同搜索结果的 MIDlet。

  图 4. 记录搜索结果

J2ME 101,第 3 部分: 深入记录管理系统

  用户界面的创建包括指定一个 Form 、一个 TextField 和两个 Command ―― 一个用于搜索记录存储,另外一个用于退出 MIDlet,如清单 19 所示。

  清单 19. 创建用户界面组件

...
// Define textfield, stringItem and commands
tfFind = new TextField("Find", "", 12, TextField.ANY);
cmExit = new Command("Exit", Command.EXIT, 1);
cmFind = new Command("Find", Command.SCREEN, 2);
// Create the form, add commands
fmMain = new Form("Record Search");
fmMain.addCommand(cmExit);
fmMain.addCommand(cmFind);
// Append textfield and stringItem to form
fmMain.append(tfFind);
...

  事件处理

  一旦 StringSearch MIDlet 处于活动状态,所有事件都将在 commandAction() 方法中处理。请求 cmFind 命令时,程序将会调用 searchRecordStore() 开始搜索处理。这个过程包括指派一个 SearchFilter() 类的实例,并把这个实例关联到记录枚举对象。指派了枚举对象后,它将会调用搜索函数来搜索记录存储。所有与搜索字符串相匹配的记录都将成为枚举结果集的一部分。

  清单 20 展示了处理事件以及搜索与用户输入文本字符串相匹配的记录的代码。请注意创建搜索过滤器时对 tfFind.getString() 的引用,该调用从文本字段中获取用户输入的搜索字符串。然后,字符串被保存在 SearchFilter 类的变量 searchText 中。当枚举器调用方法 matches() 时――对记录存储中的每条记录调用一次――它将在当前的活动记录中搜索匹配 searchText 的字符串。

  清单 20. 处理用户事件

public void commandAction(Command c, Displayable s)
{
   if (c == cmFind)
   {
    searchRecordStore();
   }
   else if (c == cmExit)
   {
    destroyApp(false);
    notifyDestroyed();
   }
}
...
//********************************************************
// Search the record store
//********************************************************
private void searchRecordStore()
{
   try
   {
    // Record store is not empty
    if (rs.getNumRecords() > 0)
    {
     // Setup the search filter with the user requested text
     SearchFilter search = new SearchFilter(tfFind.getString());
     RecordEnumeration re = rs.enumerateRecords(search, null, false);
    // Remove any previous record entries displayed on the form
     clearForm();
     // A match was found using the filter
     if (re.numRecords() > 0)
     {
      // Append all records found onto the form
      while (re.hasNextElement())
       fmMain.append(new String(re.nextRecord()));
     }
     re.destroy();  // Release enumerator
    }
   }
   catch (Exception e)
   {
    db(e.toString());
   }
}
...
//********************************************************
// Called for each record when creating the enumerator.
// Checks to see if the record contains text that
// matches the text string entered by the user.
//********************************************************
class SearchFilter implements RecordFilter
{
   private String searchText = null;
   public SearchFilter(String searchText)
   {
    // Text to find
    this.searchText = searchText.toLowerCase();
   }
   public boolean matches(byte[] candidate)
   {
    String str = new String(candidate).toLowerCase();
    // Look for text
    if (searchText != null && str.indexOf(searchText) != -1)
     return true;
    else
     return false;
   }
}

  RecordListener API

  RecordListener 接口是我们讨论的最后一个 API,但并不表明它是最不重要的。在代码中实现 RecordListener 可以保证当记录存储修改、添加或删除的时候您可以得到通知。

  以下是使用 RecordListener 的基本步骤:

  打开(创建)一个记录存储。

  创建一个新的监听器。

  实现 RecordListener 接口中的所有方法。

  RecordListener API 中的所有方法的传入参数都相同:一个指向发生修改的记录存储的引用和受到影响的记录 ID。清单 21 显示了 RecordListener API 的方法。

  清单 21. RecordListener API

void recordAdded(RecordStore recordStore, int recordId)
void recordChanged(RecordStore recordStore, int recordId)
void recordDeleted(RecordStore recordStore, int recordId)

  清单 22 中的一小段代码展示了如何在 RMS 的记录发生添加、删除或更改的时候把消息显示在控制台上。

  清单 22. 创建一个记录监听器

// Open record store
rs = RecordStore.openRecordStore(REC_STORE, true);
...
// Using handle to open record store, create a listener
rs.addRecordListener(new DemoRecordListener());
...
//********************************************************
// Listener to process updates to the record store
//********************************************************
class DemoRecordListener implements RecordListener
{
   public void recordAdded(RecordStore recordStore, int recordId)
   {
    System.out.println("Record added");
   }
   public void recordDeleted(RecordStore recordStore, int recordId)
   {
        System.out.println("Record deleted");
   }
   public void recordChanged(RecordStore recordStore, int recordId)
   {
        System.out.println("Record changed");
   }

  结束语

  在 J2ME 101 系列的这第三篇文章中,您了解了如何在自己的 MIDP 应用程序中创建和管理数据记录。文章开头部分介绍的便利方法使您可以在记录存储中写入和读取记录。 RecordEnumeration 类使您可以在 RMS 的所有记录之间移动。结合 RecordComparator 时,它可以返回排序的记录,结合 RecordEnumeration 类时它可以搜索指定的记录。如果将这三者 ―― 枚举器、比较器和过滤器 ―― 结合在一起,您将可以查找特定的记录,并按顺序返回结果。最后讨论的、但并非最不重要的 API: RecordListener 可以用于为应用程序设置事件通知。

  几周之后,我们将以对 MIDP 中网络支持的全面介绍来结束这个系列,请密切关注。

(责任编辑:admin)

  • 上一篇资讯: 确保无线 J2ME 的安全
  • 网学推荐

    免费论文

    原创论文

    浏览:
    设为首页 | 加入收藏 | 论文首页 | 论文专题 | 设计下载 | 网学软件 | 论文模板 | 论文资源 | 程序设计 | 关于网学 | 站内搜索 | 网学留言 | 友情链接 | 资料中心
    版权所有 QQ:3710167 邮箱:3710167@qq.com 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
    Copyright 2008-2015 myeducs.Cn www.myeducs.Cn All Rights Reserved
    湘ICP备09003080号