Problem:-
I have a composable WelcomeScreen that shows a finish button at the end and when the user clicks the finish button it calls a function from the WelcomeScreenViewModel that launches a viewModelScope coroutine to save a boolean value using android DataStore.
The problem I'm facing is that when the button is clicked the navigation works but the WelcomeScreenViewModel doesn't launch, after some digging I understood the problem is caused by NavController.popBackStack() which removes the WelcomeScreen from the stack which in turn kills the WelcomeScreenViewModel which in turn due to viewModelScope being a lifecycle aware component it cancels all the coroutines jobs related to the viewModel when onClear() is called which doesn't give the chance for the coroutine to launch before onClear() is called.
Solutions I tried:-
I have tired to call
NavController.popBackStack()from arememberCoroutineScope().launchblock which allowed for the ViewModel coroutine to be launched but transition fromWelcomeScreento the next screen didn't work.I tried calling
NavController.popBackStack()after the call toWelcomeScreenViewModelcoroutine but that didn't make any difference.
I'm stuck, I've been trying to find a workaround and fix this issue for hours and banging my head against the wall.
Here's some code:-
WelcomeScreen
@Composable
fun WelcomeScreen(
navHostController: NavHostController,
welcomeViewModel: WelcomeScreenViewModel = hiltViewModel()
) {
val pages = listOf(
WelcomeScreenPages.PageContent(
imageResource = R.drawable.greetings,
title = stringResource(id = R.string.greeting_page_title),
description = stringResource(R.string.greetings_page_description)
),
WelcomeScreenPages.PageContent(
imageResource = R.drawable.explore,
title = stringResource(R.string.explore_page_title),
description = stringResource(R.string.explore_page_description)
),
WelcomeScreenPages.PageContent(
imageResource = R.drawable.power,
title = stringResource(R.string.power_page_title),
description = stringResource(R.string.power_page_description)
)
)
val pagerState = rememberPagerState()
Column(
modifier = Modifier
.fillMaxWidth()
.background(color = welcomeScreenBackgroundColor)
) {
HorizontalPager(
modifier = Modifier.weight(10f),
count = pages.size,
state = pagerState
) { page ->
Page(welcomeScreenPage = pages[page])
}
HorizontalPagerIndicator(
modifier = Modifier
.weight(1f)
.align(Alignment.CenterHorizontally),
pagerState = pagerState,
activeColor = activeIndicatorColor,
inactiveColor = inactiveIndicatorColor,
indicatorWidth = PAGING_INDICATOR_WIDTH,
spacing = PAGING_INDICATOR_SPACING
)
FinishButton(
modifier = Modifier
.weight(1f),
pagerState = pagerState,
lastPage = pages.size - 1
) {
navHostController.popBackStack()
navHostController.navigate(Screen.Home.route)
welcomeViewModel.welcomePageCompleted(isCompleted = true)
}
}
}
WelcomeScreenViewModel
@HiltViewModel
class WelcomeScreenViewModel @Inject constructor(private val useCase: UseCase): ViewModel(){
private val TAG = "WelcomeScreenViewModel"
fun welcomePageCompleted(isCompleted: Boolean){
viewModelScope.launch(Dispatchers.IO) {
useCase.welcomePageCompletedUseCase(isCompleted = isCompleted)
Log.i(TAG, "Coroutine triggered! ")
Log.i(TAG,"welcome page state saved! $isCompleted")
}
}
}