Android Compose 不使用 viewModel uiState 刷新
Android Compose not refresh with viewModel uiState
为了学习,我正在编写一个简单的 compose 应用程序,该应用程序有两个 viewModels
、显示项目列表的 ItemListViewModel
和让您创建的 ItemCreateViewModel
项目,项目存储在房间中。
我的问题是,当我打开应用程序时会显示列表,但在我打开详细信息并创建新项目后,返回第一个 (ItemListViewModel
) 列表不会更新。
@HiltViewModel
class ItemListViewModel
@Inject
constructor(private val itemRepository: ItemRepository) : ViewModel() {
var uiState by mutableStateOf(value = ItemListState(state = State.LOADING))
private set
init {
viewModelScope.launch(Dispatchers.IO) {
itemRepository.fetchItems()
.distinctUntilChanged()
.collect { items ->
uiState = uiState.copy(
state = State.IDLE,
items = if (items.isNullOrEmpty()) emptyList() else items
)
}
}
}
这里是撰写视图
@Composable
fun ItemList(
viewModel: ItemListViewModel,
navController: NavController
) {
val items = viewModel.uiState.items
ShowItems(items) // <--- this is not called
}
这是存储库的乐趣
fun fetchItems(): Flow<List<ItemEntity>>
如果我关闭应用程序并重新启动它,我可以看到新创建的项目。
您的列表没有刷新,因为您的协程在导航到 CreateMedicineScreen
屏幕时被取消。当您返回 MedicineList
屏幕时,不会调用 init
(因为它是同一个 ViewModel 实例)。您可以将刷新公开为 ViewModel 中的 public 方法(正如您在代码中开始的那样),并使用 side-effect.
从可组合项中调用它
@Composable
fun MedicineList(
viewModel: MedicineListViewModel,
navController: NavController
) {
LaunchedEffect(Unit) {
viewModel.fetchMedicines()
}
val medicines = viewModel.uiState.medicines
ShowMedicines(medicines) {
navController.navigate(NEW_MEDICINE_ROUTE)
}
}
当您返回屏幕时,MedicineList
将重新组合并执行 fetch 方法。
作为奖励,我注意到您在从 CreateMedicineScreen
屏幕保存时返回导航有问题。这是因为您正在尝试从可组合项导航。它也在 documentation
中指定
You should only call navigate() as part of a callback and not as part of your composable itself, to avoid calling navigate() on every recomposition.
你也可以在这里使用副作用:
LaunchedEffect(key1 = Unit) {
navController.popBackStack()
}
为了学习,我正在编写一个简单的 compose 应用程序,该应用程序有两个 viewModels
、显示项目列表的 ItemListViewModel
和让您创建的 ItemCreateViewModel
项目,项目存储在房间中。
我的问题是,当我打开应用程序时会显示列表,但在我打开详细信息并创建新项目后,返回第一个 (ItemListViewModel
) 列表不会更新。
@HiltViewModel
class ItemListViewModel
@Inject
constructor(private val itemRepository: ItemRepository) : ViewModel() {
var uiState by mutableStateOf(value = ItemListState(state = State.LOADING))
private set
init {
viewModelScope.launch(Dispatchers.IO) {
itemRepository.fetchItems()
.distinctUntilChanged()
.collect { items ->
uiState = uiState.copy(
state = State.IDLE,
items = if (items.isNullOrEmpty()) emptyList() else items
)
}
}
}
这里是撰写视图
@Composable
fun ItemList(
viewModel: ItemListViewModel,
navController: NavController
) {
val items = viewModel.uiState.items
ShowItems(items) // <--- this is not called
}
这是存储库的乐趣
fun fetchItems(): Flow<List<ItemEntity>>
如果我关闭应用程序并重新启动它,我可以看到新创建的项目。
您的列表没有刷新,因为您的协程在导航到 CreateMedicineScreen
屏幕时被取消。当您返回 MedicineList
屏幕时,不会调用 init
(因为它是同一个 ViewModel 实例)。您可以将刷新公开为 ViewModel 中的 public 方法(正如您在代码中开始的那样),并使用 side-effect.
@Composable
fun MedicineList(
viewModel: MedicineListViewModel,
navController: NavController
) {
LaunchedEffect(Unit) {
viewModel.fetchMedicines()
}
val medicines = viewModel.uiState.medicines
ShowMedicines(medicines) {
navController.navigate(NEW_MEDICINE_ROUTE)
}
}
当您返回屏幕时,MedicineList
将重新组合并执行 fetch 方法。
作为奖励,我注意到您在从 CreateMedicineScreen
屏幕保存时返回导航有问题。这是因为您正在尝试从可组合项导航。它也在 documentation
You should only call navigate() as part of a callback and not as part of your composable itself, to avoid calling navigate() on every recomposition.
你也可以在这里使用副作用:
LaunchedEffect(key1 = Unit) {
navController.popBackStack()
}