本篇是greenDao的最后一篇,这一篇带大家看下greenDao的源码。

  • dao的初始化过程
    这一过程非常的复杂,容易绕晕,那么我就来带大家梳理一下。首先看看我们初始化dao的方法。
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this,"persons-db",null);        db = helper.getWritableDatabase();        Log.e("tag","this is db version ->"+db.getVersion());        // 该数据库连接属于DaoMaster,所以多个Session指的是想用的数据库连接        daoMaster = new DaoMaster(db);        daoSession =daoMaster.newSession();        return daoSession.getPersonDao();

我在这里返回的是PersionDao。首先看下helper的初始化 过程。

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

调用父类的构造方法。

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);        }    }

在父类中完成数据表的创建。

public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {        PersonDao.createTable(db, ifNotExists);        PeopleDao.createTable(db, ifNotExists);        IdCardDao.createTable(db, ifNotExists);        OrderDao.createTable(db, ifNotExists);        CourseDao.createTable(db, ifNotExists);    }
public static void createTable(SQLiteDatabase db, boolean ifNotExists) {        String constraint = ifNotExists? "IF NOT EXISTS ": "";        db.execSQL("CREATE TABLE " + constraint + "\"PERSON\" (" + //                "\"_id\" INTEGER PRIMARY KEY ," + // 0: id                "\"NAME\" TEXT NOT NULL ," + // 1: name                "\"AGE\" INTEGER NOT NULL ," + // 2: age                "\"CARD\" TEXT);"); // 3: card    }

这么一来,表的创建过程就理清楚了。接下来看DaoMaster的初始化。

public DaoMaster(SQLiteDatabase db) {        super(db, SCHEMA_VERSION);        registerDaoClass(PersonDao.class);        registerDaoClass(PeopleDao.class);        registerDaoClass(IdCardDao.class);        registerDaoClass(OrderDao.class);        registerDaoClass(CourseDao.class);    }

显示调用父类的构造方法,接着registDaoClass()

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);    }

看到,上面的一句很关键。new DaoConfig();

public DaoConfig(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>> daoClass) {        this.db = db;        try {            this.tablename = (String) daoClass.getField("TABLENAME").get(null);            Property[] properties = reflectProperties(daoClass);            this.properties = properties;            allColumns = new String[properties.length];            List<String> pkColumnList = new ArrayList<String>();            List<String> nonPkColumnList = new ArrayList<String>();            Property lastPkProperty = null;            for (int i = 0; i < properties.length; i++) {                Property property = properties[i];                String name = property.columnName;                allColumns[i] = name;                if (property.primaryKey) {                    pkColumnList.add(name);                    lastPkProperty = property;                } else {                    nonPkColumnList.add(name);                }            }            String[] nonPkColumnsArray = new String[nonPkColumnList.size()];            nonPkColumns = nonPkColumnList.toArray(nonPkColumnsArray);            String[] pkColumnsArray = new String[pkColumnList.size()];            pkColumns = pkColumnList.toArray(pkColumnsArray);            pkProperty = pkColumns.length == 1 ? lastPkProperty : null;            statements = new TableStatements(db, tablename, allColumns, pkColumns);            if (pkProperty != null) {                Class<?> type = pkProperty.type;                keyIsNumeric = type.equals(long.class) || type.equals(Long.class) || type.equals(int.class)                        || type.equals(Integer.class) || type.equals(short.class) || type.equals(Short.class)                        || type.equals(byte.class) || type.equals(Byte.class);            } else {                keyIsNumeric = false;            }        } catch (Exception e) {            throw new DaoException("Could not init DAOConfig", e);        }    }

这个方法就是完成DaoConfig的配置的,通过反射机制,获取到我们的Dao类,比如说PersonClass,具体的代码大家去看,就是通过反射,很好理解。注意statements是TableStatements类型的。

继续,newSession();

public DaoSession newSession() {        return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);    }
public DaoSession(SQLiteDatabase db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>            daoConfigMap) {        super(db);        personDaoConfig = daoConfigMap.get(PersonDao.class).clone();        personDaoConfig.initIdentityScope(type);        peopleDaoConfig = daoConfigMap.get(PeopleDao.class).clone();        peopleDaoConfig.initIdentityScope(type);        idCardDaoConfig = daoConfigMap.get(IdCardDao.class).clone();        idCardDaoConfig.initIdentityScope(type);        orderDaoConfig = daoConfigMap.get(OrderDao.class).clone();        orderDaoConfig.initIdentityScope(type);        courseDaoConfig = daoConfigMap.get(CourseDao.class).clone();        courseDaoConfig.initIdentityScope(type);        personDao = new PersonDao(personDaoConfig, this);        peopleDao = new PeopleDao(peopleDaoConfig, this);        idCardDao = new IdCardDao(idCardDaoConfig, this);        orderDao = new OrderDao(orderDaoConfig, this);        courseDao = new CourseDao(courseDaoConfig, this);        registerDao(Person.class, personDao);        registerDao(People.class, peopleDao);        registerDao(IdCard.class, idCardDao);        registerDao(Order.class, orderDao);        registerDao(Course.class, courseDao);    }
public void initIdentityScope(IdentityScopeType type) {        if (type == IdentityScopeType.None) {            identityScope = null;        } else if (type == IdentityScopeType.Session) {            if (keyIsNumeric) {                identityScope = new IdentityScopeLong();            } else {                identityScope = new IdentityScopeObject();            }        } else {            throw new IllegalArgumentException("Unsupported type: " + type);        }    }

这个函数就是判断,类型范围的。一般我们不需要管。看到在DaoSession的构造函数中,根据在DaoMaster初始化的config,经过范围类型判断,在DaoSession中也初始化了。至此,初始化过程完毕。

  • CURD过程 我们以insert为例
dao.insert(person);

dao对象是我们初始化后得到的,person是一个Person实体对象。

public long insert(T entity) {        return executeInsert(entity, statements.getInsertStatement());    }

上面的一段代码是AbstractDao类,这是一个抽象类,我们的Persondao就是继承的他。

statements.getInsertStatement()

通过statments对象实例获取SQLiteStatement对象,在(TableStatements类中)

public SQLiteStatement getInsertStatement() {        if (insertStatement == null) {            String sql = SqlUtils.createSqlInsert("INSERT INTO ", tablename, allColumns);            insertStatement = db.compileStatement(sql);        }        return insertStatement;    }

这样我们就获取到了一个SQLiteStatement对象。继续,看插入数据的过程。

private long executeInsert(T entity, SQLiteStatement stmt) {        long rowId;        if (db.isDbLockedByCurrentThread()) {            synchronized (stmt) {                bindValues(stmt, entity);                rowId = stmt.executeInsert();            }        } else {            // Do TX to acquire a connection before locking the stmt to avoid deadlocks            db.beginTransaction();            try {                synchronized (stmt) {                    bindValues(stmt, entity);                    rowId = stmt.executeInsert();                }                db.setTransactionSuccessful();            } finally {                db.endTransaction();            }        }        updateKeyAfterInsertAndAttach(entity, rowId, true);        return rowId;    }

看到上面会判断是否在当前线程,不在的话会开启事务。总之,还是很安全的。就这么多吧,更多的源码还是大家自己看吧。真的感觉这个牛,坐等更新+上数据库更新

更多相关文章

  1. Bundle携带对象来传输对象
  2. [置顶] android6.0源码分析之Activity启动过程
  3. android之微信分享图片
  4. 【Android每日一讲】2012.10.23 不同Activity之间的数据传递 --
  5. Android(安卓)学习系列 - Application
  6. android资源访问机制
  7. 菜鸟在android中密码框的纠结过程
  8. Java/Android引用类型及其使用全面分析
  9. Android(安卓)网络连接 打开 Url下载 信息

随机推荐

  1. boost项目复盘(二)
  2. 初试kafka监控及管理利器之kafka-eagle
  3. ansible安装碰到的问题
  4. kubernetes中启动探针startupProbe
  5. ansible初入
  6. 《Golang从入门到跑路》之指针
  7. idea2020.3.2 没有javaweb选项
  8. 《Golang从入门到跑路》之map的初识
  9. 一次
  10. SQL中的ALL、ANY和SOME的用法介绍