GreenDao概述
如果Android项目中要使用GreenDAO框架,需要先创建一个Java项目用于生成实体类和DAO类,然后在Android项目中使用这些类,在此过程中分别需要对Android项目添加GreenDAO的核心包依赖和对Java项目添加generator包依赖,所以解析GreenDAO的源码需要解析两部分,而这里只解析GreenDAO核心包在Android项目中的工作原理,generator包中的原理很简单,总的来说有四个作用:就是用于生成实体类、DAO类、建立多表之间的关联以及配置实体类的接口和序列化功能
在Android项目中用到的最核心的四个类就是:DaoMaster、DaoSession、实体类、实体Dao类。
这四个核心类的功能体系如下图所示:
DaoMaster
GreenDao框架管理类,该类对数据库相关管理操作进行封装
我们知道在使用GreenDAO时候,我们的入口点就是通过DaoMaster的静态内部类DevOpenHelper来创建一个DevOpenHelper对象
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "students-db", null);
而DevOpenHelper对象又是什么呢?我们都知道在使用SQLite的时候,我们必须通过继承SQLiteOpenHelper类并且实现它内部的一些方法来创建数据库,而这里仅仅通过DevOpenHelper类就成功创建了一个文件名为”students-db”的数据表,那么内部又是怎么实现的呢?我们可以看看DaoMaster类的源码:
public class DaoMaster extends AbstractDaoMaster {
public static final int SCHEMA_VERSION = 1;
/** Creates underlying database table using DAOs. */
public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
StudentDao.createTable(db, ifNotExists);
}
/** Drops underlying database table using DAOs. */
public static void dropAllTables(SQLiteDatabase db, boolean ifExists) {
StudentDao.dropTable(db, ifExists);
}
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);
createAllTables(db, false);
}
}
/** WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@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);
}
}
public DaoMaster(SQLiteDatabase db) {
super(db, SCHEMA_VERSION);
registerDaoClass(StudentDao.class);
}
public DaoSession newSession() {
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
}
public DaoSession newSession(IdentityScopeType type) {
return new DaoSession(db, type, daoConfigMap);
}
}
从DaoMaster中我们可以发现,DaoMaster除了具有创建表和删除表的两个功能外,还有两个内部类,分别为OpenHelper和DevOpenHelper,OpenHelper继承于SQLiteOpenHelper用于创建所有的数据库表;DevOpenHelper继承于OpenHelper用于数据库升级,而重写的onCreate()
方法中调用了createAllTables(db,false);
方法来创建数据表,而createAllTables()
方法中是通过调用StudentDao静态方法来创建表的StudentDao.createTable(db, ifNotExists);
我们点进这个方法中去看个究竟
public static void createTable(SQLiteDatabase db, boolean ifNotExists) {
String constraint = ifNotExists? "IF NOT EXISTS ": "";
db.execSQL("CREATE TABLE " + constraint + "\"STUDENT\" (" + //
"\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
"\"NAME\" TEXT NOT NULL ," + // 1: name
"\"AGE\" INTEGER," + // 2: age
"\"IS_MAN\" INTEGER);"); // 3: is_man
}
发现它内部就是通过sql语句来创建表的,只不过GreenDAO帮我们封装好了,而且你会发现删除表其实也一样:
public static void dropTable(SQLiteDatabase db, boolean ifExists) {
String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"STUDENT\"";
db.execSQL(sql);
}
好了,现在我们知道了通过DevOpenHelper是怎么创建表的,而细心的同学会发现在DevOpenHelper类中实现了onUpgrade()
方法,就是更新数据库的方法,它在更新数据表的时候会把以前的数据表删除后再重新创建,所以这个你必须注意,当我们在利用GreenDAO更新数据表的时候,如果你想以前表中的数据保存下来的话,我们必须自己封装一个方法。
接下来就是newSession()
方法了,这个当然就是得到DaoSession实例了,关于DaoSession实例,GreenDAO官方建议不要重新创建新的实例,保持一个单例的引用即可。好了,DaoMaster源码看完了,接下来就是看它的父类AbstractDaoMaster
的源码了,它的源码如下:
public abstract class AbstractDaoMaster {
protected final SQLiteDatabase db;
protected final int schemaVersion;
protected final Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> daoConfigMap;
public AbstractDaoMaster(SQLiteDatabase db, int schemaVersion) {
this.db = db;
this.schemaVersion = schemaVersion;
daoConfigMap = new HashMap<Class<? extends AbstractDao<?, ?>>, DaoConfig>();
}
protected void registerDaoClass(Class<? extends AbstractDao<?, ?>> daoClass) {
DaoConfig daoConfig = new DaoConfig(db, daoClass);
daoConfigMap.put(daoClass, daoConfig);
}
public int getSchemaVersion() {
return schemaVersion;
}
/** Gets the SQLiteDatabase for custom database access. Not needed for greenDAO entities. */
public SQLiteDatabase getDatabase() {
return db;
}
public abstract AbstractDaoSession newSession();
public abstract AbstractDaoSession newSession(IdentityScopeType type);
}
看这个类的代码,其中最让我们受关注的无非就是这一行了
protected final Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> daoConfigMap;
这里定义了一个Map集合,Key是继承自AbstractDao类的字节码对象,Value则为DaoConfig对象。每个AbstractDao对应着一个DaoConfig,然后保存在Map< Class
protected void registerDaoClass(Class<? extends AbstractDao<?, ?>> daoClass) {
DaoConfig daoConfig = new DaoConfig(db, daoClass);
daoConfigMap.put(daoClass, daoConfig);
}
所以Map的功能现在很清楚了,就是为每一个EntityDao字节码对象建立与之对应的db数据库的映射关系,从而管理所有的EntityDao类。而这个方法在哪里调用了呢?我们回到DaoMaster的源码中,发现在DaoMaster类的构造方法中调用了,并且传入了Student.class
,所以我们在创建DaoMaster对象的时候也同时为EntityDao类和相应的数据库db建立好了关联。
DaoSession
从上面可知DaoSession对象是通过master.newSession();
创建的。DaoSession对象是连接GreenDao框架到SQLite数据库的纽带,通过该对象我们可以得到一个与数据库某个表相关的操作对象xxxDao。我们看看DaoSession源码,发现它也有一个抽象的父类AbstractDaoSession,我们来看看DaoSession的源码:
public class