使用Android中自帶的SQLiteOpenHelper可以完成數(shù)據(jù)庫的創(chuàng)建與管理,但有兩點(diǎn)局限:
(1)數(shù)據(jù)庫創(chuàng)建在內(nèi)存卡中,大小受限,創(chuàng)建位置位于/data/data/應(yīng)用程序名/databases中(可使用Eclispe的DDMS查看)。
(2)如果無法獲取Root權(quán)限,則無法直接查看創(chuàng)建的數(shù)據(jù)庫。
鑒于上述限制及實(shí)際需要,打算使用SQLiteOpenHelper管理SD卡上的數(shù)據(jù)庫,通過研究SQLiteOpenHelper的源碼,發(fā)現(xiàn)其創(chuàng)建或打開數(shù)據(jù)庫的代碼位于getWritableDatabase()函數(shù)中(getReadableDatabase本身也是調(diào)用了getWritableDatabase):
if (mName == null) { db = SQLiteDatabase.create(null); } else { db = mContext.openOrCreateDatabase(mName, 0, mFactory); }
分析上述代碼發(fā)現(xiàn),當(dāng)數(shù)據(jù)庫名字為非空時(shí),創(chuàng)建數(shù)據(jù)庫或打開由mContext完成,這個(gè)mContext由SQLiteOpenHelper的構(gòu)造函數(shù)傳入:SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)。那么我們對于傳入的context,重載其openOrCreateDatabase函數(shù),使其將數(shù)據(jù)庫創(chuàng)建到SD卡中就可完成我們的目標(biāo)了~。
對應(yīng)的SQLiteOpenHelper實(shí)現(xiàn)類SdCardDBHelper
import android.content.Context; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; /** * 數(shù)據(jù)庫管理和維護(hù)類 **/ public class SdCardDBHelper extends SQLiteOpenHelper{ public static final String TAG = "SdCardDBHelper"; /** * 數(shù)據(jù)庫名稱 **/ public static String DATABASE_NAME = "sddb.db"; /** * 數(shù)據(jù)庫版本 **/ public static int DATABASE_VERSION = 1; /** * 構(gòu)造函數(shù) * * @param context 上下文環(huán)境 **/ public SdCardDBHelper(Context context){ super(context, DATABASE_NAME, null, DATABASE_VERSION); } /** * 創(chuàng)建數(shù)據(jù)庫時(shí)觸發(fā),創(chuàng)建離線存儲(chǔ)所需要的數(shù)據(jù)庫表 * * @param db **/ @Override public void onCreate(SQLiteDatabase db) { Log.e(TAG, "開始創(chuàng)建數(shù)據(jù)庫表"); try{ //創(chuàng)建用戶表(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, "創(chuàng)建離線所需數(shù)據(jù)庫表成功"); } catch(SQLException se){ se.printStackTrace(); Log.e(TAG, "創(chuàng)建離線所需數(shù)據(jù)庫表失敗"); } } /** 更新數(shù)據(jù)庫時(shí)觸發(fā), * * @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卡上創(chuàng)建數(shù)據(jù)庫的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; /** * 用于支持對存儲(chǔ)在SD卡上的數(shù)據(jù)庫的訪問 **/ public class DatabaseContext extends ContextWrapper { /** * 構(gòu)造函數(shù) * @param base 上下文環(huán)境 */ public DatabaseContext(Context base){ super(base); } /** * 獲得數(shù)據(jù)庫路徑,如果不存在,則創(chuàng)建對象對象 * @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";//數(shù)據(jù)庫所在目錄 String dbPath = dbDir+"/"+name;//數(shù)據(jù)庫路徑 //判斷目錄是否存在,不存在則創(chuàng)建該目錄 File dirFile = new File(dbDir); if(!dirFile.exists()) dirFile.mkdirs(); //數(shù)據(jù)庫文件是否創(chuàng)建成功 boolean isFileCreateSuccess = false; //判斷文件是否存在,不存在則創(chuàng)建該文件 File dbFile = new File(dbPath); if(!dbFile.exists()){ try { isFileCreateSuccess = dbFile.createNewFile();//創(chuàng)建文件 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else isFileCreateSuccess = true; //返回?cái)?shù)據(jù)庫文件對象 if(isFileCreateSuccess) return dbFile; else return null; } } /** * 重載這個(gè)方法,是用來打開SD卡上的數(shù)據(jù)庫的,android 2.3及以下會(huì)調(diào)用這個(gè)方法。 * * @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會(huì)調(diào)用此方法獲取數(shù)據(jù)庫。 * * @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; } }
調(diào)用程序:
DatabaseContext dbContext = new DatabaseContext(this); SdCardDBHelper dbHelper = new SdCardDBHelper(dbContext);
這里尤其值得注意的是,不同版本的android API會(huì)調(diào)用不同的openOrCreateDatabase函數(shù)。
當(dāng)然也可直接使用SQLiteDatabase創(chuàng)建SD卡上的數(shù)據(jù)庫,或者直接修改SQLiteOpenHelper的源碼重新編譯,不過前者沒有對數(shù)據(jù)庫進(jìn)行一些檢驗(yàn)容錯(cuò)處理,也不及SQLiteOpenHelper對數(shù)據(jù)庫操作方便。后者工作量較大,不建議采用。
最后注意記得加入對SD卡的讀寫權(quán)限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
SQLite桌面查看工具:sqlite administrator、sqlite man或者firefox插件sqlite manager等。