4

When my application starts, I launch an animation. Now I would like to switch to another component (navbar) after 30 seconds. In my research, I saw that the delay function from the Kotlin Coroutines library is used, but it doesn't directly accept components (composables in Jetpack Compose), but rather simple functions. How can I achieve this if I want to call my navbar after a certain time?

1
  • 1
    I'm curious as to what the use-case for this arbitrary 30 second wait time is Commented Nov 5 at 7:33

2 Answers 2

7

delay is a suspend function and cannot be called from a composable. You have to wrap it in a LaunchedEffect first.

Furthermore, Compose is state-based, so whatever you do after the delay it must result in a changed state.

It could look something like this:

var waitUntil by rememberSaveable { mutableStateOf(Clock.System.now() + 30.seconds) }
var isWaiting by rememberSaveable { mutableStateOf(true) }

LaunchedEffect(waitUntil) {
    delay(waitUntil - Clock.System.now())
    isWaiting = false
}

if (isWaiting) {
    CircularProgressIndicator()
} else {
    Text("The wait is over.")
}

waitUntil is the time until it should be waited. Whenever that changes the LaunchedEffect is executed, delaying until that time is reached. Afterwards isWaiting is set to false, which will then trigger a recomposition, switching your UI from the progress indicator to a text.

The LaunchedEffect is cancelled and restarted in the following cases:

  1. Whenever waitUntil changes (because it is passed as a key parameter to the LaunchedEffect).
  2. After a configuration change (like a device rotation) results in a recreation of the activity and the entire Compose tree to be rebuilt.
  3. After system-initiated process death, i.e. when the user sends your app to the background and the Android system decides to kill the process to save resources. When the user brings the app back to the foreground, the LaunchedEffect continues to wait (if there is time left, of course).

Especially for the cases 2. and 3. it is important that waitUntil and isWaiting are stored using rememberSaveable, otherwise their state will be lost.

Sign up to request clarification or add additional context in comments.

Comments

-1
@Composable
fun AppRoot() {
    var showNav by rememberSaveable { mutableStateOf(false) }

    // Runs once while this composable is in the composition
    LaunchedEffect(Unit) {
        delay(30_000)            // 30 seconds without blocking the main thread
        showNav = true           // drive UI via state
    }

    if (showNav) {
        NavBar()                 // your target UI
    } else {
        SplashAnimation()        // your initial animation UI
    }
}

This is the easiest way to achieve it

1 Comment

Although you use rememberSaveable here, this still won't work on configuration changes (or system-initiated process death) because the LaunchedEffect is restarted everytime starting a new waiting period of 30 seconds. See my answer for more details and an alternative to wait for the correct amount of time.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.