Issue
I am doing a simple app in compose in order to learn in, the app has two viewModels
, ItemListViewModel
that shows a list of items and ItemCreateViewModel
that let you create the item, items are stored in Room.
My issue is that when I open the app the list is shown, but after I open the detail and create a new Item, going back the the first (ItemListViewModel
) the list is not updated.
@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
)
}
}
}
and here the Compose view
@Composable
fun ItemList(
viewModel: ItemListViewModel,
navController: NavController
) {
val items = viewModel.uiState.items
ShowItems(items) // <--- this is not called
}
this is the repository fun
fun fetchItems(): Flow<List<ItemEntity>>
If I kill the app and restart it, I can see the new created item.
Solution
Your list doesn't get refreshed because your coroutine gets canceled when navigating to your CreateMedicineScreen
screen. When you go back to your MedicineList
screen, the init
doesn't get called (since it's the same ViewModel instance). You could expose the refresh as a public method from your ViewModel (as you started in your code) and call it from your composable using a 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)
}
}
When you'll pop back to your screen, MedicineList
will recompose and execute once the fetch method.
As a bonus, I've noticed you had an issue with your navigation back when saving from the CreateMedicineScreen
screen. It's because you're trying to navigate from a composable. It's also specified in the 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.
You could use a side effect here as well:
LaunchedEffect(key1 = Unit) {
navController.popBackStack()
}
Answered By - ptitvinou
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.