如何手动更新 Kotlin 流程

How to manually update a kotlin flow

我正在尝试在 Kotlin 中更新 Flow 的源代码,但我不确定这是否是正确的方法以及 Flow 是否可行。

我有一个包含 post 个用户的数据库,这个 return 是我 Flow<List<Post>>。 现在,当我 select 另一个用户时,我希望数据库流向 return 我 post 新 selected 用户的 posts:


lateinit var userPosts: Flow<List<Post>>
   private set

fun getPostsForUser(user: User) {
   userPosts = database.getAllPostsForUser(user)
}

但是流程永远不会使用新 selected 用户的数据进行更新。在这种情况下,Flow 仍然是正确的选择吗?如果是,我如何使用新的 posts 更新流程?

我知道如何通过从数据库中获取数据并使用 LiveData 发送数据来手动执行此操作,但我想避免每次用户 posts 时处理 posts 的更新新的或post被删除。

我想也许您正在收集一个流,然后设置一个用户,这会更改 属性 中的流,但不会更改任何已经收集的现有流。我不确定还有什么可以解释发生的事情。

有一个 public 流 属性 依赖于其他一些带有参数的函数可能容易出错。您可以 return 直接从函数中获取 Flow,这样行为就不会产生歧义。该片段为特定用户请求流并立即获得它。

distinctUntilChanged() 将阻止它发出由 repo 中的其他更改导致的未更改列表。

fun getPostsForUser(user: User) Flow<List<Post>> =
    database.getAllPostsForUser(user).distinctUntilChanged()

如果你确实想使用你的模式,我想你可以这样做。这允许永远只有一个 Flow,因此尽早开始收集它是安全的。更改用户将更改其发布的值。虽然这比上面更复杂,但它的优点是不需要在屏幕旋转和其他配置更改时刷新数据。

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)
    }

或者正如 Joffrey 所建议的那样,如果您不介意使用不稳定的 API 函数 flatMapLatest,那么使用用户流程会更简单。如果您不介意公开应在外部设置值的 public 可变流,则可以删除此处的 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)
}

这可能对某人有帮助...

当您在下游收集流量时,在某些情况下,您需要更新的流量或与以前完全不同的流量,请使用 flatmapLatest() 功能。

示例:

应用程序中有一个搜索结果流。当用户输入搜索文本流时,应根据搜索到的字符自动更新最新数据。

将查询文本放在 StateFlow 中,

private var _userSearchText = MutableStateFlow("")
val userSearchText = _userSearchText.asStateFlow()

当用户输入文本时,只需将 Stateflow 更新为,

fun setUserNameSearchText(data: String) {
   _userSearchText.value = data
}

你的流量收集就像,

val response = userSearchText.flatMapLatest {
    searchRepository.getResults(it)
        .cachedIn(viewModelScope)
}

Stateflow 将自动触发 API 调用。它将通知所有观察者。

PS:有待改进...