Android Compose 无法使用 viewModel uiState 刷新

Oni*_*vas 0 android viewmodel android-jetpack-compose

我正在编写一个简单的应用程序,以便学习,该应用程序有两个viewModelsItemListViewModel显示项目列表并ItemCreateViewModel让您创建项目,项目存储在 Room 中。

我的问题是,当我打开应用程序时,会显示列表,但在我打开详细信息并创建新项目后,返回第一个 ( 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
                    )
                }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这里是撰写视图

@Composable
fun ItemList(
    viewModel: ItemListViewModel,
    navController: NavController
) {

 
    val items = viewModel.uiState.items
    ShowItems(items)  // <--- this is not called

}

Run Code Online (Sandbox Code Playgroud)

这是存储库的乐趣

fun fetchItems(): Flow<List<ItemEntity>>
Run Code Online (Sandbox Code Playgroud)

如果我终止该应用程序并重新启动它,我可以看到新创建的项目。

pti*_*nou 5

您的列表不会刷新,因为您的协程在导航到CreateMedicineScreen屏幕时被取消。当您返回MedicineList屏幕时,init不会调用(因为它是同一个 ViewModel 实例)。您可以将刷新公开为 ViewModel 中的公共方法(正如您在代码中开始的那样),并使用副作用从可组合项中调用它。

@Composable
fun MedicineList(
    viewModel: MedicineListViewModel,
    navController: NavController
) {

    LaunchedEffect(Unit) {
        viewModel.fetchMedicines()
    }

    val medicines = viewModel.uiState.medicines
    ShowMedicines(medicines) {
        navController.navigate(NEW_MEDICINE_ROUTE)
    }
}
Run Code Online (Sandbox Code Playgroud)

当您弹回屏幕时,MedicineList将重新组合并执行一次 fetch 方法。

作为奖励,我注意到您在从CreateMedicineScreen屏幕保存时返回导航时遇到问题。这是因为您正在尝试从可组合项进行导航。文档中也有具体说明

您应该仅将 navigator() 作为回调的一部分调用,而不是作为可组合项本身的一部分,以避免在每次重组时调用 navigator()。

您也可以在这里使用副作用:

LaunchedEffect(key1 = Unit) {
    navController.popBackStack()
}
Run Code Online (Sandbox Code Playgroud)