1

In my plan, I hope to display Home UI when I run an app first, a user can open Purchase UI by clicking a button on Home UI. And more, Purchase UI will be displayed automatically if the app is expired when I run the app first.

In Code A, navActions.navigateToPurchase() is invoked in both fun NavGraph(...) and fun ScreenHome(...).

The app will crash if I don't wrap navActions.navigateToPurchase() with LaunchedEffect in fun NavGraph(), why? You can see Error Logs below.

Code A

@Composable
fun NavGraph(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(),
    navActions: NavigationActions = remember(navController) { NavigationActions(navController) },
    startDestination: String = RouteDestinations.HOME
) {
    val currentNavBackStackEntry by navController.currentBackStackEntryAsState()
    val currentRoute = currentNavBackStackEntry?.destination?.route ?: startDestination

    NavHost(
        navController = navController,
        startDestination = startDestination,
        modifier = modifier
    ) {

        composable(
            RouteDestinations.HOME
        ) {
            if (isAppExpired(LocalContext.current)) {
                LaunchedEffect(Unit) {
                    navActions.navigateToPurchase()
                }
            } else {
                ScreenHome(
                    navActions = navActions
                )
            }
        }

        composable(
            RouteDestinations.PURCHASE
        ) { entry ->
            ScreenPurchase(
                onBack = { navController.popBackStack() }
            )
        }
    }
}



@Composable
fun ScreenHome(
     navActions: NavigationActions
) {
    Button(
        onClick = { navActions.navigateToPurchase() }
    ) {
        Text("Nav to Purchase")
    }
}

class NavigationActions(private val navController: NavHostController) {
    fun navigateToHome(){
        navController.navigate(RouteDestinations.HOME)
    }   
 
    fun navigateToPurchase(){
        navController.navigate(RouteDestinations.PURCHASE)
    }
}

class ActivityMain : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SoundMeterTheme {
                Surface(color = MaterialTheme.colors.background) {
                    NavGraph()
                }
            }
        }
    }
 }

Error Logs

2022-08-01 19:26:54.271 5611-5655/info.dodata.soundmeter E/cr_VariationsUtils: Failed reading seed file "/data/user/0/info.dodata.soundmeter/app_webview/variations_seed": /data/user/0/info.dodata.soundmeter/app_webview/variations_seed (No such file or directory)
2022-08-01 19:26:54.500 5611-5698/info.dodata.soundmeter E/chromium: [ERROR:gl_surface_egl.cc(335)] eglChooseConfig failed with error EGL_SUCCESS
2022-08-01 19:26:55.288 5611-5704/info.dodata.soundmeter E/eglCodecCommon: GoldfishAddressSpaceHostMemoryAllocator: ioctl_ping failed for device_type=5, ret=-1
2022-08-01 19:26:55.510 5611-5698/info.dodata.soundmeter E/chromium: [ERROR:gl_surface_egl.cc(335)] eglChooseConfig failed with error EGL_SUCCESS
2022-08-01 19:26:55.624 5611-5611/info.dodata.soundmeter E/AndroidRuntime: FATAL EXCEPTION: main
    Process: info.dodata.soundmeter, PID: 5611
    java.util.NoSuchElementException: List contains no element matching the predicate.
        at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:180)
        at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:141)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.animation.CrossfadeKt$Crossfade$4$1.invoke(Crossfade.kt:115)
        at androidx.compose.animation.CrossfadeKt$Crossfade$4$1.invoke(Crossfade.kt:110)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.animation.CrossfadeKt.Crossfade(Crossfade.kt:124)
        at androidx.compose.animation.CrossfadeKt.Crossfade(Crossfade.kt:55)
        at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:141)
        at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:67)
        at info.dodata.soundmeter.presentation.ui.NavGraphKt.NavGraph(NavGraph.kt:38)
        at info.dodata.soundmeter.presentation.ui.NavGraphKt$NavGraph$3.invoke(Unknown Source:21)
        at info.dodata.soundmeter.presentation.ui.NavGraphKt$NavGraph$3.invoke(Unknown Source:10)
        at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:157)
        at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2270)
        at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2530)
        at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3038)
        at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3024)
        at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:252)
        at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source:1)
        at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3024)
        at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:2999)
        at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:709)
        at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:876)
        at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:107)
        at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:485)
        at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:454)
        at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
        at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:947)
        at android.view.Choreographer.doCallbacks(Choreographer.java:761)
        at android.view.Choreographer.doFrame(Choreographer.java:693)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
        Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.runtime.PausableMonotonicFrameClock@186f44, StandaloneCoroutine{Cancelling}@ee6482d, AndroidUiDispatcher@1d8a162]
HelloCW
  • 843
  • 22
  • 125
  • 310
  • You need to first what your Exception and crash logs to know better but `NavHost`can call `composable{}` more than once. That might be the issue. https://stackoverflow.com/questions/69176617/jetpack-compose-navhost-recomposition-composable-multiple-times – Thracian Jul 08 '22 at 11:23
  • Thanks! I add Error Log in the question. – HelloCW Jul 08 '22 at 11:32
  • @HelloCW When do you want to navigate to Purchase Screen? There must be some event in HomeScreen? – Arpit Shukla Jul 12 '22 at 10:50
  • check out [this answer](https://stackoverflow.com/a/71159855/3585796) – Phil Dukhov Jul 13 '22 at 06:51

1 Answers1

2

for my simple knowledge, the navigate function need to be called in the function or click event, navActions.navigateToPurchase() was not called in any of the above, because function marked Composable is not like normal function or click event, that is why LauchEffect is used as side effect for such scenarios as explained by jetpack compose tutorials on google developer guide

masokaya
  • 589
  • 4
  • 10