Kotlin Realm嵌入式对象参数更新时查询Flow不发射事件咨询
问题解答
关于Realm默认监听的行为
Realm默认的asFlow()监听不会自动追踪RealmList内部嵌入式对象的字段变更,哪怕层级在默认的4层限制以内。这是因为默认监听只关注RealmObject本身的直接字段(比如id、myEmbeddedRealmObjects列表字段本身),而列表容器内的嵌入式对象字段修改,不会被视为父对象的"直接变更",因此不会触发默认的Flow更新。必须通过keyPaths显式指定要监听的嵌套路径,才能捕获这类变更。
替代解决方案
除了为每个查询添加keyPaths,还有以下几种处理方式:
1. 直接监听嵌入式对象的Flow
如果业务场景允许,可以直接针对嵌入式对象创建查询Flow,绕过父对象的监听限制:
fun observeEmbeddedObjects(parentId: String): Flow<RealmResults<MyEmbeddedRealmObject>> = realm.query<MyEmbeddedRealmObject>("parent.id = $0", parentId) .asFlow() .mapLatest { it.list }
注:Realm中嵌入式对象会隐式关联父对象,因此可以通过
parent.id路径查询属于指定父对象的嵌入式实例。
2. 给父对象添加版本戳字段
在MyRealmObject中新增一个版本戳字段,每次更新嵌入式对象时同步更新该字段,触发父对象的默认监听:
class MyRealmObject: RealmObject { @PrimaryKey var id: String = "" var myEmbeddedRealmObjects: RealmList<MyEmbeddedRealmObject> = realmListOf() var updateVersion: Long = 0 // 新增版本戳 }
更新嵌入式对象时同步更新版本戳:
realm.write { val parentObj = findLatest<MyRealmObject>(targetId) ?: return@write targetEmbeddedObj.exampleEmbeddedParam = "updated value" parentObj.updateVersion += 1 }
此时父对象的Flow会因为updateVersion字段变化而发射新状态,你可以在mapLatest中忽略版本戳,只获取目标数据。
3. 封装扩展函数简化keyPaths配置
如果觉得重复写keyPaths麻烦,可以封装一个通用扩展函数,统一处理需要监听嵌入式对象变更的场景:
fun <T : RealmObject> SingleQuery<T>.asFlowWithNestedUpdates(): Flow<T?> = this.asFlow(listOf("*.*")) // 监听所有二级嵌套变更 .mapLatest { it.obj }
之后查询时直接调用该扩展函数即可:
fun observeMyRealmObject(id: String): Flow<MyRealmObject?> = realm .query<MyRealmObject>("id = $0", id) .first() .asFlowWithNestedUpdates()
总结
最推荐的方案还是显式指定keyPaths或使用封装的扩展函数,这是Realm官方设计的针对嵌套容器变更监听的标准方式,代码简洁且符合框架设计逻辑。其他方案会增加业务代码的复杂度,仅适合特定场景下使用。
内容的提问来源于stack exchange,提问作者J. Hegg
相关产品推荐
相关产品推荐

