Mr.*_*eks 4 kotlin android-room
我正在尝试更新 Kotlin 中 Flow 的源代码,但我不确定这是否是正确的方法以及 Flow 是否可行。
我有一个包含用户帖子的数据库,这会返回一个Flow<List<Post>>. 现在,当我选择另一个用户时,我希望数据库流返回新选择的用户的帖子:
lateinit var userPosts: Flow<List<Post>>
private set
fun getPostsForUser(user: User) {
userPosts = database.getAllPostsForUser(user)
}
Run Code Online (Sandbox Code Playgroud)
但流程永远不会用新选定用户的数据进行更新。在这种情况下,Flow 是否仍然是正确的选择?如果是,我如何使用新帖子更新 Flow?
我知道如何手动执行此操作,从数据库中获取数据并使用 LiveData 发出数据,但我想避免每次用户发布新内容或删除帖子时处理帖子更新。
我想也许您正在收集一个流,然后设置一个用户,这会更改属性中的流,但不会更改已收集的任何现有的先前流。我不知道还能如何解释正在发生的事情。
如果公共 Flow 属性依赖于某些采用参数的其他函数,则可能容易出错。您可以直接从函数返回 Flow,这样行为就不会含糊不清。该片段请求特定用户的流并立即获取它。
distinctUntilChanged()将阻止它发出因存储库中其他更改而导致的未更改列表。
fun getPostsForUser(user: User) Flow<List<Post>> =
database.getAllPostsForUser(user).distinctUntilChanged()
Run Code Online (Sandbox Code Playgroud)
如果你确实想使用你的模式,我认为你可以这样做。这使得只能有一个流,因此尽早开始收集它是安全的。更改用户将更改其发布的值。尽管这比上面更复杂,但它的优点是不需要在屏幕旋转和其他配置更改时刷新数据。
private val mutableUserPosts = MutableStateFlow<List<Post>>(emptyList())
val userPosts: Flow<List<Post>> = mutableUserPosts
private var userPostsJob: Job? = null
var user: User? = null
set(value) {
field = value
userPostsJob?.cancel()
value ?: return
userPostsJob = database.getAllPostsForUser(value)
.onEach { mutableUserPosts.emit(it) }
.launchIn(viewModelScope)
}
Run Code Online (Sandbox Code Playgroud)
或者正如 Joffrey 所建议的,如果您不介意使用不稳定的 API 函数,那么用户流程会更简单flatMapLatest。user如果您不介意公开应在外部设置值的公共可变流,则可以删除此处的属性。或者,如果您重复使用此模式,您可以为 StateFlow/MutableStateFlow 创建运算符扩展函数以将其用作属性委托。
private val userFlow = MutableStateFlow<User?>(null)
var user: User?
get() = userFlow.value
set(value) {
userFlow.value = value
}
val userPosts: Flow<List<Post>> = userFlow.flatMapLatest { user ->
if (user == null) emptyFlow() else database.getAllPostsForUser(user)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5013 次 |
| 最近记录: |