你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 网络与通信
4.9 J2ME手机日记本的设计原理与关键技术
 

一、RMS

随着J2MEjava2 Platform Micro Edition)技术在手机领域的快速发展,在Java手机上运行的软件的功能也越来越丰富。移动信息设备描述(MIDP)通过记录管理系统 (Record Management SystemRMS) 提供数据的持久存储。下面将以开发手机日记本为例,详细分析了RMS的存储原理,并给出开发手机日记本的设计原理与关键技术。

1.记录的定义

MIDP 对持久存储的数据局限于简单的字节数组 (byte array),且记录是按整条读写的,而不是按字段读写。

RMS 是用来管理记录的系统,一条记录是一个单一的数据项。RMS 没有对放入记录的内容加以限制:记录可以是数字、字符串、数组以及图像等任何一段连续字节可以描述的事物。如果将数据编码成字节数组,并且具备相应的解码手段,就能将其存入一条记录中,当然要受系统分配的容量大小的限制。

RMS中,记录的长度是可变的,这样,解释记录内容的任务就完全依靠应用程序来完成。RMS只提供存储和惟一标识符。虽然这样分工导致应用程序趋于复杂化,但是它使得 RMS 小巧灵活,这是作为 MIDP 子系统的一项重要属性。所有的RMS类和接口在 javax.microedition.rms 包中定义。

2.记录存储

记录存储是记录的有序集合。记录不是独立的实体,每一条记录必须从属于一个记录存储,而且所有的存取都通过记录存储来实现。在创建一条记录时,记录存储为其分配一个惟一的标识符。该标识符是被称作记录 ID 的整数。加入记录存储的第一条记录的ID1,第二条的记录ID2,依此类推。记录ID不是索引,记录删除后不会对现存的记录进行重新编号,也不会影响后面记录的ID 值。

二、管理记录存储

API级别中,用javax.microedition.rms.RecordStore类的实例表示记录存储,它提供了几个方法来管理记录,包括插入、更新、删除和列举。

每一个MIDlet Suite都会有属于自己的一个用于RMS的私有空间。可以通过jad描述文件事先规定Midlet Suite运行所必需的RMS空间大小,在手机内部存储空间中预存的一个空间,供由jad指定的jar包文件使用。在MIDP 2.0 以后,只要MIDlet开放了属于自己RMS空间的相应RecordStore的使用权限,那么这个RecordStore可以被Suite外部的其他MIDlet访问。   

所有与RMS相关的API都集中在javax.microedition.rms包下,包括了一个主类、四个接口,以及五个可能的被抛出异常。

1.打开和关闭记录存储

方法openRecordStore(String recordStoreName,boolean createIfNecessary)用来打开一个记录存储,也可创建一个记录存储。如:

rs=RecordStore.openRecordStore(rs_name,true);

该方法返回一个RecordStore对象的实例,第二个参数表示若该记录存储不存在时是否创建。完成对记录存储的操作之后,调用closeRecordStore()将其关闭。当不再用一个打开的RecordStore时,要关闭它以节约资源。

2.添加和更新记录

使用方法addRecord() 添加新的记录到打开的记录存储。

int addRecord(byte[] data,int offset, int numBytes)

data中指定希望保存的字节数组,在offset中指定数据显示排列中的数据开始位置,在numBytes中指定保存数据的字节数。返回值是新增加记录的id

可以用 RecordStore.setRecord() 更新记录:

void setRecord(int recordId, byte[] newData, int offSet, int numBytes)

更改recordId中指定的记录,在newData中是新的数据字节。

    3.读取记录

可以利用 RecordStore.getRecord() 的两种形式之一读取记录。第一种形式分配合适大小的字节数组并将记录数据复制到里面:

byte[] data = rs.getRecord( recordID );

第二种形式是从指定的偏移量开始,将数据复制到预分配的数组中并返回所复制的字节数量:

int numCopied = rs.getRecord( recordID, data, offset );

    4.删除记录,删除记录存储

RecordStore.deleteRecord() 删除记录:

rs.deleteRecord( recordID );

RecordStore.deleteRecordStore()删除记录存储:

    RecordStore.deleteRecordStore(rs_name );

记录存储只有当其处于未打开状态时才能被删除。一个MIDlet套件只能够删除它自己的记录存储。在删除之前,需要确保当前的存储是处于关闭状态,如果改存储仍旧处于开启状态,那么删除记录将导致RecordStoreException异常抛出。如果该删除的存储记录本身不存在,那么这将会引起RecordStoreNotFoundException异常抛出。

5.列举记录

使用RecordEnumeration enumerateRecords(RecordFilter filter, RecordComparator comparator, boolean keepUpdated) 对记录进行列举操作,本文正是利用了该方法的rs.enumerateRecords(null,null,true)列举所有记录。代码如下:

RecordStore rs=null;

RecordEnumeration re=null;

     rs=RecordStore.openRecordStore("test",true);

     re=rs.enumerateRecords(null,null,true);//列举所有记录

     byte[] data;

     while(re.hasNextElement()){//是否有下一条记录

       data = re.nextRecord();//取得下一条记录

       System.out.println("record =" + data);

     }

 

三、手机日记本的设计原理

    1.工作流程及运行画面

手机日记本的工作流程如图1所示。日记列表画面按创建日期显示日期列表,可进行日记的添加和显示内容。日记内容画面显示日记内容,可进行日记的编辑和删除。两个画面如图2所示。


 

1 手机日记本的工作流程

 


2 日记列表画面和日记内容画面

根据工作流程,要在各个画面中分别设定如表1所示的命令。

 

 

 

 

1 画面中设定的命令

日记列表画面

添加

创建日记

显示

显示内容

日记内容画面

保存

保存日记内容

删除

删除日记

 

2.文件组成及实现功能

1Memo.java

表示日记的Memo类,关于日记的属性和方法都在里面。属性包括记录ID、创建日期和日记内容。实例方法有把日记内容变换成字节的toByes(),还有设置和获得日记的日期及内容等方法。

2MobileMemo.java

MIDlet主类,日记列表画面和显示日记内容画面都是这个类实现的。其主要方法有:

reloadFromRSM()从记录存储读取所有记录到memos中。

changeMemoToRMS():访问记录存储,完成用户操作菜单的命令,包括:删除、添加和更新记录。

commandAction:事件处理程序,在列表画面中实现创建日记,显示日记内容。在显示日记内容画面中实现保存和删除日记。

四、日记的Memo

1.属性

Memo类的属性有记录ID、日记的创建日期和日记内容。

private int recId;

private Date date;

private String content="";

2.实例方法toByes()

把日记的日期和内容变换成字节数组,是Memo类的重要方法,也是任何一个管理记录存储的程序必须要定义的方法。只有将日记的日期和内容转换成字节数组,才能将其存入一条记录中,利用ByteArrayOutputStream类和DataOutputStream类实现。

     public byte[] toBytes(){

        byte[] data = null;

        try{

            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            DataOutputStream out = new DataOutputStream(baos);

            //把创建日记和日记内容发送给输出流

            out.writeLong(date.getTime());

            out.writeUTF(content);

            data = baos.toByteArray();

            baos.close();

            out.close();

            }catch(Exception e)

{

        }

        return data;//返回转换结果

     }

五、reloadFromRSM():读取所有记录到memos

利用RecordEnumeration取得记录存储中的全部记录,通过Memo对象,保存在Vector型的实例变量memos中。而且从记录存储中取得全部记录后,可随时更新日记列表的画面。Vector中加入的对象是有序的,即按加入的顺序排列,并且能够根据索引访问,可以看成是可变大小的数组。

    public void reloadFromRSM()

 {

        memos.removeAllElements();

        Record Store  rs = null;

        RecordEnumeration re = null;

        try

{

            rs = Record Store .open Record  Store (RS_NAME, true);

            //列举所有记录

            re = rs.enumerateRecords(null, null, true);

            //取得记录

            while (re.hasNextElement())

{

                int id = re.nextRecordId();//取得Record Id

                byte[] data = rs.getRecord(id);// 取得Record

                Memo memo = new Memo(data);

                memo.setRecId(id);//设定记录的Id

                memos.addElement(memo);

            }

        //利用momes更新日记列表

        initilizeList();

        for (int i = 0; i < memos.size(); i++) {

          Memo memo = (Memo) memos.elementAt(i);

//取出日记的日期date,利用Calendar转换成年月日表示,并添加到list中。

          Calendar Now = Calendar.getInstance();

          Now.setTime(memo.getDate());

          String year=String.valueOf(Now.get(java.util.Calendar.YEAR));

          String month=String.valueOf(Now.get(java.util.Calendar.MONTH)+1);

          String day=String.valueOf(Now.get(java.util.Calendar.DATE));

list.append(year+""+month+""+day+"",null);

        }

六、changeMemoToRMS():更新记录存储

    属私有方法,供事件处理程序调用处理用户菜单命令时,通过不同参数,对记录存储进行保存、删除和添加记录操作。

    private Memo changeMemoToRMS(Memo memo, Command c)

{

        RecordStore rs = null;

        try

{

            rs = RecordStore.openRecordStore(RS_NAME, true);

            if (c == ok) {

//保存日记内容

                int id = memo.getRecId();

                rs.setRecord(id, memo.toBytes(), 0, memo.toBytes().length);

            } else if (c == delete) {

//删除日记

                int id = memo.getRecId();

                rs.deleteRecord(id);

            } else if (c == add) {

//创建新日记

                int id = rs.addRecord(memo.toBytes(), 0, memo.toBytes().length);

                memo.setRecId(id);

            }

七、commandAction:事件处理程序

    如果当前是列表画面,可以添加新日记,可以取得选中的日记内容准备显示。如果当前是日记内容画面,可以保存日记,也可以删除日记。事件处理程序中创建新日记的createNewMemo()方法,保存日记内容的writeMemo()方法和清除日记内容deleteMemo()方法,都调用了前面的changeMemoToRMS()方法,通过不同参数执行相应的功能。

    public void commandAction(Command c, Displayable d)

{

//如果当前画面是列表

if (d == list)

 {

            if (c == add) {

//add命令则创建新的日记

                currentMemo = createNewMemo();

            } else if (c == show)

{//show命令则取得日记内容准备显示

                int index = list.getSelectedIndex();

                if(index == -1)return;

                currentMemo = (Memo) memos.elementAt(index);

            }

            //转到显示日记内容的画面

            memoText.setString(currentMemo.getContent());

            display.setCurrent(memoText);

//如果当前画面是日记内容

        } else if (d == memoText)

{

            if (c == ok)

{

                //ok命令保存日记

                currentMemo.setContent(memoText.getString());

                writeMemo(currentMemo);

            } else if (c == delete)

{

                //delete命令删除日记

                deleteMemo(currentMemo);

            }

            //转到日记列表画面

            reloadFromRSM();

            display.setCurrent(list);

        }

    }

八、结语

RMSMIDP中一个非常重要的子系统,它是J2ME应用程序进行持久性存储的唯一途径。持久性存储在编写应用程序的时候经常要用到,如记录游戏排行榜、记录用户名和密码等。本文通过手机日记本介绍了RMS的基础知识以及如何管理记录存储,在分析手机日记本工作流程的基础上,给出了实现的关键代码。工程在jdk1.5j2me wireless toolkit 2.2下调试和模拟运行通过。

 

  推荐精品文章

·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 
·2023年7月目录
·2023年6月目录 
·2023年5月目录
·2023年4月目录 
·2023年3月目录 
·2023年2月目录 
·2023年1月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089