1.背景
所謂外部數據庫文件此處指的就是一個在外部單獨創建的db文件,假設有這么一個場景,我們項目中有一些本地數據,不需要接口去獲取的(不需要進行網絡操作),寫死的數據,比如全國各個省各個市的一些基本信息,每個市的信息可以作為表里的一條記錄存放,在項目中使用,此時如何我們已經有了包含這些信息的db文件,我們就可以通過greendao來操作這個db文件,更具方便進行開發工作,當然這只是個模擬情況,至於合不合理,有沒有更好的方式,此處不過多討論,重點講這么一種方式,這種方式可以用於一些不經常變化的數據。
2.項目配置
- 首先看一下項目結構:
res/raw目錄存放的就是外部的db文件的壓縮文件,我們可以打開看一下數據庫結構,db文件包含兩張表,student和teacher里面簡單的插入了幾條測試數據:
- 引入greendao庫文件或者引用庫工程:
2.代碼實現
實現之前先說一下具體的思路,程序運行,首先把raw目錄下的db文件拷貝到數據庫存儲的默認目錄,然后通過greendao的api對這個文件進行操作即可;
- 我們需要獲取應用db存儲的路徑,通過如下方式:
private void getAppInfo() { // 獲取packageManager的實例 PackageManager packageManager = getPackageManager(); // getPackageName()是你當前類的包名,0代表是獲取版本信息 try { packInfo = packageManager.getPackageInfo(getPackageName(), 0); } catch (NameNotFoundException e) { e.printStackTrace(); } }
-
通過以上方式即可獲取到數據庫的路徑:
-
拷貝操作:
public static boolean copyRawDBToApkDb(Context context, int copyRawDbResId, String apkDbPath, String dbName,boolean refresh) throws IOException { boolean b = false; File f = new File(apkDbPath); if (!f.exists()) { f.mkdirs(); } File dbFile = new File(apkDbPath + dbName); b = isDbFileExists(dbFile,refresh); if (!b) { InputStream is = context.getResources().openRawResource(copyRawDbResId); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is)); ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { int size; byte[] buffer = new byte[1024 * 2]; OutputStream fos = new FileOutputStream(apkDbPath + entry.getName()); BufferedOutputStream bos = new BufferedOutputStream(fos, buffer.length); while ((size = zis.read(buffer, 0, buffer.length)) != -1) { bos.write(buffer, 0, size); } bos.flush(); bos.close(); } zis.close(); is.close(); } return !b; }
此處是拷貝操作的關鍵代碼,需要我們傳入raw資源ID,數據庫的拷貝路徑,數據庫文件名,是否覆蓋已經存在的db文件,@return 拷貝是否成功,關於refresh參數,我們一般希望只拷貝一次,當我們在某些情況下更新了這個db文件的話就可以設置為true進行覆蓋操作;
- 使用greenDao java工程,生成外部db文件所對應表的實體類Dao類等代碼:
上圖中的DBController類是我封裝的數據庫操作類,更方便我們去進行操作,DBController的關鍵代碼如下:
/** * 外部數據庫控制類 */ public class DBController { private static DaoMaster daoMasterEcmc; private static DaoMaster daoMasterSchool; // 默認DB private static DaoSession daoSessionDefault; // 拷貝的db private static DaoSession daoSchoolSession; /** * 默認數據庫名稱:localdata */ public static final String DATABASE_NAME = "localdata.db"; /** * 拷貝數據庫名稱:school */ public static final String DATABASE_SCHOOL_NAME = "school.db"; private static DaoMaster obtainMaster(Context context, String dbName) { return new DaoMaster(new DaoMaster.DevOpenHelper(context, dbName, null).getWritableDatabase()); } private static DaoMaster getDaoMaster(Context context, String dbName) { if (dbName == null) return null; if (daoMasterEcmc == null) { daoMasterEcmc = obtainMaster(context, dbName); } return daoMasterEcmc; } private static DaoMaster getSchoolDaoMaster(Context context, String dbName) { if (dbName == null) return null; if (daoMasterSchool == null) { daoMasterSchool = obtainMaster(context, dbName); } return daoMasterSchool; } /** * 取得DaoSession * * @return */ public static DaoSession getDaoSession(String dbName) { if (daoSchoolSession == null) { daoSchoolSession = getSchoolDaoMaster(MainApplication.getIns(), dbName).newSession(); } return daoSchoolSession; } /** * 默認操作localdata數據庫 */ public static DaoSession getDaoSession() { if (daoSessionDefault == null) { daoSessionDefault = getDaoMaster(MainApplication.getIns(), DATABASE_NAME).newSession(); } return daoSessionDefault; } }
- 可能我們還需要默認的greendao數據庫進行其他的操作,至於默認的操作此處不再詳細介紹,不了解的可以看greendao基本使用,此處我們演示的外部DB文件命名為school.db,默認的greenDao數據庫命名為history.db,下面我們在MainActivity進行測試操作:
public class MainActivity extends Activity { private StringBuilder builder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //創建默認的數據,並插入一條數據 HistoryDao historyDao = DBLocalController.getDaoSession().getHistoryDao(); History entity = new History(); entity.setName("科羅拉多"); entity.setImageUrl("http://www.baidu.com"); historyDao.insert(entity); //拷貝外部DB文件到指定目錄 copyRawDB(); //通過greendao查詢外部db文件數據 selDBData(); } private void selDBData() { StudentDao student = DBController.getDaoSession(DBController.DATABASE_SCHOOL_NAME).getStudentDao(); List<Student> students = student.queryBuilder().list(); builder = new StringBuilder(); for (int i = 0; i < students.size(); i++) { builder.append(students.get(i).getName() + "---"); } Toast.makeText(MainActivity.this, builder.toString(), Toast.LENGTH_SHORT).show(); } private void copyRawDB() { try { // 拷貝res/raw/xxxxdb.zip 到 // /data/data/com.xinhang.mobileclient/databases/ 目錄下面 boolean isSuccess = DBUtils.copyRawDBToApkDb(MainActivity.this, R.raw.schooldb, DBUtils.APK_DB_PATH, DBUtils.ECMC_DB_NAME, false); } catch (IOException e) { e.printStackTrace(); } } }
運行結果:
可以看到我們的外部db文件已經拷貝到數據庫默認路徑下,還有我們的默認數據庫也創建成功;區分兩個數據庫的方式是通過DBLocalController.getDaoSession(name)方法,想操作哪個數據庫傳入對應的數據庫名稱即可,gif操作圖如下;
源碼下載:源碼下載,有問題歡迎交流討論!