user18208230
user18208230

Reputation: 33

LaunchedEffect no longer triggering after navigating away and back to the Composable

I have a LaunchedEffect in my Composable like following. I want it to trigger every time a new instance of ViewEffect.Action is set in the viewEffect LiveData.

val viewEffect by viewModel.viewEffect.observeAsState()

when (viewEffect) {
    is ViewEffect.Action -> {
        LaunchedEffect(viewEffect) {
            viewModel.takeAction(viewEffect as ViewEffect.Action)
        }
    }
}

This results in 2 odd behaviors:

  1. When I navigate to a different Composable using NavHostController and come back, the LaunchedEffect is executed again even though viewEffect hasn't changed.

  2. Even weirder, after coming back to the original Composable, after the first execution, the LaunchedEffect will never trigger again, even if the value of viewEffect changes. This behavior is only seen after navigating away and back.

(More context) ViewEffect.Action has a custom equals method which compares by reference to allow it to fire multiple times with same data values:

data class Action(val info: Info) : ViewEffect() {
    // Override equals so that LaunchedEffect compares keys by reference
    // when deciding whether to launch
    override fun equals(other: Any?): Boolean {
        return this === other
    }

    override fun hashCode(): Int {
        return info.hashCode()
    }
}

I tried clearing the value of viewEffect LiveData before navigating away from the Composable, and this fixed the first issue, but the second one still persisted. I'm also hoping there is a better solution than this.

Upvotes: 1

Views: 1460

Answers (1)

bylazy
bylazy

Reputation: 1305

When you navigate to a different Composable using NavHostController, your LaunchedEffect leaves the composition and a coroutine with the block of code passed as a parameter will be cancelled. When you come back, the LaunchedEffect is executed again even though key(s) hasn't changed and that's the way it's meant to be.

So 1st oddity is normal behavior.

The 2nd oddity may be caused by the fact that the LaunchedEffect is wrapped in when block, try this way:

LaunchedEffect(viewEffect) {
    when (viewEffect) {
        is ViewEffect.Action -> {
            viewModel.takeAction(viewEffect as ViewEffect.Action)
        }
    }
}

Upvotes: 0

Related Questions