前言
今天我们来分析下GreenDao, 进而学习开源库中涉及到的一些思想.
简单的实例
1.导入相应的库
// 项目 build.gradle file:
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1'
}
}
// APP build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'
dependencies {
compile 'org.greenrobot:greendao:3.2.0'
}
2.创建一个StudentBean类(greenDao会自动将该类生成对应的表)
@Entity
public class StudentBean {
@Id
private Long id;
@Property(nameInDb = "NAME")
private String name;
}
3.选择 ReBuild project, 上一步创建的StudentBean类会自动被添加setter getter方法.
@Entity
public class StudentBean {
@Id
private Long id;
@Property(nameInDb = "NAME")
private String name;
@Generated(hash = 636788913)
public StudentBean(Long id, String name) {
this.id = id;
this.name = name;
}
@Generated(hash = 2097171990)
public StudentBean() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
测试insert操作 (下面用到的DaoMaster DaoSession StudentBeanDao类都是上一步在build目录下生成的)
DaoMaster.DevOpenHelper devOpenHelper = new
DaoMaster.DevOpenHelper(getApplicationContext(), "student.db", null);
DaoMaster daoMaster = new DaoMaster(devOpenHelper.getWritableDb());
DaoSession mDaoSession = daoMaster.newSession();
StudentBeanDao mBeanDao = mDaoSession.getStudentBeanDao();
StudentBean studentMsgBean = new StudentBean();
studentMsgBean.setName("zone");
mBeanDao.insert(studentMsgBean);
根据实例进行源码分析
创建DaoMaster的内部类DevOpenHelper对象
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(getApplicationContext(), "student.db", null);
由1-21行, DevOpenHelper间接继承SQLiteOpenHelper类, 其中”student.db”是用户自定义的数据库名称.
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
}
public static abstract class OpenHelper extends DatabaseOpenHelper {
public OpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory, SCHEMA_VERSION);
}
}
public abstract class DatabaseOpenHelper extends SQLiteOpenHelper {
public DatabaseOpenHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
this.loadSQLCipherNativeLibs = true;
this.context = context;
this.name = name;
this.version = version;
}
}
创建DaoMaster对象
DaoMaster daoMaster = new DaoMaster(devOpenHelper.getWritableDb());
首先通过上面创建的devOpenHelper对象的getWritableDb()方法得到Database对象, 由3-5行, 该方法首先会通过this.getWritableDatabase()得到SQLiteDatabase对象, 由7-9行, getWritableDb()方法最终会得到StandardDatabase对象. 我们看到StandardDatabase类, 有代理模式的影子, 后期调用standarDatabase对象处理数据库,实际上是代理类中的对象SQLiteDatabase处理.我们得到Database对象后, 由18-21行, DaoMaster构造函数会先调用父类的构造函数, 接着调用registerDaoClass(StudentBeanDao.class)该方法也是DaoMaster的父类AbstractDaoMaster实现的.由35-38行, 该方法先创建DaoConfig对象(通过传入的dao类通过反射得到一些属性),接着保存到缓存集合后期复用.
DatabaseOpenHelper类下:
public Database getWritableDb() {
return this.wrap(this.getWritableDatabase());
}
protected Database wrap(SQLiteDatabase sqLiteDatabase) {
return new StandardDatabase(sqLiteDatabase);
}
public class StandardDatabase implements Database {
private final SQLiteDatabase delegate;
public StandardDatabase(SQLiteDatabase delegate) {
this.delegate = delegate;
}
}
public class DaoMaster extends AbstractDaoMaster {
public DaoMaster(Database db) {
super(db, SCHEMA_VERSION);
registerDaoClass(StudentBeanDao.class);
}
}
public abstract class AbstractDaoMaster {
protected final Database db;
protected final int schemaVersion;
protected final Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> daoConfigMap;
public AbstractDaoMaster(Database db, int schemaVersion) {
this.db = db;
this.schemaVersion = schemaVersion;
this.daoConfigMap = new HashMap();
}
}
protected void registerDaoClass(Class<? extends AbstractDao<?, ?>> daoClass) {
DaoConfig daoConfig = new DaoConfig(this.db, daoClass);
this.daoConfigMap.put(daoClass, daoConfig);
}
生成DaoSession对象
由2行, 通过传入刚刚生成的daoConfigMap和一些其他信息调用DaoSession构造函数生成DaoSession对象; 由9-16行,我们看到DaoSession构造函数中, 首先通过daoConfigMap集合得到对应的DaoConfig对象, 然后clone一份对象, 接着通过刚刚得到DaoConfig和daoSession创建StudentBeanDao对象, 最后通过registerDao(StudentBean.class, studentBeanDao)方法绑定两者的关系(通过map集合).
DaoSession mDaoSession = daoMaster.newSession();
public DaoSession newSession() {
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
}
public class DaoSession extends AbstractDaoSession {
private final DaoConfig studentBeanDaoConfig;
private final StudentBeanDao studentBeanDao;
public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
daoConfigMap) {
super(db);
studentBeanDaoConfig = daoConfigMap.get(StudentBeanDao.class).clone();
studentBeanDaoConfig.initIdentityScope(type);
studentBeanDao = new StudentBeanDao(studentBeanDaoConfig, this);
registerDao(StudentBean.class, studentBeanDao);
}
}
public class AbstractDaoSession {
private final Map<Class<?>, AbstractDao<?, ?>> entityToDao;
protected <T> void registerDao(Class<T> entityClass, AbstractDao<T, ?> dao) {
this.entityToDao.put(entityClass, dao);
}
}
通过insert操作, 分析源码
mBeanDao.insert(studentMsgBean); (mBeanDao上一步分析的时创建的studentBeanDao对象), 首先通过this.statements.getInsertStatement()得到DatabaseStatement对象,然后执行executeInsert(...)方法(由父类AbstractDao实现,由29行,通过SQLiteDatabase的代理对象StandardDatabase调用beginTransaction()开启事务,具体的代码看43-48行;接着通过insertInsideTx(entity, stmt)方法给stmt对象绑定一些参数,最后通过stmt.executeInsert()方法完成插入;具体的代码在50-61行,其中第54行是具体的子类实现的比如这里就是StudentBeanDao实现了该方法在方法里对stmt(SQLiteStatement)对象绑定一些entity对象的属性值。insert结束了,同样通过代理对象间接调用SQLiteDatabase对象来关闭事务。
public long insert(T entity) {
return this.executeInsert(entity, this.statements.getInsertStatement(), true);
}
public class TableStatements {
public DatabaseStatement getInsertStatement() {
if(this.insertStatement == null) {
String sql = SqlUtils.createSqlInsert("INSERT INTO ",
this.tablename, this.allColumns);
DatabaseStatement newInsertStatement = this.db.compileStatement(sql);
synchronized(this) {
if(this.insertStatement == null) {
this.insertStatement = newInsertStatement;
}
}
if(this.insertStatement != newInsertStatement) {
newInsertStatement.close();
}
}
return this.insertStatement;
}
}
private long executeInsert(T entity, DatabaseStatement stmt, boolean setKeyAndAttach) {
long rowId;
if(this.db.isDbLockedByCurrentThread()) {
rowId = this.insertInsideTx(entity, stmt);
} else {
this.db.beginTransaction();
try {
rowId = this.insertInsideTx(entity, stmt);
this.db.setTransactionSuccessful();
} finally {
this.db.endTransaction();
}
}
if(setKeyAndAttach) {
this.updateKeyAfterInsertAndAttach(entity, rowId, true);
}
return rowId;
}
public class StandardDatabase implements Database {
private final SQLiteDatabase delegate;
public void beginTransaction() {
this.delegate.beginTransaction();
}
}
private long insertInsideTx(T entity, DatabaseStatement stmt) {
synchronized(stmt) {
if(this.isStandardSQLite) {
SQLiteStatement rawStmt = (SQLiteStatement)stmt.getRawStatement();
this.bindValues(rawStmt, entity);
return rawStmt.executeInsert();
} else {
this.bindValues(stmt, entity);
return stmt.executeInsert();
}
}
}
总结
整个流程还是蛮清晰的。通过一些类来代理SQLite中的SQLiteDatabase SQLiteStatement对象来进行数据库的操作。GreenDao以对象关系映射(ORM)对原生的SQLite数据库高度封装。我们使用该库比直接使用SQLite数据库更方便。