greenDao使用
网络资源整理自用,非原创。
- 配置
//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 //数据库版本
targetGenDir '*******' //生成DaoMaster类文件夹
daoPackage '**********' //生成DaoMaster类包名
}
dependencies {
compile 'org.greenrobot:greendao:3.1.0'
}
- 表创建
@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 用于标识这是一个需要Greendao帮我们生成代码的bean
@Id 标明主键,括号里可以指定是否自增
@Property 用于设置属性在[数据库](http://lib.csdn.net/base/mysql)中的列名(默认不写就是保持一致)
@NotNull 非空
@Transient 标识这个字段是自定义的不会创建到数据库表里
@Unique 添加唯一约束
  make projeck后会自动添加seter,geter以及构造函数。并且会新加三个类:
- BookDao
- DaoMaster
- DaoSession
2. 封装
//网上找的封装
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中调用getInstance
DBManager.getInstance();
//可以再封装,调用api实现增删改查
DBManager.getInstance().getSession().getBookDao().queryBuilder().list();//查询book表中所有数据
5. 升级和迁移
  普通升级直接修改数据库版本号就可以了,但是默认实现会删除所有数据,重新创建数据库表格。所以需要自己实现升级。
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出来的,非原创。。。。。
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;
}
}
上边处理了数据库升级,数据迁移的问题。
在我自己的项目中还有一个问题是需要处理外部数据库,所以还需指定一个数据库路径。
public class GreenDaoContext extends ContextWrapper {
private String currentUserId = "greendao";//一般用来针对一个用户一个数据库,以免数据混乱问题
private Context mContext;
public GreenDaoContext() {
super(BaseApp.gContext);
this.mContext = BaseApp.gContext;
// this.currentUserId = "greendao";//初始化
}
/**
* 获得数据库路径,如果不存在,则创建对象
*
* @param dbName
*/
@Override
public File getDatabasePath(String dbName) {
String dbDir = "";//指定数据库路径
if (TextUtils.isEmpty(dbDir)){
Log.e("SD卡管理:", "SD卡不存在,请加载SD卡");
return null;
}
File baseFile = new File(dbDir);
// 目录不存在则自动创建目录
if (!baseFile.exists()){
baseFile.mkdirs();
}
StringBuffer buffer = new StringBuffer();
buffer.append(baseFile.getPath());
buffer.append(File.separator);
// buffer.append(currentUserId);
dbDir = buffer.toString();// 数据库所在目录
// buffer.append(File.separator);
// buffer.append(dbName+"_"+currentUserId);//也可以采用此种方式,将用户id与表名联系到一块命名
buffer.append(dbName);
String dbPath = buffer.toString();// 数据库路径
LogUtil.e(LogUtil.getLogTag()+dbPath);
// 判断目录是否存在,不存在则创建该目录
File dirFile = new File(dbDir);
if (!dirFile.exists()){
dirFile.mkdirs();
}
// 数据库文件是否创建成功
boolean isFileCreateSuccess = false;
// 判断文件是否存在,不存在则创建该文件
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
try {
LogUtil.e(LogUtil.getLogTag()+"创建db");
isFileCreateSuccess = dbFile.createNewFile();// 创建文件
} catch (IOException e) {
e.printStackTrace();
}
} else
isFileCreateSuccess = true;
// 返回数据库文件对象
if (isFileCreateSuccess)
return dbFile;
else
return super.getDatabasePath(dbName);
}
/**
* 重载这个方法,是用来打开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), factory);
return result;
}
/**
* Android 4.0会调用此方法获取数据库。
*
* @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;
}
}