Jetpack Compose MutableLiveData 未更新 UI 个组件
Jetpack Compose MutableLiveData not updating UI Components
我试图通过包含下载 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)
...
}
UI 组件
@Composable
fun ExampleComposable(downloadViewModel: DownloadViewModel) {
val progressList by courseViewModel.progressList.observeAsState()
val currentProgress = progressList.find { item -> item.id == local.id }
...
LinearProgressIndicator(
progress = currentProgress.progress
)
...
}
尽可能考虑在JC中使用mutableStateOf(...)
而不是LiveData
和Flow
。所以,在你的 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*/)
在你的activity,
@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(...)
。这允许轻松修改和添加项目到列表中。这意味着您可以像普通列表一样使用它,它会工作得很好,在修改时触发重组,供可组合项读取它。
我查了很多文解决了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
}
很奇怪,浪费了很多时间,希望对需要更新的小伙伴有所帮助
LiveData/Flow 与 Jetpack Compose 一起使用完全没问题。事实上,它们被显式命名为 in the docs.
这些相同的文档还在下面红框中的几行中描述了您的错误:
Caution: Using mutable objects such as ArrayList or mutableListOf() as state in Compose will cause your users to see incorrect or stale data in your app.
Mutable objects that are not observable, such as ArrayList or a mutable data class, cannot be observed by Compose to trigger recomposition when they change.
Instead of using non-observable mutable objects, we recommend you use an observable data holder such as State<List> and the immutable listOf().
所以解决方法很简单:
- 让你的
progressList
不可变
- 在更新时创建一个新列表,它是旧列表的副本,但具有您的新进度值
我试图通过包含下载 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)
...
}
UI 组件
@Composable
fun ExampleComposable(downloadViewModel: DownloadViewModel) {
val progressList by courseViewModel.progressList.observeAsState()
val currentProgress = progressList.find { item -> item.id == local.id }
...
LinearProgressIndicator(
progress = currentProgress.progress
)
...
}
尽可能考虑在JC中使用mutableStateOf(...)
而不是LiveData
和Flow
。所以,在你的 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*/)
在你的activity,
@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(...)
。这允许轻松修改和添加项目到列表中。这意味着您可以像普通列表一样使用它,它会工作得很好,在修改时触发重组,供可组合项读取它。
我查了很多文解决了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
}
很奇怪,浪费了很多时间,希望对需要更新的小伙伴有所帮助
LiveData/Flow 与 Jetpack Compose 一起使用完全没问题。事实上,它们被显式命名为 in the docs.
这些相同的文档还在下面红框中的几行中描述了您的错误:
Caution: Using mutable objects such as ArrayList or mutableListOf() as state in Compose will cause your users to see incorrect or stale data in your app.
Mutable objects that are not observable, such as ArrayList or a mutable data class, cannot be observed by Compose to trigger recomposition when they change.
Instead of using non-observable mutable objects, we recommend you use an observable data holder such as State<List> and the immutable listOf().
所以解决方法很简单:
- 让你的
progressList
不可变 - 在更新时创建一个新列表,它是旧列表的副本,但具有您的新进度值