注:使用sdk版本為3.2.2
1. model的主鍵如果是數字類型,必須使用封裝類型
greendao 查詢方法 XXXDao
的生成是使用greendao-generator
中的dao.ftl
為模板生成的
@Override
public boolean hasKey(${entity.className} entity) {
<#if entity.pkProperty??>
<#if entity.pkProperty.notNull>
throw new UnsupportedOperationException("Unsupported for entities with a non-null key");
<#else>
<#if entity.protobuf>
return entity.has${entity.pkProperty.propertyName?cap_first}();
<#else>
return entity.get${entity.pkProperty.propertyName?cap_first}() != null;
</#if>
</#if>
<#else>
// TODO 使用 notNull的判斷會直接判斷 xxx != null, 數字類型生成模板就是錯誤的
return false;
</#if>
}
2. AbstractDao.save() 使用范圍
- pk為自增狀態下不設置 pk的保存
- 當前model已存數據庫,需要更新
public void save(T entity) {
if (hasKey(entity)) {
update(entity);
} else {
insert(entity);
}
}
3. AbstractDao的緩存機制
AbstractDao除了使用方便外,還構建了自己的緩存機制
public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
daoConfigMap)
//IdentityScopeType Session, None
//DaoConfig
@SuppressWarnings("rawtypes")
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);
}
}
//AbstractDao
public T load(K key) {
assertSinglePk();
if (key == null) {
return null;
}
if (identityScope != null) {
T entity = identityScope.get(key);
//獲取緩存中entity
if (entity != null) {
return entity;
}
}
String sql = statements.getSelectByKey();
String[] keyArray = new String[]{key.toString()};
Cursor cursor = db.rawQuery(sql, keyArray);
return loadUniqueAndCloseCursor(cursor);
}
/** Internal use only. Considers identity scope. */
final protected T loadCurrent(Cursor cursor, int offset, boolean lock) {
if (identityScopeLong != null) {
if (offset != 0) {
// Occurs with deep loads (left outer joins)
if (cursor.isNull(pkOrdinal + offset)) {
return null;
}
}
long key = cursor.getLong(pkOrdinal + offset);
T entity = lock ? identityScopeLong.get2(key) : identityScopeLong.get2NoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(entity);
if (lock) {
identityScopeLong.put2(key, entity);
} else {
identityScopeLong.put2NoLock(key, entity);
}
return entity;
}
} else if (identityScope != null) {
K key = readKey(cursor, offset);
if (offset != 0 && key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
T entity = lock ? identityScope.get(key) : identityScope.getNoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(key, entity, lock);
return entity;
}
} else {
// Check offset, assume a value !=0 indicating a potential outer join, so check PK
if (offset != 0) {
K key = readKey(cursor, offset);
if (key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
}
T entity = readEntity(cursor, offset);
attachEntity(entity);
return entity;
}
}
//AbstractDao中只要調用這兩個方法,就會把查詢結果加入緩存中
//如果同時對獲取到的結果進行修改,緩存中的model就會相應變化
//AbstractDao.queryRaw()不涉及緩存, queryBuilder方法會使用緩存數據
4. 執行SQL語句無效
5. Cursor的內存泄露
GreenDao封裝好了查詢,cursor的生成與關閉都是在 AbstractDao中進行的,那么多線程操作時就可能會存在內存泄露的可能性。現在還沒有好的解決方法