【问题标题】:Android update activity with value of data object field from MutableStateFlow<List<MyDataObject>>()Android 使用来自 MutableStateFlow<List<MyDataObject>>() 的数据对象字段的值更新活动
【发布时间】:2021-10-17 05:21:39
【问题描述】:

当我更改用于显示下载进度条的对象中的字段值时,我无法可靠地从viewModel() 更新我的活动/UI 层。该活动可以很好地观察列表中对象的添加和删除,但不会更改进度字段。

数据类

data class DownloadObject(
   val id: String?,
   var progress: Float,
)

视图模型

class MyViewModel () : ViewModel() {

   private val _progressList = MutableStateFlow<List<DownloadObject>>(emptyList())
   val progressList: StateFlow<List<DownloadObject>>
       get() = _progressList

   //add to list updates the activity
   _progressList.value += DownloadObject

   //remove from list updates the activity
   _progessList.value -= DownloadObject

   // Change progress field doesn't update the activity
   _progressList.value.onEach{
       if(it.id == id) {it.progress = progress}
   }
}

活动

val progressList by courseViewModel.progressList.collectAsState(emptyList()
...
LinearProgressIndicator(progress = progressList.find { it.id == id }?.progress)

我尝试过使用mutableStateListOf()MutableLiveData,但遇到了许多相同的问题。我已经将两个州代码实验室都用于撰写,但我真的不知道从这里做什么。非常感谢任何帮助,谢谢!

【问题讨论】:

  • 如果您希望您的问题得到解答,您需要让专家尽快获得具有可重现问题的工作样本。完美地,我应该将您的代码粘贴到我的示例项目中,并在我运行它时尽快看到问题。在您的情况下,我不知道您如何存储/更改 id 以及为什么 find 可能不会以任何原因返回 null

标签: android android-activity android-livedata android-jetpack-compose android-viewmodel


【解决方案1】:
// Change progress field doesn't update the activity
   _progressList.value.onEach{
       if(it.id == id) {it.progress = progress}
   }

这实际上不会触发您的progressList StateFlow 中的更新。 为此,您可能需要使用以下内容:

_progressList.value = progressList.value.map {
    if(it.id == id) {
        it.copy(progress = progress)
    } else {
        it
    }
}

【讨论】:

    【解决方案2】:

    在列表中添加和删除实际上是在更新 UI,因为您正在使用“+”和“-”运算符执行这些操作,它们会在后台创建一个新列表。因此,如果你想更新列表的内容,然后重新组合,你要么必须做类似的事情,要么改变你的方法。

    对于第一个选项,您可以

    _progressList.value = progressList.value.onEach{ // Or something of equivalent sort, if Kotlin is smart enough
           if(it.id == id) {it.progress = progress}
       }
    

    在使用 compose 时,更好的方法是始终使用 MutableState 而不是 Flow 或其他方法。很干净。

    class MyViewModel () : ViewModel() {
    
       val progressList = mutableStateListOf<DownloadObject>()
    
        /* Treat it as a regular list object now*/
    
       _progressList += DownloadObject
    
       _progessList.value -= DownloadObject
    
        // It hopefully will work now
       _progressList.forEach{
           if(it.id == id) {it.progress = progress}
       }
    }
    

    活动:-

    val progressList by courseViewModel.progressList // That's it
    ...
    LinearProgressIndicator(progress = progressList.find { it.id == id }?.progress)
    

    看看它是否有效并告诉我

    【讨论】:

    • 谢谢,虽然这确实更新了列表的内容,但它不会触发活动可观察到的状态更新。
    • 哪个不会触发重组?第一种还是第二种方法?
    • 这些方法都不会触发活动中的重组。这不是我向活动公开的变量类型的问题(mutableStateOf、mutableStateListOf、flow、MutableLiveData 等),因为我都试过了。我标记为正确的答案,映射然后复制条件,确实有效!
    猜你喜欢
    • 2020-06-12
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-30
    • 2021-08-30
    • 1970-01-01
    相关资源
    最近更新 更多