Home > Net >  Screen Flashes when using datastore to update UI
Screen Flashes when using datastore to update UI

Time:01-26

I am using Jetpack Compose to build my UI and when a user enters the app, the app will first check whether he/she is a first time user.

If it's a first time user, it will load the ScreenStarter() composable. Else, it will load the AppContent() composable.

My code is like that:

App.kt

 {
    /**
     * This is the Main MES app that will
     * determine which screen content to show
     **/

    /** Load the app settings from datastore **/
    val appSettings = application.datastore.data.collectAsState(initial = MesAppSettings()).value

    /** Set the correct app theme that the user has set **/
    val darkTheme = when (appSettings.appTheme) {
        AppTheme.FOLLOW_SYSTEM -> isSystemInDarkTheme()
        AppTheme.DARK -> true
        AppTheme.LIGHT -> false
    }

    MesTheme(
        darkTheme = darkTheme // Load the app theme
    ) {

        
        /** Determine screen content **/
        if (!appSettings.isFirstTimeLogging) {
            AppContent(
                application = application,
                appSettings = appSettings,
                widthSizeClass = widthSizeClass
            )
        } else {
            ScreenStarter(
                application = application,
                requestMultiplePermissions = requestMultiplePermissions
            )
        }

    }
}

The issue here is that, if it is a recurrent user and he/she opens the app, the screen flashes, and we can briefly see the ScreenStarter() composable before it switches to the AppContent() composable. I think this happens because the data is fetched asynchronously from the data store.

Can someone advise on how to fix this ?

CodePudding user response:

Use some different initial value for appSettings. You can use null for example, then if appSettings is null, show blank screen or some progress indicator, if it's not null, you know that correct data has been loaded from storage and you can show content based on your logic.

CodePudding user response:

One way to fix this issue is by using the remember function from the Jetpack Compose library. The remember function allows you to remember the state of a composable, so that it doesn't get recreated when the parent composable is recreated.

You can use remember to wrap the composable that is checking whether the user is a first-time user, like this:

remember {
    if (!appSettings.isFirstTimeLogging) {
        AppContent(
            application = application,
            appSettings = appSettings,
            widthSizeClass = widthSizeClass
        )
    } else {
        ScreenStarter(
            application = application,
            requestMultiplePermissions = requestMultiplePermissions
        )
    }
}

This will ensure that the composable that checks whether the user is a first-time user is only created once, and the state is remembered across re-creations.

Another way to handle this would be to use a loading state, by displaying a loading screen until the appSettings data is loaded and then switch to either the AppContent or ScreenStarter composable.

You can use the mutableStateOf(false) to maintain a loading state, and check that in the if condition.

val loaded = mutableStateOf(false)
val appSettings = application.datastore.data.collectAsState(initial = MesAppSettings()).value

when (loaded.value) {
    true -> {
        if (!appSettings.isFirstTimeLogging) {
            AppContent(
                application = application,
                appSettings = appSettings,
                widthSizeClass = widthSizeClass
            )
        } else {
            ScreenStarter(
                application = application,
                requestMultiplePermissions = requestMultiplePermissions
            )
        }
    }
    false -> {
        LoadingScreen()
    }
}

In this case, when the data is loaded, you can set the loaded state to true, which will switch the composable to either AppContent or ScreenStarter.

  • Related