一、使用Raw文件夾下的資料庫文件 在使用GreenDao框架時,資料庫和數據表都是根據生成的框架代碼來自動創建的,從生成的DaoMaster中的OpenHelper類可以看出: 對應的createAllTables函數代碼: 再接著往下看: 從以上的代碼可以看出GreenDao在第一次使用的時候會 ...
一、使用Raw文件夾下的資料庫文件
在使用GreenDao框架時,資料庫和數據表都是根據生成的框架代碼來自動創建的,從生成的DaoMaster中的OpenHelper類可以看出:
public static abstract class OpenHelper extends SQLiteOpenHelper { public OpenHelper(Context context, String name, CursorFactory factory) { super(context, name, factory, SCHEMA_VERSION); } @Override public void onCreate(SQLiteDatabase db) { Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
//修改第二個參數為true
createAllTables(db, false); } }
對應的createAllTables函數代碼:
/** Creates underlying database table using DAOs. */ public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) { xxxxxDao.createTable(db, ifNotExists); }
再接著往下看:
/** Creates the underlying database table. */ public static void createTable(SQLiteDatabase db, boolean ifNotExists) { String constraint = ifNotExists? "IF NOT EXISTS ": ""; db.execSQL("CREATE TABLE " + constraint + "'DOCTOR' (" + // "'_id' INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id "'NAME' TEXT," + // 1: name }
從以上的代碼可以看出GreenDao在第一次使用的時候會強制創建數據表,如果這樣的話很可能就會導致程式崩潰。
public static abstract class OpenHelper extends SQLiteOpenHelper { public OpenHelper(Context context, String name, CursorFactory factory) { super(context, name, factory, SCHEMA_VERSION); } @Override public void onCreate(SQLiteDatabase db) { Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); //修改第二個參數為true createAllTables(db, true); } }
所以要使用Raw文件中的資料庫文件需要以下幾步:
1)修改參數:
public static abstract class OpenHelper extends SQLiteOpenHelper { public OpenHelper(Context context, String name, CursorFactory factory) { super(context, name, factory, SCHEMA_VERSION); } @Override public void onCreate(SQLiteDatabase db) { Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); //修改第二個參數為true createAllTables(db, true); } }
2)添加GreenDaoContextWrapper.java文件到項目中
public class GreenDaoContextWrapper extends ContextWrapper {
private Context mContext;
public GreenDaoContextWrapper(Context base) {
super(base);
this.mContext= base;
}
@Override
public File getDatabasePath(String name) {
Log.d("GreenDao","getDatabasePath");
Log.d("GreenDao",mContext.getDatabasePath(name).getAbsolutePath());
String filePath=mContext.getDatabasePath(name).getAbsolutePath();
File file=new File(filePath);
if (!file.exists()){
buildDatabase(filePath);
}
return file;
}
/**
* 創建資料庫文件,其實就是將raw文件夾下的資料庫文件複製到應用的database文件夾下:
* /data/data/com.xxxx/databases/
* @param filePath
*/
private void buildDatabase(String filePath){
Log.d("GreenDao","buildDatabase");
InputStream inputStream=mContext.getResources().openRawResource(R.raw.accurmedicine);
FileOutputStream fos= null;
try {
fos = new FileOutputStream(filePath);
byte[] buffer=new byte[1024];
int length;
while ((length=inputStream.read(buffer))>0){
fos.write(buffer,0,length);
}
fos.close();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
Log.d("GreenDao","openOrCreateDatabase");
SQLiteDatabase result= SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name),factory);
return result;
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
Log.d("GreenDao","openOrCreateDatabase");
SQLiteDatabase result= SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name),factory);
return result;
}
}
這裡提一下:ContextWrapper是一個Context包裝類,需要包含一個真正的Context,詳細介紹看:
http://www.jianshu.com/p/94e0f9ab3f1d
3)在創建DevOpenHelper的時候使用GreenDaoContextWrapper
String DBName="xxx"; DaoMaster.DevOpenHelper helper=new DaoMaster.DevOpenHelper(new GreenDaoContextWrapper(context),DBName,null);
這樣就大功告成了!
二、資料庫版本升級
這個辦法是從網上看到的,還不錯,就搬過來了。
public class MigrationHelper { private static MigrationHelper instance; public static MigrationHelper getInstance() { if (instance==null){ instance=new MigrationHelper(); } return instance; } /** * 創建臨時表->刪除舊表->創建新表->導入數據 * @param database * @param daoClasses */ public void migrate(SQLiteDatabase database, Class<? extends AbstractDao<?,?>>...daoClasses){ generateTempTables(database,daoClasses); DaoMaster.dropAllTables(database,true); DaoMaster.createAllTables(database,false); restoreData(database,daoClasses); } /** * 臨時表生產 * @param database * @param daoClasses */ private void generateTempTables(SQLiteDatabase database,Class<? extends AbstractDao<?,?>>...daoClasses){ for (int i=0;i<daoClasses.length;i++){ DaoConfig config=new DaoConfig(database,daoClasses[i]); String divider=""; String tableName=config.tablename; String tmpTableName=config.tablename.concat("_TEMP"); ArrayList<String > properties=new ArrayList<>(); StringBuilder createTableStringBuilder=new StringBuilder(); createTableStringBuilder.append("CREATE TABLE ").append(tmpTableName).append(" ("); List<String> columns = getColumns(database, tableName); for (int j=0;j<config.properties.length;j++){ String columnName=config.properties[j].columnName; if (columns.contains(columnName)){ properties.add(columnName); String type=null; try { type=getTypeByClass(config.properties[j].type); } catch (Exception e) { e.printStackTrace(); } createTableStringBuilder.append(divider).append(columnName).append(" ").append(type); if (config.properties[j].primaryKey){ createTableStringBuilder.append(" PRIMARY KEY"); } divider=","; } } createTableStringBuilder.append(");"); Log.d("xxxxx","sql="+createTableStringBuilder.toString()); database.execSQL(createTableStringBuilder.toString()); StringBuilder insertTableString=new StringBuilder(); insertTableString.append("insert into ").append(tmpTableName).append(" ("); insertTableString.append(TextUtils.join(",",properties)); insertTableString.append(") select "); insertTableString.append(TextUtils.join(",",properties)); insertTableString.append(" from ").append(tableName).append(";"); Log.d("xxxxx","sql="+insertTableString.toString()); database.execSQL(insertTableString.toString()); } } /** * 數據欄位與Java數據類型匹配 * @param type * @return * @throws Exception */ private String getTypeByClass(Class<?> type) throws Exception { if (type.equals(String.class)){ return "TEXT"; } if (type.equals(Long.class)||type.equals(Integer.class)){ return "INTEGER"; } if (type.equals(Boolean.class)){ return "BOOLEAN"; } String strException="數據表數據類型匹配錯誤"; Exception exception=new Exception(strException.concat("- Class").concat(type.toString())); throw exception; } /** * 獲取當前數據表欄位列表 * @param database * @param tableName * @return */ private static List<String > getColumns(SQLiteDatabase database,String tableName){ List<String > columns=new ArrayList<>(); Cursor cursor=null; /** * 通過查詢數據表 */ cursor=database.rawQuery("select * from "+tableName+" limit 1",null); try { if (cursor!=null){ String[] columnNames = cursor.getColumnNames(); for (String name:columnNames){ columns.add(name.toUpperCase()); } // columns=new ArrayList<>(Arrays.asList(cursor.getColumnNames())); } }catch (Exception e){ e.printStackTrace(); }finally { if (cursor!=null){ cursor.close(); } } return columns; } /** * 數據恢復->刪除臨時表 * @param database * @param daoClasses */ private void restoreData(SQLiteDatabase database,Class<? extends AbstractDao<?,?>>...daoClasses){ for (int i=0;i<daoClasses.length;i++){ DaoConfig config=new DaoConfig(database,daoClasses[i]); String tableName=config.tablename; String tmpTableName=config.tablename.concat("_TEMP"); ArrayList<String > properties=new ArrayList<>(); for (int j=0;j<config.properties.length;j++){ String columnName = config.properties[j].columnName; if(getColumns(database, tmpTableName).contains(columnName)) { properties.add(columnName); } } StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" ("); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(" FROM ").append(tmpTableName).append(";"); StringBuilder dropTableStringBuilder = new StringBuilder(); dropTableStringBuilder.append("DROP TABLE ").append(tmpTableName); database.execSQL(insertTableStringBuilder.toString()); database.execSQL(dropTableStringBuilder.toString()); } } }
然後在需要資料庫版本設計的時候修改DaoMaster中的SCHEMA_VERSION
public static final int SCHEMA_VERSION = 1;
這個變數就是用於在創建OpenHelper時指定資料庫版本號。
緊接著修改DevOpenHelper的onUpgrade代碼:
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); // dropAllTables(db, true); // onCreate(db); MigrationHelper.getInstance() .migrate(db, paramsDao.class, ); }
最後大功告成!
順帶需要補充一下,查看SQLite資料庫版本可以執行以下這句語句:
PRAGMA user_version
設置SQLite資料庫版本的語句:
PRAGMA user_version =<你的版本號>
以上的這兩句話其實可以在SQLiteDatabase以及SQLiteOpenHelper的源碼中看到:
在android-24的SQLiteOpenHelper源碼中可以看到:
/** * Gets the database version. * * @return the database version */ public int getVersion() { return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue(); } /** * Sets the database version. * * @param version the new database version */ public void setVersion(int version) { execSQL("PRAGMA user_version = " + version); }
而SQLiteOpenHelper設置和獲取資料庫版本就是通過調用這兩句話來實現的,具體源碼可以查看SQLiteOpenHelper的getDatabaseLocked函數,這裡不再贅述。