JAVAME的RMS通用持久化框架

在写JAVAME程序的时候,我们经常需要保存一些数据到手机里面,也经常希 望能把对象也保存到手机里面,但是JAVAME里面没有反射机制,也没有 java.io.Serializable接口,所以没有序列化的机制,要保存对象的话,就得自 己动手了。

在JAVAME中,程序的数据保存的地方,无外乎两种,一种是把数据保存在RMS 里面,这是所有的JAVAME的手机都支持的,还有一种就是把数据保存在手机的文 件系统里面,这个不是所有手机都能支持的,只有支持JSR075的手机,才支持把 数据保存在文件系统里面,并且如果你的程序没有经过签名的话,你每次保存或 者读取,手机都会弹出恼人的提示,是否允许程序访问文件系统。所在我一般都 是把数据存在RMS里面,因为读写RMS是安全的,并且也是不需要手机提示的。因 为我们的RMS数据是存在一个特殊的地方。但是JAVAME的RMS功能非常底层,为了 保存一些数据,我们必须和byte[]打交道,所以我就产生了,在此之前封装一层 自己的程序的想法,这样封装好以后,使用起来就非常方便了。只要实现了相关 接口,就可以享受到比较易用的方法了。

此框架总共包括了四个类,分别如下:

Serializable类,它是一个接口,类似于JAVASE里面的Serializable接口, 唯一不同的就是,JAVASE里面的接口是一个空接口,只做标记用的,而这里的这 个接口是有方法需要实现的。

Lazy类,它也是一个接口,它定义了一些方法,如果你的对象比较大,需要 惰性加载的时候,可以实现此接口,并且此接口是Serializable接口的子类,也 就是说实现了Lazy接口,你就相当于实现了Serializable接口。

RMSUtil类,此类是一个工具类,用于统一进行RMS的相关操作,也是此框架 的核心类。

RecordFetcher类,也是一个接口,它继承了RecordComparaTor, RecordFilter接口,在取数据的时候,需要用到它。

好了,下面我们就开始看代码吧。

 1 /*  2  * To change this template, choose Tools | Templates  3  * and open the template in the ediTor.  4  */  5 package com.hadeslee.mobile.rms;  6  7 import java.io.IOException;  8  9 /**10  * 一个可自己串行化的类所要实现的接口11  * @author hadeslee12  */13 public interface Serializable {1415     /**16      * 把自己编码成字节数组的格式17      * @return 字节数组18      */19     public byte[] serialize() throws IOException;2021     /**22      * 把一个对象用此字节数组进行重装23      * @param data 字节数组24      */25     public void unSerialize(byte[] data) throws IOException;2627     /**28      * 设置此对象序列化后对应的存储对象的ID29      * @param id ID30      */31     public void setId(int id);3233     /**34      * 得到此对象序列化后的ID35      * 此方法唯有在反序列化后的对象上调用才有效36      * 如果一个对象是没有序列化的,那么它的ID是-1;37      * @return ID38      */39     public int getId();40 }41  1 /*  2  * To change this template, choose Tools | Templates  3  * and open the template in the ediTor.  4  */  5 package com.hadeslee.mobile.rms;  6  7 import java.io.IOException;  8  9 /**10  * 可以延迟加载的对象必须要实现的接口11  * @author binfeng.li12  */13 public interface Lazy extends Serializable {1415     /**16      * 实现此接口的类要实现的方法17      * 可以用于延迟加载某些属性。比如18      * get("ImgData"),get("fullImage")..等等19      * 由于J2ME不支持注释也不支持反射,所以只能以20      * 此种方法来进行模拟了21      * 此方法是RMSUtil要存对象的时候调用的,这样就可以把22      * 一个对象的不同部份存到不同的RMS里面去了23      * @param key 要得到的某性的键24      * @return 其对应的值25      * @throws IOException26      */27     public byte[] getAttach(Object key)throws IOException;2829     /**30      * 当把某个附属的对象保存进去以后,所要调用的31      * 方法,此方法告诉主体,它的那个附件被保存后32      * 在RMS里面对应的ID是多少33      * @param key34      * @param id35      */36     public void savedAttach(Object key, int id);3738     /**39      * 得到此对象所支持的所有的key的数组40      * @return KEY的数组,不能为NULL41      */42     public Object[] getAttachKeys();4344     /**45      * 此对象的附属对象所存的RMS的名字46      * @return RMS的名字47      */48     public String getNameOfAttachRMS();49 }50

  1 /*  2  * To change this template, choose Tools | Templates  3  * and open the template in the ediTor.  4  */  5 package com.hadeslee.mobile.rms;  6  7 import javax.microedition.rms.RecordComparaTor;  8 import javax.microedition.rms.RecordFilter;  910 /**11  * 此类是一个继承了两个接口的接口,并且添加了自己12  * 的方法,自己的方法是用于通知数量以及开始取的位置13  * 只是为了方便于传递参数以及以后扩展14  * @author binfeng.li15  */16 public interface RecordFetcher extends RecordComparaTor, RecordFilter {1718     /**19      * 从哪个下标开始取20      * @return 下标21      */22     public int getFromIndex();2324     /**25      * 最多取多少条记录26      * @return 记录27      */28     public int getMaxRecordSize();29 }30  1 /*  2  * To change this template, choose Tools | Templates  3  * and open the template in the ediTor.  4  */  5 package com.hadeslee.mobile.rms;  6  7 import com.hadeslee.mobile.log.LogManager;  8 import java.util.Enumeration;  9 import java.util.Hashtable;  10 import java.util.VecTor;  11 import javax.microedition.rms.RecordEnumeration;  12 import javax.microedition.rms.RecordSTore;  13 import javax.microedition.rms.RecordSToreException;  14  15 /**  16  * 一个专门用来操作RMS的工具类,通过这个类  17  * 可以把RMS封装起来,上层调用就更方便了  18  * @author binfeng.li  19  */  20 public class RMSUtil {  21  22     /**  23      * 用于缓存生命周期之内的所有的RecordSTore的表,当 MIDlet要退出的  24      * 时候,调用此类的关闭方法,使RMS正确地被关闭  25      */  26     private static Hashtable rmsCache = new Hashtable ();  27  28     private RMSUtil() {  29     }  30  31     /**  32      * 插入一个对象到一个RMS的数据库里面,如果此数据库不 存在  33      * 则自动创建一个对于MIDlet私有的数据库。如果存在,则 直接  34      * 插在此数据库的最后面  35      * @param ser 要插入的数据,必须是实现了Serializable接 口的类  36      * @return 是否插入成功  37      */  38     public static boolean insertObject(Serializable ser) {  39         RecordSTore rs = null;  40         try {  41             rs = getRecordSTore(ser.getClass ().getName());  42             if (ser instanceof Lazy) {  43                 Lazy lazy = (Lazy) ser;  44                 insertAttachDatas(lazy);  45             }  46             byte[] data = ser.serialize();  47             int id = rs.addRecord(data, 0, data.length);  48             ser.setId(id);  49             return true;  50         } catch (Exception exe) {  51             exe.printStackTrace();  52             LogManager.error ("RMSUtil.insertObject(),ser = " + ser + ",exe = " + exe);  53             return false;  54         }  55     }  56  57     /**  58      * 更新某个对象到RMS里面去,  59      * @param ser 要更新的对象  60      * @return 是否成功  61      */  62     public static boolean updateObject(Serializable ser) {  63         RecordSTore rs = null;  64         try {  65             rs = getRecordSTore(ser.getClass ().getName());  66             byte[] data = ser.serialize();  67             rs.setRecord(ser.getId(), data, 0, data.length);  68             return true;  69         } catch (Exception exe) {  70             exe.printStackTrace();  71             LogManager.error ("RMSUtil.updateObject(),ser = " + ser + ",exe = " + exe);  72             return false;  73         }  74     }  75  76     /**  77      * 从RMS里面删除某个对象  78      * @param ser 要删除的对象  79      * @return 是否成功  80      */  81     public static boolean deleteObject(Serializable ser) {  82         if (ser.getId() == -1) {  83             return false;  84         }  85         RecordSTore rs = null;  86         try {  87             rs = getRecordSTore(ser.getClass ().getName());  88             int id = ser.getId();  89             rs.deleteRecord(id);  90             ser.setId(-1);  91             return true;  92         } catch (Exception exe) {  93             exe.printStackTrace();  94             LogManager.error ("RMSUtil.deleteObject(),ser = " + ser + ",exe = " + exe);  95             return false;  96         }  97     }  98  99     /**100      * 从某个数据库里面读取某个对象101      * @param id 此对象的ID102      * @param clz 对应的类103      * @return 此对象,如果发生任何异常,则返回null104      */105     public static Serializable readObject(int id, Class clz) {106         RecordSTore rs = null;107         try {108             rs = getRecordSTore(clz.getName());109             byte[] data = rs.getRecord(id);110             Serializable ser = (Serializable) clz.newInstance();111             ser.unSerialize(data);112             ser.setId(id);113             return ser;114         } catch (Exception exe) {115             //如果读取对象失败,则可能是有东西被删了 或者版本不一样,此时就应该删掉116             exe.printStackTrace();117             LogManager.error("RMSUtil.readObject (),id = " + id + ",Class = " + clz + ",exe= " + exe);118             if (rs != null) {119                 try {120                     rs.deleteRecord(id);121                 } catch (Exception ex) {122                     ex.printStackTrace ();123                     LogManager.error ("RMSUtil.readObject$rs.deleteRecord(id),id = " + id + ",exe = " + ex);124                 }125             }126             return null;127         }128     }129130     /**131      * 得到某个类存在RMS里面的总数,这样便于分段取132      * @param cls 类名133      * @return 有效记录总数134      */135     public static int getSToreSize(Class cls) {136         try {137             RecordSTore rs = getRecordSTore (cls.getName());138             return rs.getNumRecords();139         } catch (Exception exe) {140             exe.printStackTrace();141             LogManager.error("RMSUtil.getSToreSize (),Class = " + cls + ",exe = " + exe);142             return -1;143         }144     }145146     /**147      * 列出某个类的对象的集合,最多取多少个对象148      * @param cls 类名149      * @param from 从第几个开始取150      * @param maxSize 最多取多少个对象151      * @return 取到的列表152      */153     public static VecTor listObjects(Class cls, int from, int maxSize) {154         System.out.println("class="+cls);155         if (from < 0 || maxSize = from) {190                 if (size < maxSize) {191                     Serializable ser = readObject(id, cls);192                     if (ser != null) {193                         v.addElement (ser);194                         size++;195                     }196                 } else {197                     break;198                 }199             }200             index++;201         }202     }203204     /**205      * 列出某个类的对象,并用一种过滤以及排序的方法来进行过 滤或者排序206      * @param cls 类名207      * @param fetcher 取记录的方法208      * @return 记录列表209      */210     public static VecTor listObjects(Class cls, RecordFetcher fetcher) {211         System.out.println("fetcher class="+cls);212         int from = fetcher.getFromIndex();213         int maxSize = fetcher.getMaxRecordSize();214         if (from < 0 || maxSize < 1) {215             throw new IllegalArgumentException("from can not less than 0 and maxSize must greater than 0");216         }217         VecTor v = new VecTor();218         RecordEnumeration ren = null;219         try {220             RecordSTore rs = getRecordSTore (cls.getName());221             ren = rs.enumerateRecords(fetcher, fetcher, false);222             fetchRecord(v, cls, ren, from, maxSize);223         } catch (Exception exe) {224             LogManager.error("RMSUtil.listObjects (),Class = " + cls + ",exe = " + exe);225             exe.printStackTrace();226         } finally {227             ren.destroy();228         }229         return v;230     }231232     /**233      * 插入某个可延迟加载的对象的所有附件到数据库里面去234      * 插入完成后,此lazy对象将变得很完整,因为此时它的235      * 附件对象的ID都已经设置好了236      * @param lazy 要插入附件的主对象237      * @return 是否插入成功238      */239     private static boolean insertAttachDatas(Lazy lazy) {240         try {241             Object[] attachKeys = lazy.getAttachKeys();242             RecordSTore rs = getRecordSTore (lazy.getNameOfAttachRMS());243             for (int i = 0; i 32) {367             name = name.substring(name.length()-32, name.length());368         }369         if (rmsCache.containsKey(name)) {370             return (RecordSTore) rmsCache.get (name);371         } else {372             RecordSTore rs = RecordSTore.openRecordSTore(name, true);373             rmsCache.put(name, rs);374             return rs;375         }376     }377 }378

相信看完代码以后,大家应该知道如何使用它吧。如果有需要持久化的类, 那么就需要实现Serializable接口,然后只要调用RMSUtil.insertObject()就可 以了,同理,查找也是一样的,你可以查找同一个类的一系列对象,也可以自己 定义记录查询器,在里面设置查询条件。

目前JAVAME的持久化框架,也有用其它的方法实现的,比如动态插入代码的 方法,也就是你在写好了JAVAME的代码以后,在编译的过程中,它自动帮你加上 相应的方法,我看了一个他们的源码,其实也就是它们自己帮你实现了一个相当 于Serializable接口,我觉得这样不好的地方在于,它会为你的类添加方法,万 一你的类里面原来就有那个方法的时候,那就会出现不可意料的情况了,还有, 我觉得自己的数据还是自己一个一个把它写出来,这样心里更踏实一些。我一直 都认为,封装得有一个度,不能过度的封装,过度封装表面上看是编码更方便了 ,但是写的时候,自己心里也更没底了,因为你不知道别人的代码都做了一些什 么。因为别人的代码做的事情太多了。呵呵,纯属个人意见。

大家如果有什么自己的看法,欢迎留言。

还有,此代码用到了我的另外一个通用框架,那就是LOG框架,所以如果直接 下载的话,可能会编译不过了,只要注释掉LogManager的调用就可以了。LOG框 架的说明点击这里,这个LOG框架现在正在改动中,以使它更好用,更没有侵入 性。

本文配套源码

快乐不是因为拥有的多而是计较的少

JAVAME的RMS通用持久化框架

相关文章:

你感兴趣的文章:

标签云: