- 論壇徽章:
- 0
|
筆者在前面的兩篇文章《
兩個(gè)小時(shí)精通Android開(kāi)發(fā)之界面篇
》、《
兩個(gè)小時(shí)精通Android開(kāi)發(fā)之按鍵映射篇
》分別講了無(wú)縫移植J2ME程序到Android平臺(tái)上對(duì)界面和用戶按鍵交互所做的適配接口,原則上利用這些接口原有的J2ME程序基本不用做任何的修改就可以運(yùn)行在Android平臺(tái)上,所以精通J2ME也就等于精通了Android。
筆者這篇文章里要講述的是J2ME平臺(tái)和Android平臺(tái)另外一個(gè)重要的不同點(diǎn),那就是數(shù)據(jù)持久存儲(chǔ)系統(tǒng)。
J2ME平臺(tái)里采用RMS系統(tǒng)進(jìn)行數(shù)據(jù)的持久存儲(chǔ),而Android平臺(tái)則提供了豐富的接口進(jìn)行數(shù)據(jù)的持久存儲(chǔ),但任何持久存儲(chǔ)的本質(zhì)無(wú)非就是數(shù)據(jù)串行化后被保存到磁盤空間上,仔細(xì)研究J2ME平臺(tái)RMS系統(tǒng)的實(shí)現(xiàn)源碼可以看到,J2ME是通過(guò)一個(gè)叫做RecordStoreFile的類進(jìn)行數(shù)據(jù)持久化存儲(chǔ)的,而這個(gè)RecordStoreFile類的實(shí)現(xiàn)如下:
public class RecordStoreFile {
private static SecurityToken classSecurityToken;
private static final String dbExtension = ".db";
private RandomAccessStream recordStream;
private String myStoragePath;
public static void initSecurityToken(SecurityToken token) {
if (classSecurityToken != null) {
return;
}
classSecurityToken = token;
}
public RecordStoreFile(String uidPath)
throws IOException
{
RandomAccessStream newStream;
myStoragePath = uidPath;
newStream = new RandomAccessStream(classSecurityToken);
newStream.connect(myStoragePath, Connector.READ_WRITE);
recordStream = newStream;
}
public static String getUniqueIdPath(String fileName) {
return getStoragePath(fileName);
}
public static String getUniqueIdPath(String vendorName, String suiteName,
String fileName) {
return getStoragePath(vendorName, suiteName, fileName);
}
public static boolean exists(String uidPath) {
File file;
file = new File(classSecurityToken);
return file.exists(uidPath);
}
public static boolean deleteFile(String uidPath)
{
File file;
file = new File(classSecurityToken);
try {
file.delete(uidPath);
return true;
} catch (IOException ioe) {
return false;
}
}
public void seek(int pos) throws IOException
{
recordStream.setPosition(pos);
}
public void write(byte[] buf) throws IOException
{
write(buf, 0, buf.length);
}
public void write(byte[] buf, int offset, int numBytes) throws IOException
{
recordStream.writeBytes(buf, offset, numBytes);
}
public int read(byte[] buf) throws IOException
{
return read(buf, 0, buf.length);
}
public int read(byte[] buf, int offset, int numBytes) throws IOException
{
return recordStream.readBytes(buf, offset, numBytes);
}
public void close() throws IOException
{
// close recordStream if it exists
if (recordStream != null) {
recordStream.disconnect();
recordStream = null;
}
}
public void truncate(int size) throws IOException
{
if (recordStream != null) {
recordStream.truncate(size);
}
}
public static String[] listRecordStores() {
return listRecordStoresForSuite(new File(classSecurityToken),
getStoragePath(null), false);
}
private static String[] listRecordStoresForSuite(File storage,
String suiteStorageRoot,
boolean rawNames) {
Vector files;
Vector names;
String file;
String asciiName;
files = storage.filenamesThatStartWith(suiteStorageRoot);
names = new Vector();
// work through list of strings from the directory
for (int i = 0; i
file = (String)files.elementAt(i);
if (file.endsWith(dbExtension)) {
if (rawNames) {
names.addElement(file);
} else {
asciiName = file.substring(suiteStorageRoot.length(),
file.length() - 3);
names.addElement(File.asciiFilenameToUnicode(asciiName));
}
}
}
if (names.size() == 0) {
return null;
}
String[] rv = new String[names.size()];
names.copyInto(rv);
return rv;
}
public static void removeRecordStoresForSuite(SecurityToken token,
String suiteStorageRoot) {
File storage;
String[] filenames;
storage = new File(token);
filenames = listRecordStoresForSuite(storage, suiteStorageRoot, true);
if (filenames == null) {
return;
}
for (int i = 0; i
try {
storage.delete(filenames);
} catch (IOException ioe) {
// move on to the next suite
}
}
}
public static boolean suiteHasRmsData(String suiteStorageRoot) {
File storage = new File(classSecurityToken);
Vector files = storage.filenamesThatStartWith(suiteStorageRoot);
for (int i = 0; i
String file = (String)files.elementAt(i);
if (file.endsWith(dbExtension)) {
return true;
}
}
return false;
}
public static int spaceAvailable()
{
return new File(classSecurityToken).getBytesAvailableForFiles();
}
private static String getStoragePath(String name)
{
String str;
MIDletSuite mSuite;
StringBuffer path;
mSuite = Scheduler.getScheduler().getMIDletSuite();
str = mSuite.getStorageRoot();
if (name != null) {
path = new StringBuffer(str);
// convert the unicode filename into a system acceptable string
path.append(File.unicodeToAsciiFilename(name));
path.append(dbExtension);
str = path.toString();
}
return str;
}
private static String getStoragePath(String vendor, String suite,
String name) {
String str = File.getStorageRoot();
StringBuffer path = new StringBuffer(str);
if (vendor != null && suite != null) {
path.append(File.unicodeToAsciiFilename(vendor));
path.append('_');
path.append(File.unicodeToAsciiFilename(suite));
path.append('_');
}
if (name != null) {
path.append(File.unicodeToAsciiFilename(name));
path.append(dbExtension);
str = path.toString();
}
return str;
}
}
可見(jiàn),RMS系統(tǒng)也是通過(guò)IO把數(shù)據(jù)串行化后存儲(chǔ)應(yīng)用程序的空間內(nèi)的,絕大多數(shù)的J2ME程序都需要利用RMS來(lái)進(jìn)行數(shù)據(jù)的持久存儲(chǔ)的,比如游戲積分、系統(tǒng)設(shè)置等。那么為了無(wú)縫移植J2ME到Android平臺(tái),筆者自己寫(xiě)了一個(gè)簡(jiǎn)易的RMS系統(tǒng),能滿足絕大多數(shù)應(yīng)用程序的需要。
Android下對(duì)文件的操作和J2ME基本一樣,但是需要綁定一個(gè)Context上下文,以把文件保存到當(dāng)前應(yīng)用程序的目錄下,這個(gè)目錄在打開(kāi)DDMS窗口后可以看到,具體位置是data/data/PACKAGE_NAME/files下面。
利用文件操作可以進(jìn)行數(shù)據(jù)的讀寫(xiě),筆者封裝的接口如下:
public static boolean deleteFile(String fileName){
File file = new File(fileName);
if(file.isFile() && file.exists()){
file.delete();
System.out.println("刪除單個(gè)文件"+fileName+"成功!");
return true;
}else{
System.out.println("刪除單個(gè)文件"+fileName+"失!");
return false;
}
}
public String read(String file) {
String data = "";
try {
FileInputStream stream = System.getSystemHandler().getContext().openFileInput(file);
StringBuffer sb = new StringBuffer();
int c;
while ((c = stream.read()) != -1) {
sb.append((char) c);
}
stream.close();
data = sb.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
public void write(String file, byte[] msg) {
try {
FileOutputStream stream = System.getSystemHandler().getContext().openFileOutput(file,Context.MODE_WORLD_WRITEABLE);
stream.write(msg);
stream.flush();
stream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
有了基本的讀寫(xiě)數(shù)據(jù)操作,就可以封裝RMS中常見(jiàn)的key-value的保存和讀取了,代碼實(shí)現(xiàn)如下:
public boolean put(String key, byte[] value) {
boolean bSaveOk = false;
byte[] data = null;
if (value == null) {
throw new NullPointerException();
}
ByteArrayOutputStream bout = null;
DataOutputStream dout = null;
try {
bout = new ByteArrayOutputStream();
dout = new DataOutputStream(bout);
dout.writeUTF(key);
dout.writeInt(value.length);
dout.write(value, 0, value.length);
data = bout.toByteArray();
write(dbName,data);
bSaveOk = true;
} catch (Exception e) {
bSaveOk = false;
e.printStackTrace();
}
return bSaveOk;
}
public byte[] getByteArray(String key) {
ByteArrayInputStream bin = null;
DataInputStream din = null;
byte[] data = null;
try {
String valueKey = read(dbName);
din = new DataInputStream(new ByteArrayInputStream(valueKey.getBytes()));
while(din.available() > 0)
{
String getKey = din.readUTF();
int getLength = din.readInt();
data = new byte[getLength];
int bytesRead = 0;
while (bytesRead
int count = din.read(data, bytesRead, data.length
- bytesRead);
if (count == -1)
break;
bytesRead += count;
}
if(getKey.equals(key))
break;
}
din.close();
din = null;
} catch (Exception e) {
e.printStackTrace();
data = null;
}
return data;
}
}
本文來(lái)自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u2/88379/showart_2151738.html |
|