【问题标题】:No response from Api when collected StateFlow does not change kotlin收集 StateFlow 时 Api 没有响应不会更改 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()
}

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

【问题讨论】:

    标签: android kotlin mvvm


    【解决方案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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-25
      • 2022-12-06
      • 2020-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多