使用Android中自帶的SQLiteOpenHelper可以完成數據庫的創建與管理,但有兩點局限:
(1)數據庫創建在內存卡中,大小受限,創建位置位于/data/data/應用程序名/databases中(可使用Eclispe的DDMS查看)。
(2)如果無法獲取Root權限,則無法直接查看創建的數據庫。
鑒于上述限制及實際需要,打算使用SQLiteOpenHelper管理SD卡上的數據庫,通過研究SQLiteOpenHelper的源碼,發現其創建或打開數據庫的代碼位于getWritableDatabase()函數中(getReadableDatabase本身也是調用了getWritableDatabase):
if (mName == null) { db = SQLiteDatabase.create(null); } else { db = mContext.openOrCreateDatabase(mName, 0, mFactory); }
分析上述代碼發現,當數據庫名字為非空時,創建數據庫或打開由mContext完成,這個mContext由SQLiteOpenHelper的構造函數傳入:SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)。那么我們對于傳入的context,重載其openOrCreateDatabase函數,使其將數據庫創建到SD卡中就可完成我們的目標了~。
對應的SQLiteOpenHelper實現類SdCardDBHelper
import android.content.Context; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; /** * 數據庫管理和維護類 **/ public class SdCardDBHelper extends SQLiteOpenHelper{ public static final String TAG = "SdCardDBHelper"; /** * 數據庫名稱 **/ public static String DATABASE_NAME = "sddb.db"; /** * 數據庫版本 **/ public static int DATABASE_VERSION = 1; /** * 構造函數 * * @param context 上下文環境 **/ public SdCardDBHelper(Context context){ super(context, DATABASE_NAME, null, DATABASE_VERSION); } /** * 創建數據庫時觸發,創建離線存儲所需要的數據庫表 * * @param db **/ @Override public void onCreate(SQLiteDatabase db) { Log.e(TAG, "開始創建數據庫表"); try{ //創建用戶表(user) db.execSQL("create table if not exists user" + "(_id integer primary key autoincrement,name varchar(20),password varchar(20),role varchar(10),updateTime varchar(20))"); Log.e(TAG, "創建離線所需數據庫表成功"); } catch(SQLException se){ se.printStackTrace(); Log.e(TAG, "創建離線所需數據庫表失敗"); } } /** 更新數據庫時觸發, * * @param db * @param oldVersion * @param newVersion **/ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //db.execSQL("ALTER TABLE person ADD COLUMN other STRING"); } }
重載的openOrCreateDatabase在sd卡上創建數據庫的Context
import java.io.File; import java.io.IOException; import android.content.Context; import android.content.ContextWrapper; import android.database.DatabaseErrorHandler; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.util.Log; /** * 用于支持對存儲在SD卡上的數據庫的訪問 **/ public class DatabaseContext extends ContextWrapper { /** * 構造函數 * @param base 上下文環境 */ public DatabaseContext(Context base){ super(base); } /** * 獲得數據庫路徑,如果不存在,則創建對象對象 * @param name * @param mode * @param factory */ @Override public File getDatabasePath(String name) { //判斷是否存在sd卡 boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState()); if(!sdExist){//如果不存在, Log.e("SD卡管理:", "SD卡不存在,請加載SD卡"); return null; } else{//如果存在 //獲取sd卡路徑 String dbDir=android.os.Environment.getExternalStorageDirectory().getAbsolutePath(); dbDir += "/database";//數據庫所在目錄 String dbPath = dbDir+"/"+name;//數據庫路徑 //判斷目錄是否存在,不存在則創建該目錄 File dirFile = new File(dbDir); if(!dirFile.exists()) dirFile.mkdirs(); //數據庫文件是否創建成功 boolean isFileCreateSuccess = false; //判斷文件是否存在,不存在則創建該文件 File dbFile = new File(dbPath); if(!dbFile.exists()){ try { isFileCreateSuccess = dbFile.createNewFile();//創建文件 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else isFileCreateSuccess = true; //返回數據庫文件對象 if(isFileCreateSuccess) return dbFile; else return null; } } /** * 重載這個方法,是用來打開SD卡上的數據庫的,android 2.3及以下會調用這個方法。 * * @param name * @param mode * @param factory */ @Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) { SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null); return result; } /** * Android 4.0會調用此方法獲取數據庫。 * * @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int, * android.database.sqlite.SQLiteDatabase.CursorFactory, * android.database.DatabaseErrorHandler) * @param name * @param mode * @param factory * @param errorHandler */ @Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) { SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null); return result; } }
調用程序:
DatabaseContext dbContext = new DatabaseContext(this); SdCardDBHelper dbHelper = new SdCardDBHelper(dbContext);
這里尤其值得注意的是,不同版本的android API會調用不同的openOrCreateDatabase函數。
當然也可直接使用SQLiteDatabase創建SD卡上的數據庫,或者直接修改SQLiteOpenHelper的源碼重新編譯,不過前者沒有對數據庫進行一些檢驗容錯處理,也不及SQLiteOpenHelper對數據庫操作方便。后者工作量較大,不建議采用。
最后注意記得加入對SD卡的讀寫權限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
SQLite桌面查看工具:sqlite administrator、sqlite man或者firefox插件sqlite manager等。