網(wǎng)絡(luò)資源整理自用,非原創(chuàng)。
- 配置
//project配置
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'org.greenrobot:greendao-gradle-plugin:3.1.0'
}
}
//module配置
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'
android {
greendao {
schemaVersion 1 //數(shù)據(jù)庫版本
targetGenDir '*******' //生成DaoMaster類文件夾
daoPackage '**********' //生成DaoMaster類包名
}
dependencies {
compile 'org.greenrobot:greendao:3.1.0'
}
- 表創(chuàng)建
@Entity(nameInDb = "Book")
public class Book {
@Id(autoincrement = true)
@Property(nameInDb = "no")
//@Unique
private String no;
@Property(nameInDb = "title")
//@Transient
private String title;
@Property(nameInDb = "author")
//@NotNull
private String author;}```
@Entity 用于標(biāo)識這是一個需要Greendao幫我們生成代碼的bean
@Id 標(biāo)明主鍵,括號里可以指定是否自增
@Property 用于設(shè)置屬性在[數(shù)據(jù)庫](http://lib.csdn.net/base/mysql)中的列名(默認(rèn)不寫就是保持一致)
@NotNull 非空
@Transient 標(biāo)識這個字段是自定義的不會創(chuàng)建到數(shù)據(jù)庫表里
@Unique 添加唯一約束
  make projeck后會自動添加seter,geter以及構(gòu)造函數(shù)。并且會新加三個類:
- BookDao
- DaoMaster
- DaoSession
2. 封裝
//網(wǎng)上找的封裝
public class DBManager {
private DaoMaster mDaoMaster;
private DaoSession mDaoSession;
private static DBManager mInstance; //單例
private DBManager(){
if (mInstance == null) {
DaoMaster.DevOpenHelper devOpenHelper = new MergeDevOpenHelper(new GreenDaoContext(), "******.db");
mDaoMaster = new DaoMaster(devOpenHelper.getWritableDatabase());
mDaoSession = mDaoMaster.newSession();
}
}
public static DBManager getInstance() {
if (mInstance == null) {
synchronized (DBManager.class) {//保證異步處理安全操作
if (mInstance == null) {
mInstance = new DBManager();
}
}
}
return mInstance;
}
public DaoMaster getMaster() {
return mDaoMaster;
}
public DaoSession getSession() {
return mDaoSession;
}
public DaoSession getNewSession() {
mDaoSession = mDaoMaster.newSession();
return mDaoSession;
}
}
1. 使用
//在application的onCreate中調(diào)用getInstance
DBManager.getInstance();
//可以再封裝,調(diào)用api實(shí)現(xiàn)增刪改查
DBManager.getInstance().getSession().getBookDao().queryBuilder().list();//查詢book表中所有數(shù)據(jù)
5. 升級和遷移
  普通升級直接修改數(shù)據(jù)庫版本號就可以了,但是默認(rèn)實(shí)現(xiàn)會刪除所有數(shù)據(jù),重新創(chuàng)建數(shù)據(jù)庫表格。所以需要自己實(shí)現(xiàn)升級。
public class MergeDevOpenHelper extends DaoMaster.OpenHelper{
public MergeDevOpenHelper(Context context, String name) {
super(context, name);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
MigrationHelper.getInstance().migrate(db, BookDao.class);
}
}
//類是從github中copy出來的,非原創(chuàng)。。。。。
public class MigrationHelper {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION =
"MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static MigrationHelper instance;
public static MigrationHelper getInstance() {
if (instance == null) {
instance = new MigrationHelper();
}
return instance;
}
public void migrate(Database db, Class... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
private void generateTempTables(Database db, Class... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
}
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if (daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
}
divider = ",";
}
}
createTableStringBuilder.append(");");
db.execSQL(createTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}
private void restoreData(Database db, Class... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList properties = new ArrayList();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tempTableName).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(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(insertTableStringBuilder.toString());
db.execSQL(dropTableStringBuilder.toString());
}
}
private String getTypeByClass(Class type) throws Exception {
if (type.equals(String.class)) {
return "TEXT";
}
if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
return "INTEGER";
}
if (type.equals(Boolean.class)) {
return "BOOLEAN";
}
Exception exception =
new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
throw exception;
}
private static List getColumns(Database db, String tableName) {
List columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null) cursor.close();
}
return columns;
}
}
上邊處理了數(shù)據(jù)庫升級,數(shù)據(jù)遷移的問題。
在我自己的項目中還有一個問題是需要處理外部數(shù)據(jù)庫,所以還需指定一個數(shù)據(jù)庫路徑。
public class GreenDaoContext extends ContextWrapper {
private String currentUserId = "greendao";//一般用來針對一個用戶一個數(shù)據(jù)庫,以免數(shù)據(jù)混亂問題
private Context mContext;
public GreenDaoContext() {
super(BaseApp.gContext);
this.mContext = BaseApp.gContext;
// this.currentUserId = "greendao";//初始化
}
/**
* 獲得數(shù)據(jù)庫路徑,如果不存在,則創(chuàng)建對象
*
* @param dbName
*/
@Override
public File getDatabasePath(String dbName) {
String dbDir = "";//指定數(shù)據(jù)庫路徑
if (TextUtils.isEmpty(dbDir)){
Log.e("SD卡管理:", "SD卡不存在,請加載SD卡");
return null;
}
File baseFile = new File(dbDir);
// 目錄不存在則自動創(chuàng)建目錄
if (!baseFile.exists()){
baseFile.mkdirs();
}
StringBuffer buffer = new StringBuffer();
buffer.append(baseFile.getPath());
buffer.append(File.separator);
// buffer.append(currentUserId);
dbDir = buffer.toString();// 數(shù)據(jù)庫所在目錄
// buffer.append(File.separator);
// buffer.append(dbName+"_"+currentUserId);//也可以采用此種方式,將用戶id與表名聯(lián)系到一塊命名
buffer.append(dbName);
String dbPath = buffer.toString();// 數(shù)據(jù)庫路徑
LogUtil.e(LogUtil.getLogTag()+dbPath);
// 判斷目錄是否存在,不存在則創(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 {
LogUtil.e(LogUtil.getLogTag()+"創(chuàng)建db");
isFileCreateSuccess = dbFile.createNewFile();// 創(chuàng)建文件
} catch (IOException e) {
e.printStackTrace();
}
} else
isFileCreateSuccess = true;
// 返回數(shù)據(jù)庫文件對象
if (isFileCreateSuccess)
return dbFile;
else
return super.getDatabasePath(dbName);
}
/**
* 重載這個方法,是用來打開SD卡上的數(shù)據(jù)庫的,android 2.3及以下會調(diào)用這個方法。
*
* @param name
* @param mode
* @param factory
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,SQLiteDatabase.CursorFactory factory) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
return result;
}
/**
* Android 4.0會調(diào)用此方法獲取數(shù)據(jù)庫。
*
* @param name
* @param mode
* @param factory
* @param errorHandler
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int,
* android.database.sqlite.SQLiteDatabase.CursorFactory,
* android.database.DatabaseErrorHandler)
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory,DatabaseErrorHandler errorHandler) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
return result;
}
}