<acronym id="cr5pu"></acronym>
  • <kbd id="cr5pu"><font id="cr5pu"></font></kbd>
  • <li id="cr5pu"><output id="cr5pu"></output></li>
    <del id="cr5pu"><li id="cr5pu"></li></del><center id="cr5pu"></center>
    <output id="cr5pu"><kbd id="cr5pu"></kbd></output>
  • <rp id="cr5pu"></rp>
    <var id="cr5pu"></var>
  • <nav id="cr5pu"></nav>
  • 千里冰封
    JAVA 濃香四溢
    posts - 151,comments - 2801,trackbacks - 0
    在寫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 hadeslee
    12  */
    13 public interface Serializable {
    14 
    15     /**
    16      * 把自己編碼成字節數組的格式
    17      * @return 字節數組
    18      */
    19     public byte[] serialize() throws IOException;
    20 
    21     /**
    22      * 把一個對象用此字節數組進行重裝
    23      * @param data 字節數組
    24      */
    25     public void unSerialize(byte[] data) throws IOException;
    26 
    27     /**
    28      * 設置此對象序列化后對應的存儲對象的ID
    29      * @param id ID
    30      */
    31     public void setId(int id);
    32 
    33     /**
    34      * 得到此對象序列化后的ID
    35      * 此方法唯有在反序列化后的對象上調用才有效
    36      * 如果一個對象是沒有序列化的,那么它的ID是-1;
    37      * @return ID
    38      */
    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.li
    12  */
    13 public interface Lazy extends Serializable {
    14 
    15     /**
    16      * 實現此接口的類要實現的方法
    17      * 可以用于延遲加載某些屬性。比如
    18      * get("ImgData"),get("fullImage")..等等
    19      * 由于J2ME不支持注釋也不支持反射,所以只能以
    20      * 此種方法來進行模擬了
    21      * 此方法是RMSUtil要存對象的時候調用的,這樣就可以把
    22      * 一個對象的不同部份存到不同的RMS里面去了
    23      * @param key 要得到的某性的鍵
    24      * @return 其對應的值
    25      * @throws IOException 
    26      */
    27     public byte[] getAttach(Object key)throws IOException;
    28 
    29     /**
    30      * 當把某個附屬的對象保存進去以后,所要調用的
    31      * 方法,此方法告訴主體,它的那個附件被保存后
    32      * 在RMS里面對應的ID是多少
    33      * @param key
    34      * @param id
    35      */
    36     public void savedAttach(Object key, int id);
    37 
    38     /**
    39      * 得到此對象所支持的所有的key的數組
    40      * @return KEY的數組,不能為NULL
    41      */
    42     public Object[] getAttachKeys();
    43 
    44     /**
    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;
     9 
    10 /**
    11  * 此類是一個繼承了兩個接口的接口,并且添加了自己
    12  * 的方法,自己的方法是用于通知數量以及開始取的位置
    13  * 只是為了方便于傳遞參數以及以后擴展
    14  * @author binfeng.li
    15  */
    16 public interface RecordFetcher extends RecordComparator, RecordFilter {
    17 
    18     /**
    19      * 從哪個下標開始取
    20      * @return 下標
    21      */
    22     public int getFromIndex();
    23 
    24     /**
    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 此對象的ID
    102      * @param clz 對應的類
    103      * @return 此對象,如果發生任何異常,則返回null
    104      */
    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     }
    129 
    130     /**
    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     }
    145 
    146     /**
    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 < 1) {
    156             throw new IllegalArgumentException("from can not less than 0 and maxSize must greater than 0");
    157         }
    158         Vector v = new Vector();
    159         RecordEnumeration ren = null;
    160         try {
    161             RecordStore rs = getRecordStore(cls.getName());
    162             ren = rs.enumerateRecords(nullnullfalse);
    163             fetchRecord(v, cls, ren, from, maxSize);
    164         } catch (Exception exe) {
    165             LogManager.error("RMSUtil.listObjects(),Class = " + cls + ",from = " + from + ",maxSize = " + maxSize + ",exe = " + exe);
    166             exe.printStackTrace();
    167         } finally {
    168             ren.destroy();
    169         }
    170         return v;
    171     }
    172 
    173     /**
    174      * 用于前面一個方法和后面一個方法的共用方法,
    175      * 它用來從特定的記錄枚舉里面去取特定的記錄,
    176      * 并放到特定的地方
    177      * @param v 要保存的地方
    178      * @param cls 要實例化的類
    179      * @param ren 記錄的枚舉
    180      * @param from 從哪里開始取
    181      * @param maxSize 要取多少條記錄
    182      * @throws java.lang.Exception 可能會拋出的異常
    183      */
    184     private static void fetchRecord(Vector v, Class cls, RecordEnumeration ren, int from, int maxSize) throws Exception {
    185         int index = 0;
    186         int size = 0;
    187         while (ren.hasNextElement()) {
    188             int id = ren.nextRecordId();
    189             if (index >= 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     }
    203 
    204     /**
    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     }
    231 
    232     /**
    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 < attachKeys.length; i++) {
    244                 Object key = attachKeys[i];
    245                 byte[] data = lazy.getAttach(key);
    246                 int id = rs.addRecord(data, 0, data.length);
    247                 lazy.savedAttach(key, id);
    248             }
    249             return true;
    250         } catch (Exception exe) {
    251             exe.printStackTrace();
    252             LogManager.error("RMSUtil.insertAttachDatas(),Lazy = " + lazy + ",exe = " + exe);
    253             return false;
    254         }
    255     }
    256 
    257     /**
    258      * 得到某個可以延遲加載的對象的某個附件的字節數組內容
    259      * TODO 如果能把此方法變成私有,那就更好了
    260      * 此方法是專門供lazy對象調用的,這樣的話,實體類里面就出現了
    261      * 讀取數據的方法,但是由于J2ME不支持反射,只能這樣實現了
    262      * @param lazy 可以延遲加載的對象
    263      * @param id 附件的ID
    264      * @return 對應的數組
    265      */
    266     public static byte[] getAttachData(Lazy lazy, int id) {
    267         try {
    268             return getRecordStore(lazy.getNameOfAttachRMS()).getRecord(id);
    269         } catch (Exception exe) {
    270             exe.printStackTrace();
    271             LogManager.error("RMSUtil.getAttachData(),Lazy = " + lazy + ",id = " + id + ",exe = " + exe);
    272             return null;
    273         }
    274     }
    275 
    276     /**
    277      * 更新某個對象的附件
    278      * TODO 如果能把此方法變成私有就更好了
    279      * @param lazy 可延遲加載的對象
    280      * @param id 附件的ID
    281      * @param data 附件的內容
    282      * @return 是否成功
    283      */
    284     public static boolean updateAttachData(Lazy lazy, int id, byte[] data) {
    285         try {
    286             RecordStore rs = getRecordStore(lazy.getNameOfAttachRMS());
    287             rs.setRecord(id, data, 0, data.length);
    288             return true;
    289         } catch (Exception exe) {
    290             exe.printStackTrace();
    291             LogManager.error("RMSUtil.updateAttachData(),Lazy = " + lazy + ",exe = " + exe);
    292             return false;
    293         }
    294     }
    295 
    296     /**
    297      * 從附件數據庫中刪除某個附件
    298      * @param lazy 主對象
    299      * @param id 附件的ID
    300      * @return 是否刪除成功
    301      */
    302     public static boolean deleteAttachData(Lazy lazy, int id) {
    303         try {
    304             RecordStore rs = getRecordStore(lazy.getNameOfAttachRMS());
    305             rs.deleteRecord(id);
    306             return true;
    307         } catch (Exception exe) {
    308             exe.printStackTrace();
    309             LogManager.error("RMSUtil.deleteAttachData(),Lazy = " + lazy + ",id = " + id + ",exe = " + exe);
    310             return false;
    311         }
    312     }
    313 
    314     /**
    315      * 關閉所有的RMS
    316      */
    317     public static void closeAllRMS() {
    318         Enumeration en = rmsCache.elements();
    319         while (en.hasMoreElements()) {
    320             RecordStore rs = (RecordStore) en.nextElement();
    321             closeRecordStore(rs);
    322         }
    323         rmsCache.clear();
    324     }
    325 
    326     public static void deleteRecord(Class cls, int id) {
    327         deleteRecord(cls.getName(), id);
    328     }
    329 
    330     /**
    331      * 刪除某個倉庫里面的某條記錄
    332      * @param rsName 倉庫的名字
    333      * @param id 記錄的ID
    334      */
    335     public static void deleteRecord(String rsName, int id) {
    336         try {
    337             RecordStore rs = RecordStore.openRecordStore(rsName, false);
    338             if (rs != null) {
    339                 rs.deleteRecord(id);
    340             }
    341             rs.closeRecordStore();
    342         } catch (Exception exe) {
    343         }
    344     }
    345 
    346     /**
    347      * 一個簡單的方法用于關閉RecordStore
    348      * @param rs 要關閉的RecordStore
    349      */
    350     private static void closeRecordStore(RecordStore rs) {
    351         try {
    352             rs.closeRecordStore();
    353         } catch (Exception exe) {
    354             LogManager.error("RMSUtil.closeRecordStore(),rs = " + rs + ",exe = " + exe);
    355             exe.printStackTrace();
    356         }
    357     }
    358 
    359     /**
    360      * 得到某個RMS的存儲數據庫,先從緩存里面去找,如果沒有找到則生成
    361      * 一個并把它放到緩存里面,還有,因為RMS的名字,最長只支持32位
    362      * @param name 數據庫的名字
    363      * @return 找到的RMS數據庫
    364      */
    365     private synchronized static RecordStore getRecordStore(String name) throws RecordStoreException {
    366         if (name.length() > 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框架現在正在改動中,以使它更好用,更沒有侵入性。

    Netbeans項目工程打包下載,請點擊這里。此工程中還有LOG框架在里面。




    盡管千里冰封
    依然擁有晴空

    你我共同品味JAVA的濃香.
    posted on 2009-03-01 10:13 千里冰封 閱讀(5020) 評論(3)  編輯  收藏 所屬分類: JAVAME

    FeedBack:
    # re: JAVAME的RMS通用持久化框架[未登錄]
    2009-03-01 08:38 | Aaron
    謝謝樓主的分享,非常好的文章  回復  更多評論
      
    # re: JAVAME的RMS通用持久化框架
    2009-03-01 09:58 | foot
    樓主學習的速度很快啊。  回復  更多評論
      
    # re: JAVAME的RMS通用持久化框架
    2009-05-20 15:57 | f
    javamE已死  回復  更多評論
      

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    久久一级片
    <acronym id="cr5pu"></acronym>
  • <kbd id="cr5pu"><font id="cr5pu"></font></kbd>
  • <li id="cr5pu"><output id="cr5pu"></output></li>
    <del id="cr5pu"><li id="cr5pu"></li></del><center id="cr5pu"></center>
    <output id="cr5pu"><kbd id="cr5pu"></kbd></output>
  • <rp id="cr5pu"></rp>
    <var id="cr5pu"></var>
  • <nav id="cr5pu"></nav>