本篇是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;
}
~~~
看到上面會判斷是否在當前線程,不在的話會開啟事務。總之,還是很安全的。就這么多吧,更多的源碼還是大家自己看吧。真的感覺這個牛,坐等更新+上數據庫更新
- 前言
- Android四大圖片緩存框架之-Fresco(一)
- Android四大圖片緩存框架之-Fresco之initialize(二)
- Android 四大緩存框架之-Universal-Image-Loader
- Android四大圖片緩存框架之-Picasso和Glide
- Android ORM數據庫框架之-greenDao(一)
- Android ORM數據庫框架之-greenDao(二)
- Android ORM數據庫框架之-greenDao(三)
- Android ORM數據庫框架之-greenDao(四)
- Android 網絡開源庫之-retrofit
- RxJava的簡單學習(學習自扔物線)
- Android ORM框架之-ActiveAndroid的簡單分析