GreenDao遇到的一些坑

注:使用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中進行的,那么多線程操作時就可能會存在內存泄露的可能性。現在還沒有好的解決方法

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容