GreenDao 源码剖析

上一篇文章,我们有讲解到GreenDao的基本应用,本文开始深了解GreenDao的源码。当我们编写好了Entity类之后,会自动生成DaoMaster、DaoSession、Entity Dao这三个核心类。
三者之间的关系如下:

//生成数据库文件,名为students-db
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "xxx.db", null);
SQLiteDatabase db = helper.getWritableDatabase();
//建立特定模式下的所有的DAO对象和数据库db对象的映射
DaoMaster master = new DaoMaster(db);
//管理特定模式下的所有DAO对象,并提供一些通用的CRUD持久化方法
DaoSession session = master.newSession();
//得到指定的StudentDao对象
StudentDao dao = session.getStudentDao();
dao.insert(entity);
//...
1. DaoMaster
public class DaoMaster extends AbstractDaoMaster {
    public static final int SCHEMA_VERSION = 1;
    // 创建数据库
    public static void createAllTables(Database db, boolean ifNotExists) {
        UserDao.createTable(db, ifNotExists);
    }
    // 删除数据库
    public static void dropAllTables(Database db, boolean ifExists) {
        UserDao.dropTable(db, ifExists);
    }
    // 获取DaoSession对象
    public static DaoSession newDevSession(Context context, String name) {
        Database db = new DevOpenHelper(context, name).getWritableDb();
        DaoMaster daoMaster = new DaoMaster(db);
        return daoMaster.newSession();
    }

    public DaoMaster(SQLiteDatabase db) {
        this(new StandardDatabase(db));
    }

    public DaoMaster(Database db) {
        super(db, SCHEMA_VERSION);
        //注意此处传入UserDao对象
        registerDaoClass(UserDao.class);
    }

    public DaoSession newSession() {
        return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
    }

    public DaoSession newSession(IdentityScopeType type) {
        return new DaoSession(db, type, daoConfigMap);
    }
    public static abstract class OpenHelper extends DatabaseOpenHelper {
        public OpenHelper(Context context, String name) {
            super(context, name, SCHEMA_VERSION);
        }

        public OpenHelper(Context context, String name, CursorFactory factory)             
        {
            super(context, name, factory, SCHEMA_VERSION);
        }

        @Override
        public void onCreate(Database db) {
            Log.i("greenDAO", "Creating tables for schema version " +
                   SCHEMA_VERSION);
            createAllTables(db, false);
        }
    }

    public static class DevOpenHelper extends OpenHelper {
        public DevOpenHelper(Context context, String name) {
            super(context, name);
        }

        public DevOpenHelper(Context context, String name, 
                             CursorFactory factory) 
        {
            super(context, name, factory);
        }
         //数据库升级,会删除所有的表格,然后再创建数据库
        @Override
        public void onUpgrade(Database db, int oldVersion, int newVersion) {
            Log.i("greenDAO", "Upgrading schema from version " + 
                 oldVersion + " to " + newVersion + " by dropping all tables");
            dropAllTables(db, true);
            onCreate(db);
        }
    }
}

DaoMaster类里面有两个静态内部类OpenHelper继承了DatabaseOpenHelper类,而DatabaseOpenHelper类又继承了SQLiteOpenHelper类。DevOpenHelper类则继承了OpenHelper。DevOpenHelper类的构造函数里面参数name代表类数据库名称。onCreate函数会调用createAllTables函数,onUpgrade函数会调用dropAllTables,再重新创建数据库。

AbstractDaoMaster.java

public abstract class AbstractDaoMaster {
    protected final SQLiteDatabase db;
    protected final int schemaVersion;
    // EntityDao类为Key
    protected final Map>, DaoConfig> daoConfigMap;

    public AbstractDaoMaster(SQLiteDatabase db, int schemaVersion) {
        this.db = db;
        this.schemaVersion = schemaVersion;

        daoConfigMap = new HashMap>, DaoConfig>();
    }

    // 初始化daoConfigMap对象
    protected void registerDaoClass(Class> 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);
}

daoConfigMap其实是存储了EntityDao与db数据库之前的映射关系。

2. DaoSession
public class DaoSession extends AbstractDaoSession {

    private final DaoConfig studentDaoConfig;
    private final StudentDao studentDao;

    public DaoSession(SQLiteDatabase db, IdentityScopeType type, 
                      Map>, DaoConfig>
                      daoConfigMap) {
        super(db);

        studentDaoConfig = daoConfigMap.get(StudentDao.class).clone();
        studentDaoConfig.initIdentityScope(type);

        studentDao = new StudentDao(studentDaoConfig, this);
        registerDao(Student.class, studentDao);
    }

    public void clear() {
        studentDaoConfig.getIdentityScope().clear();
    }

    public StudentDao getStudentDao() {
        return studentDao;
    }
}

AbstractDaoSession.java

public class AbstractDaoSession {
    private final SQLiteDatabase db;
    private final Map, AbstractDao> entityToDao;

    public AbstractDaoSession(SQLiteDatabase db) {
        this.db = db;
        this.entityToDao = new HashMap, AbstractDao>();
    }

    protected  void registerDao(Class entityClass, AbstractDao dao) {
        entityToDao.put(entityClass, dao);
    }

    /** Convenient call for {@link AbstractDao#insert(Object)}. */
    public  long insert(T entity) {
        @SuppressWarnings("unchecked")
        AbstractDao dao = (AbstractDao) getDao(entity.getClass());
        return dao.insert(entity);
    }

    /** Convenient call for {@link AbstractDao#insertOrReplace(Object)}. */
    public  long insertOrReplace(T entity) {
        @SuppressWarnings("unchecked")
        AbstractDao dao = (AbstractDao) getDao(entity.getClass());
        return dao.insertOrReplace(entity);
    }

    /** Convenient call for {@link AbstractDao#refresh(Object)}. */
    public  void refresh(T entity) {
        @SuppressWarnings("unchecked")
        AbstractDao dao = (AbstractDao) getDao(entity.getClass());
        dao.refresh(entity);
    }

    /** Convenient call for {@link AbstractDao#update(Object)}. */
    public  void update(T entity) {
        @SuppressWarnings("unchecked")
        AbstractDao dao = (AbstractDao) getDao(entity.getClass());
        dao.update(entity);
    }
//...
    /** Convenient call for {@link AbstractDao#delete(Object)}. */
    public  void delete(T entity) {
        @SuppressWarnings("unchecked")
        AbstractDao dao = (AbstractDao) getDao(entity.getClass());
        dao.delete(entity);
    }

    /** Convenient call for {@link AbstractDao#deleteAll()}. */
    public  void deleteAll(Class entityClass) {
        @SuppressWarnings("unchecked")
        AbstractDao dao = (AbstractDao) getDao(entityClass);
        dao.deleteAll();
    }

    /** Convenient call for {@link AbstractDao#load(Object)}. */
    public  T load(Class entityClass, K key) {
        @SuppressWarnings("unchecked")
        AbstractDao dao = (AbstractDao) getDao(entityClass);
        return dao.load(key);
    }

    /** Gets the SQLiteDatabase for custom database access. Not needed for greenDAO entities. */
    public SQLiteDatabase getDatabase() {
        return db;
    }

    /**
     * Creates a new {@link AsyncSession} to issue asynchronous entity operations. See {@link AsyncSession} for details.
     */
    public AsyncSession startAsyncSession() {
        return new AsyncSession(this);
    }
}
3. Dao
public class StudentDao extends AbstractDao {

    public static final String TABLENAME = "STUDENT";

    /**
     * Properties of entity Student.
* Can be used for QueryBuilder and for referencing column names. */ public static class Properties { public final static Property Id = new Property(0, Long.class, "id", true, "_id"); public final static Property Name = new Property(1, String.class, "name", false, "NAME"); public final static Property Age = new Property(2, Integer.class, "age", false, "AGE"); public final static Property Is_man = new Property(3, Boolean.class, "is_man", false, "IS_MAN"); }; public StudentDao(DaoConfig config) { super(config); } public StudentDao(DaoConfig config, DaoSession daoSession) { super(config, daoSession); } /** Creates the underlying database table. */ 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 } /** Drops the underlying database table. */ public static void dropTable(SQLiteDatabase db, boolean ifExists) { String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"STUDENT\""; db.execSQL(sql); } /** @inheritdoc */ @Override protected void bindValues(SQLiteStatement stmt, Student entity) { stmt.clearBindings(); Long id = entity.getId(); if (id != null) { stmt.bindLong(1, id); } stmt.bindString(2, entity.getName()); Integer age = entity.getAge(); if (age != null) { stmt.bindLong(3, age); } Boolean is_man = entity.getIs_man(); if (is_man != null) { stmt.bindLong(4, is_man ? 1L: 0L); } } /** @inheritdoc */ @Override public Long readKey(Cursor cursor, int offset) { return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); } /** @inheritdoc */ @Override public Student readEntity(Cursor cursor, int offset) { Student entity = new Student( // cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id cursor.getString(offset + 1), // name cursor.isNull(offset + 2) ? null : cursor.getInt(offset + 2), // age cursor.isNull(offset + 3) ? null : cursor.getShort(offset + 3) != 0 // is_man ); return entity; } /** @inheritdoc */ @Override public void readEntity(Cursor cursor, Student entity, int offset) { entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); entity.setName(cursor.getString(offset + 1)); entity.setAge(cursor.isNull(offset + 2) ? null : cursor.getInt(offset + 2)); entity.setIs_man(cursor.isNull(offset + 3) ? null : cursor.getShort(offset + 3) != 0); } /** @inheritdoc */ @Override protected Long updateKeyAfterInsert(Student entity, long rowId) { entity.setId(rowId); return rowId; } /** @inheritdoc */ @Override public Long getKey(Student entity) { if(entity != null) { return entity.getId(); } else { return null; } } /** @inheritdoc */ @Override protected boolean isEntityUpdateable() { return true; } }

其中bindValues()这个方法就是绑定实体的属性名和表中的字段名的,还有比较重要的就是这个静态内部类Properties,该类中分别对每一个实体类的属性都创建了一个Property对象,而我们可以根据Property来得到这个属性对应表中的列名、是否为主键等值,其中还包括了一些方法,比如判断表中某个字段的值是否和value相等:eq(Object value);

Property源码如下:

public class Property {
    public final int ordinal;
    public final Class type;
    public final String name;
    public final boolean primaryKey;
    public final String columnName;

    public Property(int ordinal, Class type, String name, 
                     boolean primaryKey, String columnName) {
        this.ordinal = ordinal;
        this.type = type;
        this.name = name;
        this.primaryKey = primaryKey;
        this.columnName = columnName;
    }

    /** Creates an "equal ('=')" condition  for this property. */
    public WhereCondition eq(Object value) {
        return new PropertyCondition(this, "=?", value);
    }

    /** Creates an "not equal ('<>')" condition  for this property. */
    public WhereCondition notEq(Object value) {
        return new PropertyCondition(this, "<>?", value);
    }

    /** Creates an "LIKE" condition  for this property. */
    public WhereCondition like(String value) {
        return new PropertyCondition(this, " LIKE ?", value);
    }

    /** Creates an "BETWEEN ... AND ..." condition  for this property. */
    public WhereCondition between(Object value1, Object value2) {
        Object[] values = { value1, value2 };
        return new PropertyCondition(this, " BETWEEN ? AND ?", values);
    }

    /** Creates an "IN (..., ..., ...)" condition  for this property. */
    public WhereCondition in(Object... inValues) {
        StringBuilder condition = new StringBuilder(" IN (");
        SqlUtils.appendPlaceholders(condition, inValues.length).append(')');
        return new PropertyCondition(this, condition.toString(), inValues);
    }

    /** Creates an "IN (..., ..., ...)" condition  for this property. */
    public WhereCondition in(Collection inValues) {
        return in(inValues.toArray());
    }

    /** Creates an "NOT IN (..., ..., ...)" condition  for this property. */
    public WhereCondition notIn(Object... notInValues) {
        StringBuilder condition = new StringBuilder(" NOT IN (");
        SqlUtils.appendPlaceholders(condition, notInValues.length).append(')');
        return new PropertyCondition(this, condition.toString(), notInValues);
    }

    /** Creates an "NOT IN (..., ..., ...)" condition  for this property. */
    public WhereCondition notIn(Collection notInValues) {
        return notIn(notInValues.toArray());
    }

    /** Creates an "greater than ('>')" condition  for this property. */
    public WhereCondition gt(Object value) {
        return new PropertyCondition(this, ">?", value);
    }

    /** Creates an "less than ('<')" condition  for this property. */
    public WhereCondition lt(Object value) {
        return new PropertyCondition(this, "=')" condition  for this property. */
    public WhereCondition ge(Object value) {
        return new PropertyCondition(this, ">=?", value);
    }

    /** Creates an "less or equal ('<=')" condition  for this property. */
    public WhereCondition le(Object value) {
        return new PropertyCondition(this, "<=?", value);
    }

    /** Creates an "IS NULL" condition  for this property. */
    public WhereCondition isNull() {
        return new PropertyCondition(this, " IS NULL");
    }

    /** Creates an "IS NOT NULL" condition  for this property. */
    public WhereCondition isNotNull() {
        return new PropertyCondition(this, " IS NOT NULL");
    }
}

更多内容

1. GreenDao源码分析及使用GreenDao实现静态数据缓存
2. Android数据存储之GreenDao 3.0 详解
3. Android | 分析greenDAO 3.2实现原理
4. ORM对象关系映射之GreenDAO源码解析

你可能感兴趣的:(GreenDao 源码剖析)