【问题标题】:Jetpack Compose MutableLiveData not updating UI ComponentsJetpack Compose MutableLiveData 不更新 UI 组件
【发布时间】:2023-03-10 06:19:01
【问题描述】:

我试图通过包含下载 ID 和进度值的数据对象列表一次显示多个下载进度条。此对象列表的值正在更新(通过日志记录显示),但 UI 组件在其初始值从 null 更改为第一个进度值后不会更新。请帮忙!

我看到有类似的问题,但他们的解决方案对我不起作用,包括附加观察员。

class DownLoadViewModel() : ViewModel() {
   ...
   private var _progressList = MutableLiveData<MutableList<DownloadObject>>()
   val progressList = _progressList // Exposed to the UI.
   ...
   
   //Update download progress values during download, this is called 
   // every time the progress updates.
   val temp = _progressList.value
   temp?.forEach { item ->
      if (item.id.equals(download.id)) item.progress = download.progress
   }
   _progressList.postValue(temp)
   ...
}

界面组件

@Composable
fun ExampleComposable(downloadViewModel: DownloadViewModel) {
    val progressList by courseViewModel.progressList.observeAsState()
    val currentProgress = progressList.find { item -> item.id == local.id }
    ...
    LinearProgressIndicator(
        progress = currentProgress.progress
    )
    ...
}

【问题讨论】:

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


    【解决方案1】:

    查了很多文字,解决ViewModel中的List不更新Composable的问题。我试了三种方法都无济于事,比如:LiveData、MutableLiveData、mutableStateListOf、MutableStateFlow

    根据测试发现值变了,但是界面没有更新。该文件说,只有当 State 的值发生变化时,页面才会更新。根本问题是数据问题。如果没有更新,说明State没有监听到数据更新。

    以上方法对增删有效,但是单独更新不起作用,因为我更新了T中的元素,但是对象并没有改变。

    解决办法是深拷贝。

    
        fun agreeGreet(greet: Greet) {
            val g = greet.copy(agree = true)  // This way is invalid 
            favourites[0] = g
        }
    
    
    
        fun agreeGreet(greet: Greet) {
            val g = greet.copy() // This way works
            g.agree = true
            favourites[0] = g
        }
    
    

    很奇怪,浪费了很多时间,希望对需要更新的人有所帮助。

    【讨论】:

    • 是的,感谢您更新这个问题,它已在另一个页面上得到回答,但在这里也有答案非常有帮助。
    • 这里是另一个非常相似的问题的链接,有一个有效的解决方案stackoverflow.com/questions/68781116/…
    • 只可惜​​浏览量最高的官方文档不会提示这些。幸好遗憾,我们在这里相遇
    【解决方案2】:

    尽可能考虑在 JC 中使用mutableStateOf(...) 而不是LiveDataFlow。所以,在你的viewmodel

    class DownLoadViewModel() : ViewModel() {
       ...
       private var progressList by mutableStateOf(listOf<DownloadObject>()) //Using an immutable list is recommended
       ...
       
       //Update download progress values during download, this is called 
       // every time the progress updates.
       val temp = progress.value
       temp?.forEach { item ->
          if (item.id.equals(download.id)) item.progress = download.progress
       }
       progress.postValue(temp)
       ...
    }
    

    现在,如果您想向progressList 添加一个元素,您可以执行以下操作:-

    progressList = progressList + listOf(/*item*/)

    在你的活动中,

    @Composable
    fun ExampleComposable(downloadViewModel: DownloadViewModel) {
        val progressList by courseViewModel.progressList
        val currentProgress = progressList.find { item -> item.id == local.id }
        ...
        LinearProgressIndicator(
            progress = currentProgress.progress
        )
        ...
    }
    

    编辑,

    对于具体的用例,你也可以使用mutableStateListOf(...)而不是mutableStateOf(...)。这允许轻松修改和添加项目到列表中。这意味着您可以像使用常规 List 一样使用它,并且它可以正常工作,在修改时触发重新组合,供 Composables 读取它。

    【讨论】:

    • 嘿,顺便考虑一下撰写代码实验室。州也有一个。
    • 真正帮助你掌握概念
    • 为此,您可以使用progressList = progressList.toMutableList().also { it[index] = newItem }
    • 好吧,a)使用MutableState 对象类型,您不需要“观察”,Compose 已预先配置为观察值的任何变化,b)我在答案中编写了该代码盒子本身,在移动设备上;不知道它必须编译,因为我只是想给你核心思想,即使用MutableState 对象而不是LiveDataFlow,并且c)查看文档,他们清楚地提到,实际上不要查看文档-您说您参加了 codelab 对吗?在那里他们用MutableState“替换”LiveData,同时展示它(当然,这是一个最佳实践)
    • 面临问题的不止您一个人。检查该站点是否有类似问题,您会发现至少有三个(我自己回答过)患有相同问题的人,通过将其替换为MutableState 解决了他们的问题。一个是昨天(或今天,取决于您所在的时区)最近的一个
    【解决方案3】:

    将 LiveData/Flow 与 Jetpack Compose 一起使用是完全可以的。事实上,它们被明确命名为in the docs

    这些相同的文档还在红框中以下几行描述了您的错误:

    警告:在 Compose 中使用可变对象(例如 ArrayList 或 mutableListOf())作为状态会导致您的用户在您的应用中看到不正确或过时的数据。

    不可观察的可变对象,例如 ArrayList 或可变数据类,无法被 Compose 观察以在它们发生变化时触发重组。

    我们建议您使用可观察的数据持有者,例如 State 和不可变的 listOf(),而不是使用不可观察的可变对象。

    所以解决方法很简单:

    • 让您的 progressList 不可变
    • 更新时创建一个新列表,它是旧列表的副本,但具有新的进度值

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-24
      • 2023-01-14
      • 1970-01-01
      • 1970-01-01
      • 2022-11-03
      • 1970-01-01
      • 1970-01-01
      • 2021-07-18
      相关资源
      最近更新 更多