收集 StateFlow 时 Api 没有响应不会更改 kotlin

Posted

技术标签:

【中文标题】收集 StateFlow 时 Api 没有响应不会更改 kotlin【英文标题】:No response from Api when collected StateFlow does not change kotlin 【发布时间】:2022-01-10 11:52:04 【问题描述】:

在我的片段中,我有一个 RecyclerView,它显示了我在选项菜单中输入的查询的结果。它是我从中接收电视节目列表的 API。

查询需要长度至少为 3 的字符串。当它为 1 或 2 时,适配器被清除。

override fun onQueryTextChange(newText: String?): Boolean 
if (newText != null && newText.length > 2) 
 if (!newText.isNullOrBlank() && newText.length > 2)
 viewModel.searchMovies(newText)
  
else 
adapter.setMoviesList(emptyList())
     
return true

但是,我在输入 e.g. 后遇到了问题。 “猫”两次。我收到了一份有猫的节目清单。从选项菜单中删除查询并再次对其进行录音后,适配器为空。并且没有相同的搜索。对我来说 -> 因为流量值没有改变。

在 ViewModel 我有:

    private val _moviesStateFlow = MutableStateFlow<List<TvMazeShowResponse>>(emptyList())
    val moviesStateFlow = _moviesStateFlow as StateFlow<List<TvMazeShowResponse>>

    fun searchMovies(query: String) 
        viewModelScope.launch 
            val response = api.getApiResponse(query)
            _moviesStateFlow.emit(response)
        
    

还有我在片段中收集的这个 StateFlow。

        lifecycleScope.launch 
            viewModel.moviesStateFlow.collect 
                adapter.setMoviesList(it)
            
        

为了解决这个问题,我在 VM 中添加了另一个函数

    fun clearFlow() 
        viewModelScope.launch 
            _moviesStateFlow.emit(emptyList())
        
    

现在在 onQueryTextChange 的片段中我添加了 else。

else 
adapter.setMoviesList(emptyList())
viewModel.clearFlow()

现在它可以按预期工作了。但是有没有更好的方法来实现这一点?

【问题讨论】:

【参考方案1】:

为减少您的代码复杂度,请避免在您的 UI 类(片段/活动/适配器)中执行逻辑,并让您的 ViewModel 提供单一的事实来源。

override fun onQueryTextChange(newText: String?): Boolean 
    viewModel.searchMovies(newText.orEmpty())
    return true


// In ViewModel
fun searchMovies(query: String) 
    val trimmedQuery = query.trim()
    viewModelScope.launch 
        val response = if (trimmedQuery.length <= 2) emptyList() else api.getApiResponse(trimmedQuery)
        _moviesStateFlow.emit(response)
    

为避免在用户快速输入时运行多个过时的查询,我建议在开始新的搜索时取消以前的搜索。

private val searchJob? = null

fun searchMovies(query: String) 
    val trimmedQuery = query.trim()
    searchJob?.cancel()
    searchJob = viewModelScope.launch 
        val response = if (trimmedQuery.length <= 2) emptyList() else api.getApiResponse(trimmedQuery)
        _moviesStateFlow.emit(response)
    

【讨论】:

以上是关于收集 StateFlow 时 Api 没有响应不会更改 kotlin的主要内容,如果未能解决你的问题,请参考以下文章

StateFlow:收集后取消旧的发射状态

如何使用 Spring Boot WebClient 收集分页 API 响应?

有没有办法从 Flow 中创建 StateFlow

Kotlin Flow响应式编程,StateFlow和SharedFlow

Kotlin Flow响应式编程,StateFlow和SharedFlow

Kotlin Flow 冷流 StateFlow 热流 StateFlow 的应用