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;


<#else>
        // TODO 使用 notNull的判断会直接判断 xxx != null, 数字类型生成模板就是错误的
        return false;

    }
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>, 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中进行的,那么多线程操作时就可能会存在内存泄露的可能性。现在还没有好的解决方法

你可能感兴趣的:(GreenDao遇到的一些坑)