当收集到的 StateFlow 未更改 kotlin 时,Api 没有响应
No response from Api when collected StateFlow does not change kotlin
在我的片段中,我有一个 RecyclerView,它显示我在选项菜单中输入的查询的结果。这是一个 API,我从中收到电视节目列表。
查询至少需要len为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
}
但是,我在输入例如“猫”两次。我收到了一份有猫的节目清单。从选项菜单中删除查询并再次点击后,适配器为空。并且没有相同的搜索。对我来说->因为流量值没变。
在 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()
}
现在它按预期工作了。但是有没有更好的方法来实现它?
为了让您的代码不那么复杂,请避免在您的 UI 类 (Fragment/Activity/Adapter) 中进行逻辑处理,并让您的 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)
}
}
在我的片段中,我有一个 RecyclerView,它显示我在选项菜单中输入的查询的结果。这是一个 API,我从中收到电视节目列表。
查询至少需要len为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
}
但是,我在输入例如“猫”两次。我收到了一份有猫的节目清单。从选项菜单中删除查询并再次点击后,适配器为空。并且没有相同的搜索。对我来说->因为流量值没变。
在 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()
}
现在它按预期工作了。但是有没有更好的方法来实现它?
为了让您的代码不那么复杂,请避免在您的 UI 类 (Fragment/Activity/Adapter) 中进行逻辑处理,并让您的 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)
}
}