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()
}