【问题标题】:Using StateFlow To Update List Adapter使用 StateFlow 更新列表适配器
【发布时间】:2021-12-28 01:51:18
【问题描述】:

我正在尝试从 LiveData 切换到 StateFlow 以填充我的 ListAdapter。

我目前有一个MutableLiveData<List<CustomClass>>,我正在观察它来更新列表适配器:

  viewModel.mutableLiveDataList.observe(viewLifecycleOwner, Observer {
         networkIngredientAdapter.submitList(it)
}

这很好用。现在我将 viewModel 中的MutableLiveData<List<CustomClass>?> 替换为MutableStateFlow<List<CustomClass>?>,如下所示:

 private val _networkResultStateFlow = MutableStateFlow<List<IngredientDataClass>?>(null)
    val networkResultStateFlow : StateFlow<List<IngredientDataClass>?>
    get() = _networkResultStateFlow

 fun loadCustomClassListByNetwork() {
            viewModelScope.launch {
//a network request using Retrofit
 val result = myApi.myService.getItems()
 _networkResultStateFlow.value = result
}
}

我正在这样的片段中收集新列表:


 lifecycleScope.launchWhenStarted {
 viewModel.networkResultStateFlow.collect(){
                list -> networkIngredientAdapter.submitList(list)}
}

但是,当我调用 loadCustomClassListByNetwork() 时,列表适配器不会更新。为什么我无法收集价值

【问题讨论】:

  • 尝试将launchWhenStarted替换为launchWhenCreated
  • 还将 ?>(null) 替换为 >(emptyList()) 以获得干净的代码

标签: android kotlin-coroutines kotlin-flow kotlin-stateflow


【解决方案1】:

尝试用以下代码替换片段中的代码:

lifecycleScope.launch {
viewModel.networkResultStateFlow.flowWithLifecycle(lifecycle)
         .collect { }
}

【讨论】:

  • 我认为您的答案是正确的,因为flowWithLifecycle() 将创建一个新的协程范围,这就是我的解决方案以一种不太优雅的方式所做的事情。不幸的是,我无法测试您的答案,因为我无法将 SDK 版本更改为 flowWithLifecycle() 所需的 31。
【解决方案2】:

我在最初的问题中没有提到,但是在创建的协程范围内进行了两次收集调用:

lifecycleScope.launchWhenStarted {

       viewModel.networkResultStateFlow.collect(){
                list -> networkIngredientAdapter.submitList(list)}

       viewModel.listOfSavedIngredients.collectLatest(){
                  list -> localIngredientAdapter.submitList(list)}
}

以前只有第一个对方付费电话有效,因此只有一个列表在更新。所以我刚刚创建了两个单独的协程范围,现在它可以工作了:

lifecycleScope.launchWhenStarted {

       viewModel.networkResultStateFlow.collect(){
                list -> networkIngredientAdapter.submitList(list)}
}

lifecycleScope.launchWhenStarted {

       viewModel.listOfSavedIngredients.collectLatest(){
                  list -> localIngredientAdapter.submitList(list)}
}

注意:使用 launchlaunchWhenStartedlaunchWhenCreated 会产生相同的结果。

我会在弄清楚每次收集调用需要单独范围的原因后编辑我的回复。

编辑: 所以只有一个 listAdapter 被更新的原因是因为我需要为我的每个 StateFlow 单独的 CoroutineScope,因为根据定义,Flows 在协程上运行。每个流程都使用其各自的协程范围来收集自己的值,因此您不能让流程共享相同的协程范围 b/c,然后它们将冗余地收集相同的值。 @ruby6221 提供的答案还创建了一个新的协程范围,因此很可能有效,但由于升级我的 SDK 版本的不相关问题,我无法对其进行测试,否则我会将其设置为正确答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多