[英]Kotlin - StateFlow not emitting updates to its collectors
我的应用程序中有一个 UserStateModel(数据类)类型的 StateFlow。
private val _userStateFlow: MutableStateFlow<UserStateModel?> = MutableStateFlow(UserStateModel())
val userStateFlow: StateFlow<UserStateModel?> = _userStateFlow
这是用户状态模型
data class UserStateModel(
val uid: String? = null,
val username: String? = null,
val profileImageUrl: String? = null,
var isLoggedIn: Boolean = false,
val isPremiumUser: Boolean = false,
val posts: List<Post>? = listOf()
)
当我使用新的用户名更新 StateFlow 时,它会将更改发送给收集器并更新 UI。 但是当我更改帖子中的属性时:列表? 列出它不会发出更改。 当我更改列表的大小时,当我更改索引 0 处的 Post 的 name 属性时,它不会。 如何检测对 Data 类的子属性的更改?
现在我使用一个丑陋的解决方法,我补充说
val updateErrorWorkaround: Int = 0
到 UserStateModel 数据类并将其增加一,以便收集器得到通知
Ps 我正在使用 MVVM + Clean Architecture 和 Jeptack Compose
编辑那是我的帖子模型:
data class Post(
val id: Int,
val name: String,
val tags: MutableList<Tag>? = null
)
这是我更新 MutableList 的方法:
val posts = userStateFlow.value?.posts
posts.get(index).tags?.add(myNewTag)
_userStateFlow.value = userStateFlow.value?.copy(posts = posts)
这些更改不会发送给收集器
StateFlow
仅在检测到值更改时发出,它忽略用相同数据替换值。 为此,它将先前的值与新的值进行比较。 出于这个原因,我们不应该修改我们已经提供给StateFlow
的数据,因为它无法检测到变化。
例如,我们将value
设置为User(name=John)
。 然后我们通过将其name
修改为James
来改变相同的用户对象,并将value
设置为这个“新”用户对象。 StateFlow
将“新” User(name=James)
与其存储的值(现在也是User(name=James)
进行比较,因此它看不到任何变化。
在您的示例中,您创建了UserStateModel
的副本,但在内部您重复使用相同的对象并改变它们。 在这种情况下,您向tags
添加了一个新项目,并且此更改也影响了旧的UserStateModel
,因此StateFlow
不会检测到更改。
要解决此问题,您需要复制所有已更改的数据,并且不要在原地更改任何内容。 使所有数据不可变更安全,因此val
和List
- 这样您就被迫进行复制。 我将tags
更改为val tags: List<Tag> = listOf()
,那么您的代码可能如下所示:
val posts = userStateFlow.value?.posts!!.toMutableList()
posts[index] = posts[index].copy(tags = posts[index].tags + myNewTag)
userStateFlow.value = userStateFlow.value?.copy(posts = posts)
在这里,我们不仅创建了UserStateModel
的副本。 我们还复制posts
列表,我们修改的Post
,我们还复制标签列表。
或者,如果StateFlow
的这种行为对您来说更烦人而不是有用,您可以使用SharedFlow
,它不比较值,而只是发出。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.