Record Management System是J2ME的一個重要的子系統,目標是實現利用程序本地數據的持久性存儲。目前支撐文件系統的移動信息設備還有限,因此Record Management System是J2ME開發職員實現本地數據存儲的首選道路。本文的目標就是全面的先容Record Management System的知識。
顧名思義Record Management System是治理數據的系統,Record是系統中最重要的實體。在移動設備存儲空間存儲的並不是字段,而是字節數組。Mobile Infomation Device Profile(MIDP)規范中並沒有規定什麼樣的數據才干存儲為記錄,事實上記錄是任何可以被字節數組表現的數據,例如圖片、文本等。
Record Management System的職責是存儲和唯一標識記錄,而表現數據的任務是由利用程序來完成的,因此J2ME的開發職員往往要花費更多的精力來處理存儲空間中的數據。這樣做的目標是簡化MIDP的實現,使得J2ME的子系統盡量的小巧、機動。畢竟移動信息設備的存儲空間和處理器的才能都有限。
Record Store是一系列記錄的有序聚集,記錄是不能單獨存在的,必需屬於Record Store。Record Store保證記錄的讀寫把持都是原子的,數據不會被損壞。在API中Record Store是由Javax.microedition.rms.RecordStore實現的,關於RecordStore的具體把持在接下來的文章中會有具體的先容。
MIDP規范中闡明移動信息設備要供給至少8K的非易失性存儲空間給利用程序來實現數據的持久性存儲。但是不同的設備供給的空間並不雷同。假如MIDlet suite應用了Record Management System,那麼它必需在MANIFEST文件和JAD文件中通過設置MIDlet-Data-Size來闡明它所需要的最小的數據存儲空間,單位是字節,例如MIDlet-Data-Size:8192。
假如你的值超過了移動設備規定的最大值那麼你的利用程序將不能准確安裝。這個值並不是移動設備真正供給應利用程序的最大Record Management System的存儲空間,往往要大一些,因此開發職員應當避免把利用程序需要的最小存儲空間設置的過大,必要的時候應當參考相干設備的闡明手冊。在非易失性存儲空間內讀寫數據往往速度會比擬慢,因此針對頻繁拜訪的數據最好供給緩存的機制來供給性能。
Record Management System的讀寫把持是線程安全的,但是由於Record Store是被全部MIDlet suite共享的,所以假如不同MIDlet上運行的線程把持Record Store的時候,我們應當進行必要的線程同步,避免數據被損壞。
MIDP1.0和MIDP2.0中關於Record Management System的實現有些不同,在同一個MIDlet suite裡面的MIDlets可以相互拜訪彼此的Record Store。但是在MIDP1.0的實現中,並沒有供給在不同MIDlet suite之間共享Record Store的機制。
在MIDP2.0中供給的了新的API來解決不同MIDlet suite之間共享Record Store的標題,在創立Record Store的時候通過授權模式和讀寫把持參數來進行共享機制的治理,將在下面的連載文章中進行具體的先容。
加強對Record Management System的懂得的最好的措施就是進行實際的開發,在進行開發中我發明並不是所有移動設備的MIDP實現都准確無誤。當我用getSizeAvaliable()方法查詢諾基亞6108的可用Record Store空間的時候得到的數值是超過1M字節,但是當我寫進40K的數據的時候就呈現了RecordStoreFullException異常,因此我編寫了一個主動測試手機Record Store最大存儲空間的軟件。
原理是每隔必定時間例如100-500毫秒向Record Store內寫進1K字節的數據,當拋出存儲空間已滿的異常的時候就可以得到最大值了,准確單位為K字節。下面是程序的源代碼和JAD文件的內容,開發平台為Eclipse3.0RC2+EclipseME0.4.1+Wtk2.1+J2SDK1.4.2._03,在真機諾基亞 6108上測試通過並顯示最大值為31K。(請不要在模仿器上進行測試,那樣成果沒有意義)
這裡只是帶領讀者對Record Management System進行了大概的懂得,固然在文章最後供給了一個利用程序。但是並沒有深進分析如何應用Record Management System。在接下來的文章中我們會深進分析Javax.microedition.rms包中的類,重點是如何應用RecordStore類。
在先容如何應用Record Management System之前,我想首先先容一下Java IO以及在J2ME平台實現序列化的內容,無論對Record Management System還是MIDP中的通用聯網框架來說,上述內容都是非常重要的。
在CLDC中定義的Java IO是非常短小精悍的,但是也供給了足夠的類來完成我們的IO把持。由於和J2SE的實現是通用的,因此你可以應用J2ME和J2SE或者J2EE平台進行通信。比如通過聯網和servlet進行通信。在Record Management System中我們重要應用的類是ByteArrayInputStream、ByteArrayOutputStream、DataInputStream和DataOutputStream。前面兩個是基於字節的,ByteArrayInputStream的作用是把字節數組轉換成流而ByteArrayOutputStream的作用是把內存緩沖區內的數據轉換成字節。後面兩個類是基於Java基礎數據類型和String把持的。通常他們把前面兩個類作為參數傳送給結構器,這樣他們就可以對基礎數據類型以及String進行讀寫把持了。
值得留心的一點是ByteArrayOutputStream的toByteArray()方法是把內存中的數據進行復制返回,這樣的話多浪費了一份內存,為了更有效的應用有限的存儲空間你可以擴大ByteArrayOutputSteam類然後供給getByteArray()方法,下面是例子:
public class MyByteArrayOutputStream extends ByteArrayOutputStream
{
public byte[] getByteArray()
{
return buf;
}
}
在J2ME中並沒有供給對象序列化的機制,但是我們可以自己實現它。請考慮下面這個類:
public class Bank
{
private String bankName;
private String phone;
private int employeeNum;
public Bank(){}
public Bank(String aBankName,String aPhone,int aEmployeeNum)
{
this.bankName = aBankName;
this.phone = aPhone;
this.employeeNum = aEmployeeNum;
}
public String getBankName()
{
return bankName !=null?bankName:"";
}
public String getPhone()
{
return phone!=null?phone:"";
}
public int getEmployeeNum()
{
return employeeNum;
}
}
我們添加兩個方法到這個類來實現對象序列化。如下所示:
public class Bank
{
private String bankName;
private String phone;
private int employeeNum;
public Bank(){}
public Bank(String aBankName,String aPhone,int aEmployeeNum)
{
this.bankName = aBankName;
this.phone = aPhone;
this.employeeNum = aEmployeeNum;
}
public String getBankName()
{
return bankName !=null?bankName:"";
}
public String getPhone()
{
return phone!=null?phone:"";
}
public int getEmployeeNum()
{
return employeeNum;
}
public byte[] serialize() throws IOException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream DOS = new DataOutputStream(bos);
DOS.writeUTF(getBankName());
DOS.writeUTF(getPhone());
DOS.writeInt(getEmployeeNum());
DOS.flush();
return bos.toByteArray();
}
public Bank deserialize(byte[] data) throws IOException
{
ByteArrayInputStream bis = new ByteArrayInputStream(data);
DataInputStream dis = new DataInputStream(bis);
Bank myBank = new Bank(); myBank.bankName = dis.readUTF();
myBank.phone = dis.readUTF();
myBank.employeeNum = dis.readInt();
return myBank;
}
}
這樣我們就實現了對象的序列化,應用起來也非常簡略。序列化和反序列化的把持分辨如下面所示:
Bank aBank = .....;
RecordStore rs = .....;
try
{
byte[] data = aBank.serialize();
rs.addRecord(data,0,data.length);
}
catch(IOException e)
{
//do something
}
catch(RecordStoreException e)
{
//do something
}
byte[] data = ..........;
Bank aBank = null;
try
{
aBank = Bank.deserialize(data);
}
catch(IOException e)
{
}
值得留心的一點是在Bank類中我們的成員都是基礎數據類型以及String類型,並不存在指向其他對象的引用,這是最幻想也是最簡略的情況,事實上我們在J2ME中設計序列化的類的時候也應當盡量這樣做,避免不必要得麻煩