0

I'm utilizing the DataStore value isLanguageSelected to determine whether to display the HomeScreen() composable or the LanguageScreen(). While the functionality works as intended, I'm encountering an issue where there's a flickering effect when transitioning to the LanguageScreen(). For instance, if isLanguageSelected is true in DataStore, it briefly displays the LanguageScreen() composable before showing the HomeScreen(), resulting in the flickering effect. Here's the relevant code:

@Composable
fun MyAppNavHost(
    navController: NavHostController = rememberNavController()
) {

    val dataStore = LocalContext.current.dataStore
    val userPreferencesRepository = UserPreferencesRepository(dataStore)
    val isLanguageSelected by userPreferencesRepository.isLanguageSelected.collectAsState(initial = false)
    
        NavHost(
            navController = navController,
            startDestination = if (!isLanguageSelected) LanguageScreen.route else HomeScreen.route
        ){
            composable(HomeScreen.route) {
                HomeScreen()
            }
            composable(LanguageScreen.route) {
                LanguageScreen()
            }
        }
}

I've attempted a solution where I check if the DataStore is loaded first, but I'm not satisfied with the approach. I'm seeking a more professional alternative. Here's the code I tried:

var isDataLoaded by remember { mutableStateOf(false) }

LaunchedEffect(dataStore) {
    delay(1000)  
    isDataLoaded = true
}

if (isDataLoaded)
    NavHost(){} 
4
  • try removing the if in startDestination. make home start destination and then based on the state use navController to navigate to select language screen fvilarino.medium.com/… Commented Apr 7, 2024 at 10:27
  • Why UserPreferencesRepository(dataStore) is not remembered Commented Apr 8, 2024 at 2:33
  • @Srimani789 Am i supposed to do that? If yes please enlighten the details. Thanks Commented Apr 8, 2024 at 2:38
  • @CODAR747 remember = store the value just in case recompose is called. So if you not remember the repository object then it will re-create for every recomposition. Usually repos are part of viewmodel Commented Apr 8, 2024 at 4:50

1 Answer 1

0

I think the flickering that you are observing is caused by this line:

collectAsState(initial = false)

This will make the Flow return false initally, resulting in the LanguageScreen being shown. Then, the actual value is read out of the DataStore. The whole NavHost will recompose with the new startDestination set to HomeScreen.

I am not sure if you actually need a Flow if you just want to read a single value out of the DataStore when starting the App.

One typical way to solve this problem is by adding a loading screen Composable. Set the loading Composable as the startDestination. Then, in that Composable, check whether the language has already been selected.

@Composable
LoadingScreen(
    onLanguageSet: () -> Unit,
    onLanguageNotSet: () -> Unit
) {

    LaunchedEffect(Unit) {
        // read value from the datastore ...
        if (languageSelected) {
            onLanguageSet()
        } else {
            onLanguageNotSet()
        }
    }

    Box(
        contentAlignment = Alignment.Center,
        modifier = Modifier.fillMaxSize()
    ) {
        CircularProgressIndicator()
    }
}

Then, in your NavHost, add this Composable as a new destination:

NavHost(
    navController = navController,
    startDestination = LoadingScreen.route
) {
    composable(LoadingScreen.route) {
        LoadingScreen(
            onLanguageSet = {
                navController.navigate(HomeScreen.route) {
                    popUpTo(LoadingScreen.route) {
                        inclusive = true  // prevent going back to LoadingScreen
                    }
                }
            }, 
            onLanguageNotSet = {
                navController.navigate(LanguageScreen.route) {
                    popUpTo(LoadingScreen.route) {
                        inclusive = true
                    }
                }
            }
        )
    }
    composable(HomeScreen.route) {
        HomeScreen()
    }
    composable(LanguageScreen.route) {
        LanguageScreen()
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.