adrielcafe / voyager

🛸 A pragmatic navigation library for Jetpack Compose
https://voyager.adriel.cafe
MIT License
2.54k stars 129 forks source link

Crash on implementing ScreenLifecycleOwner #472

Open skymansandy opened 1 month ago

skymansandy commented 1 month ago

I'm trying to use this API to listen to screen being disposed. https://voyager.adriel.cafe/lifecycle/#screenlifecycleowner

Getting this crash whenever trying to navigate to the screen. Any idea what is missed?

Library version: 1.1.0-beta-02

Crashlog:

FATAL EXCEPTION: main
                 Process: digital.allen.study.debug, PID: 19551
                 java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/compose/runtime/internal/ComposableFunction2;
                    at com.sampleapp.ui.full_screen.MyScreenLifecycleOwner.ProvideBeforeScreenContent(FullScreen.kt:48)
                    at cafe.adriel.voyager.core.lifecycle.MultipleScreenLifecycleOwnerUtilKt.RecursiveProvideBeforeScreenContent(multipleScreenLifecycleOwnerUtil.kt:44)
                    at cafe.adriel.voyager.core.lifecycle.MultipleScreenLifecycleOwnerUtilKt.MultipleProvideBeforeScreenContent(multipleScreenLifecycleOwnerUtil.kt:16)
                    at cafe.adriel.voyager.navigator.Navigator.saveableState(Navigator.kt:146)
                    at cafe.adriel.voyager.transitions.ScreenTransitionKt$ScreenTransition$9.invoke(ScreenTransition.kt:182)
                    at cafe.adriel.voyager.transitions.ScreenTransitionKt$ScreenTransition$9.invoke(ScreenTransition.kt:169)
                    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:139)
                    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                    at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1$5.invoke(AnimatedContent.kt:755)
                    at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1$5.invoke(AnimatedContent.kt:744)
                    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:118)
                    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                    at androidx.compose.animation.AnimatedVisibilityKt.AnimatedEnterExitImpl(AnimatedVisibility.kt:818)
                    at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1.invoke(AnimatedContent.kt:726)
                    at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1.invoke(AnimatedContent.kt:709)
                    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                    at androidx.compose.animation.AnimatedContentKt.AnimatedContent(AnimatedContent.kt:768)
                    at androidx.compose.animation.AnimatedContentKt.AnimatedContent(AnimatedContent.kt:141)
                    at cafe.adriel.voyager.transitions.ScreenTransitionKt.ScreenTransition(ScreenTransition.kt:150)
                    at cafe.adriel.voyager.transitions.ScreenTransitionKt$ScreenTransition$10.invoke(Unknown Source:25)
                    at cafe.adriel.voyager.transitions.ScreenTransitionKt$ScreenTransition$10.invoke(Unknown Source:14)
                    at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:192)
                    at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2556)
                    at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2827)
                    at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3314)
                    at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:3265)
                    at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:940)
                    at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1155)
                    at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:127)
                    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:583)
                    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:551)
                    at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:41)
                    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:1337)
                    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1348)
                    at android.view.Choreographer.doCallbacks(Choreographer.java:952)
skymansandy commented 1 month ago

Also, @adrielcafe would it be better if All Screens by default has the lifecycle callbacks like onCreate/onStart/onResume/...../onDestroy like fragments/activities have?

skymansandy commented 1 month ago

Update:

I think the crash had something to do with using Composable marked functions in subclasses of a base class. (https://issuetracker.google.com/issues/316196500)

I had to override ProvideBeforeScreenContent as well in the subclass.

But I'm still not getting onDispose callback.

class HomeScreen : Screen, ScreenLifecycleProvider {

    override fun getLifecycleOwner() = object : ScreenLifecycleOwner {
        override fun onDispose(screen: Screen) {
            println("HomeScreen is being disposed")
        }

        @Composable
        override fun ProvideBeforeScreenContent(
            provideSaveableState: @Composable (suffixKey: String, content: @Composable () -> Unit) -> Unit,
            content: @Composable () -> Unit
        ) {
            super.ProvideBeforeScreenContent(provideSaveableState, content)
        }
    }

    @Composable
    override fun Content() {
        val navigator = LocalNavigator.currentOrThrow

        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center,
        ) {
            Button(onClick = { navigator.push(ProfileScreen()) }) {
                Text("Home Screen")
            }
        }
    }
}