greenDao源码分析


前言

今天我们来分析下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数据库更方便。

实例代码地址

相关文章