GreenDao3.0系列文章:
GreenDao3.0 源碼分析-DaoMaster和DaoSeesion
AbstractDaoMaster
從圖中我們知道,DaoMaster和AbstractDaoMaster是父子類的關(guān)系,我們先看AbstractDaoMaster:
從上面類圖中,我們知道daoMaster維護(hù)一個(gè)daoConfigMap以Dao.class為key維護(hù)一個(gè)映射關(guān)系,而且通過(guò)調(diào)用
我們可以知道 AbstractDaoMaster的功能主要職責(zé)之一是創(chuàng)建注冊(cè)DaoConfig,并且維護(hù)他和dao之間的關(guān)系。
實(shí)現(xiàn)類DaoMaster的功能
功能一:創(chuàng)建所有表和刪除所有表
通過(guò)調(diào)用XXXDAO的靜態(tài)方法來(lái)進(jìn)行建表和刪表。
功能二:創(chuàng)建Session會(huì)話
public DaoSession newSession() {
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
}
public DaoSession newSession(IdentityScopeType type) {
return new DaoSession(db, type, daoConfigMap);
}
兩個(gè)創(chuàng)建的默認(rèn)數(shù)據(jù)緩存的類型,一個(gè)是隨我們定義的類型,IdentityScopeType定義了兩個(gè)類型,后面再說(shuō)。
功能三:注冊(cè)Config:
public DaoMaster(Database db) {
super(db, SCHEMA_VERSION);
registerDaoClass(NoteDao.class);
}
創(chuàng)建DaoMaster對(duì)象的時(shí)候以 Class<?> 來(lái)作為key,對(duì)DaoConfig進(jìn)行配置緩存綁定。
功能四:定義內(nèi)部類OpenHelper和DevOpenHelper。
Dao配置類DaoConfig
源碼對(duì)DaoConfig是這樣評(píng)價(jià)的:在GreenDao內(nèi)部使用,通過(guò)AbstractDaoMaster創(chuàng)建和持有其對(duì)象,存儲(chǔ)一些DAO實(shí)體所必須的數(shù)據(jù)。這個(gè)類實(shí)例能通過(guò)以Dao class為Key ,使用map維護(hù),通過(guò)key取出必要的信息。
也就是說(shuō),DaoConfig就是用來(lái)存儲(chǔ)dao,必要的一些數(shù)據(jù)的。
DaoConfig,維護(hù)了以下的字段:
上圖源碼可知,DaoConfig 維護(hù)了數(shù)據(jù)庫(kù)對(duì)象、數(shù)據(jù)庫(kù)名稱、Dao實(shí)體類表所有的屬性對(duì)應(yīng)關(guān)系等,并且這些字段都是在這個(gè)類進(jìn)行初始化的,核心功能有兩個(gè)。
根據(jù)xxxDao.class反射獲得屬性對(duì)象:
private static Property[] reflectProperties(Class<? extends AbstractDao<?, ?>> daoClass)
throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
Class<?> propertiesClass = Class.forName(daoClass.getName() + "$Properties");
Field[] fields = propertiesClass.getDeclaredFields();
ArrayList<Property> propertyList = new ArrayList<Property>();
//根據(jù)反射的字段 拿出靜態(tài)和公開(kāi)的屬性對(duì)象
final int modifierMask = Modifier.STATIC | Modifier.PUBLIC;
for (Field field : fields) {
//有些工具可能會(huì)引入其他字段,可以忽略它們
if ((field.getModifiers() & modifierMask) == modifierMask) {
Object fieldValue = field.get(null);
if (fieldValue instanceof Property) {
propertyList.add((Property) fieldValue);
}
}
}
//列表轉(zhuǎn)成數(shù)組,并通過(guò)序號(hào)進(jìn)行排序
Property[] properties = new Property[propertyList.size()];
for (Property property : propertyList) {
if (properties[property.ordinal] != null) {
throw new DaoException("Duplicate property ordinals");
}
properties[property.ordinal] = property;
}
return properties;
}</pre>
初始化緩存的策略
public enum IdentityScopeType {
Session, None
}
數(shù)據(jù)庫(kù)緩存的種類有兩種。Session,就是使用內(nèi)存緩存,None就是不使用內(nèi)存緩存。
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);
}
}
可以看到,當(dāng)我們創(chuàng)建Dao之前會(huì)調(diào)用這個(gè)方法,就說(shuō)明,如果type==IdentityScopeType.None沒(méi)有內(nèi)存緩存,反之會(huì)根據(jù)主鍵的類型,賦予內(nèi)存緩存的管理對(duì)象。
還有其他功能就是對(duì)TableStatements初始化,判斷主鍵是否是數(shù)字類型,分揀主鍵的數(shù)據(jù)和非主鍵的數(shù)組,記錄所有屬性行等大家可以看源碼,都比較簡(jiǎn)單。
Property、TableStatements是兩個(gè)非常重要的對(duì)象,留待后面我們?cè)僦v。
AbstractDaoSession
AbstractDaoSession維護(hù)是的Dao.calss對(duì)應(yīng)AbstractDao的關(guān)系,AbstractDao是所有實(shí)體Dao對(duì)象的父類,AbstractDaoSession里面就是實(shí)現(xiàn)一個(gè)從映射表中取出AbstractDao對(duì)象來(lái)進(jìn)行增刪改查的操作,也提供了runInTx(Runnable runnable)在事務(wù)中做任務(wù)不需要返回結(jié)果,和callInTx(Callable<V> callable)在事務(wù)中做任務(wù)并且等待結(jié)果等一些方法。
注:一些關(guān)于Rx和異步的操作留待后面統(tǒng)一再說(shuō)。
DaoSession
DaoSession是一個(gè)Dao會(huì)話,首先我們看構(gòu)造方法中的初始化
public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
daoConfigMap) {
super(db);
//根據(jù)Class<?>取出配置信息
noteDaoConfig = daoConfigMap.get(NoteDao.class).clone();
//根據(jù)Session的緩存類型初始化定制的緩存范圍
noteDaoConfig.initIdentityScope(type);
//根據(jù)配置初始化得到一個(gè)NoteDao實(shí)體
noteDao = new NoteDao(noteDaoConfig, this);
//注冊(cè)到映射表中
registerDao(Note.class, noteDao);
}
由注釋可知,DaoSession會(huì)創(chuàng)建我們需要的Dao對(duì)象并注冊(cè)到映射表中管理起來(lái)。
每個(gè)Dao還會(huì)生成這樣的格式的語(yǔ)句,所以我們可以根據(jù)Session對(duì)象直接獲取到XXDao:
public XXDao getxxDao() {
return xxDao;
}
還有一個(gè)清除所有內(nèi)存緩存的方法:
public void clear() {
noteDaoConfig.clearIdentityScope();
}