I have an app that has a bottom nav , it has some tabs, now, from tab A I have a ticker that updates a value in the view every 5 seconds, when I switch to tab B I'm expecting that the scope of the viewmodel that is associated with the route A is no longer active to keep executing the code, alltought I expect the viewmodel to survive since there is no sense of removing it on tab change.
My current code
NavGraph
NavHost(navController, startDestination = BottomNavItem.HomeScreen.screen_route) {
composable(BottomNavItem.HomeScreen.screen_route) {
val homeViewModel: HomeViewModel = hiltViewModel()
val homeUiState = homeViewModel.uiState.collectAsState()
HomeScreen(uiState = homeUiState.value)
}
composable(BottomNavItem.FiatToCryptoScreen.screen_route) {
val viewModel: CryptoToFiatViewModel = hiltViewModel()
val uiState = viewModel.uiState.collectAsState()
CryptoToFiatScreen(uiState = uiState.value)
}
}
Now, HomeScreen takes HomeViewModel, which in the init block, it will fire a request every 5 seconds to get latest results from a coin
@HiltViewModel
class HomeViewModel @Inject constructor(private val repo: HomeRepository) : ViewModel() {
init {
updateFeaturedCoin()
}
private fun updateFeaturedCoin() {
viewModelScope.launch {
while (isActive) {
val featuredCoinPrice = repo.getTickerForCoin("BTC")
if (featuredCoinPrice.isSuccess) {
homeScreenState.update {
it.copy(
isLoading = false,
featuredCoinPrice = featuredCoinPrice.getOrNull()?.price
)
}
}
delay(5000)
}
}
}
....
}
Now, this is working fine, my problem is that when I change tabs, lets say, going to CryptoTofiatScreen, and if I put a breakpoint in the isActive condition, this will never be false, and I need this cicle to stop executing if I move to another tab, because now the HomeViewModel is not in the foreground anymore to update its view.
How can I tell HomeViewModel that is not active anymore if I switch to another composable in the route ?
I tought that scoping the viewmodel to its route will trigger an event to tell the viewmodel is not active anymore if I change routes
CodePudding user response:
One option would be, to use a displosableEffect
on the Home Composable, to start/stop viewmodel code:
DisposableEffect(Unit) {
homeViewModel.setIsActive(true)
onDispose {
homeViewModel.setIsActive(false)
}
}
This would require passing the viewModel instance to the component, instead of the just the state, like you are doing now.