在我幾個Android應用中,我需要訪問已有的數據庫。這些數據庫往往很大,甚至超過asset文件大約1兆字節的限制。而且在新的版本中數據庫需要更新。我在網上,特別是StackOverflow看了一些文章,並做了一些試驗,覺得下面的代碼能基本上滿足我的需求。
其主要思路是:
1. 把數據庫分解成幾個asset文件。
2. 當需要打開數據庫時,如果數據庫不存在,就把那幾個asset文件重新合並成一個數據庫文件。
3. 如果數據庫的版本改變了,就在onUpgrade()方法中把數據庫文件刪除掉。
下面是代碼:
//數據庫的缺省路徑
private static finalString DB_PATH = "/data/data/com.mypackage.myapp/databases/";
private static finalString DB_NAME = "mydb.db";
private static finalint DB_VERSION = 2;
private static finalString DB_SPLIT_NAME = "mydb.db.00";
private static finalint DB_SPLIT_COUNT = 3;
private SQLiteDatabasem_database;
private final Contextm_context;
/**
* Constructor
*保存傳進來的context參數以用來訪問應用的asset和資源文件。
* @param context
*/
public MyDB(Contextcontext) {
super(context, DB_NAME, null, DB_VERSION);
this.m_context = context;
}
public static MyDBopenDatabaseReadOnly(Context context) {
MyDB db = new MyDB(context);
try {
db.createDataBase();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
db.openDataBase(SQLiteDatabase.OPEN_READONLY);
return db;
}
public static MyDBopenDatabaseReadWrite(Context context) {
MyDB db = new MyDB(context);
try {
db.createDataBase();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
db.openDataBase(SQLiteDatabase.OPEN_READWRITE);
return db;
}
/**
*創建一個空數據庫,用來存儲你已有的數據庫。
*/
public voidcreateDataBase() throws IOException{
boolean dbExist =checkDataBase();
if (dbExist) {
/*
**如果你的數據庫的版本改變了,調用這個方法確保在onUpgrade()被調用時
**傳進去的是可寫的數據庫。
*/
SQLiteDatabase db =this.getWritableDatabase();
if (db != null) {
db.close();
}
}
dbExist = checkDataBase();
if (!dbExist) {
try {
/*
** 調用這個方法以確保在缺省路徑內產生一個空數據庫,以便在其基礎上復制我們已有的數據庫。
*/
SQLiteDatabase db =this.getReadableDatabase();
if (db != null) {
db.close();
}
copyDataBase();
}
catch (IOException e) {
Log.e("DB", e.getMessage());
throw new Error("Error copyingdatabase");
}
}
}
/**
* 檢查數據庫是否已存在,以避免重復復制。
* @return true if it exists, false if itdoesn't
*/
private static booleancheckDataBase(){
SQLiteDatabase checkDB = null;
try {
String path = DB_PATH + DB_NAME;
checkDB =SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
}
catch (SQLiteException e){
//database does't exist yet.
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
/**
* 把存在asset文件中的數據庫復制的剛創建的空數據庫中。
* */
private voidcopyDataBase() throws IOException {
// 剛創建的空數據庫的路徑
String outFileName = DB_PATH + DB_NAME;
// 打開空數據庫
OutputStream output = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024*8];
AssetManager assetMgr =m_context.getAssets();
for (int i = 1; i <= DB_SPLIT_COUNT; i++){
// 打開分解的asset文件
String fn = DB_SPLIT_NAME +String.valueOf(i);
InputStream input = assetMgr.open(fn);
//Log.i("DB", "opened" + fn);
int length;
while ((length = input.read(buffer)) >0) {
//Log.i("DB", "read" + String.valueOf(length));
output.write(buffer, 0, length);
//Log.i("DB", "write" + String.valueOf(length));
}
input.close();
}
//Close the streams
output.flush();
output.close();
}
/**
* 打開數據庫。
* */
private voidopenDataBase(int flags) throws SQLException{
//Open the database
String myPath = DB_PATH + DB_NAME;
m_database =SQLiteDatabase.openDatabase(myPath, null, flags);
}
/**
* 關閉數據庫。
* */
@Override
public synchronizedvoid close() {
if (m_database != null)
m_database.close();
super.close();
}
}
@Override
public voidonCreate(SQLiteDatabase db) {
// 不需做任何事
}
/**
* 在數據庫版本提高時,刪除原有數據庫。
* */
@Override
public voidonUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
m_context.deleteDatabase(DB_NAME);
}
}
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11