Giter Site home page Giter Site logo

`ComposeView` and `IllegalStateException: You can consumeRestoredStateForKey only after super.onCreate of corresponding component` about workflow-kotlin HOT 9 CLOSED

rjrjr avatar rjrjr commented on June 11, 2024
`ComposeView` and `IllegalStateException: You can consumeRestoredStateForKey only after super.onCreate of corresponding component`

from workflow-kotlin.

Comments (9)

rjrjr avatar rjrjr commented on June 11, 2024

Here's the config change variant, first bullet above. I believe every frame here is open source, either Androidx or Workflow.

java.lang.IllegalStateException: You can consumeRestoredStateForKey only after super.onCreate of corresponding component
        at androidx.savedstate.SavedStateRegistry.consumeRestoredStateForKey(SavedStateRegistry.kt:72)
        at androidx.compose.ui.platform.DisposableSaveableStateRegistry_androidKt.DisposableSaveableStateRegistry(DisposableSaveableStateRegistry.android.kt:75)
        at androidx.compose.ui.platform.DisposableSaveableStateRegistry_androidKt.DisposableSaveableStateRegistry(DisposableSaveableStateRegistry.android.kt:54)
        at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:105)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:157)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:156)
        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.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:156)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:140)
        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.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:78)
        at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3248)
        at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3238)
        at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
        at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown:1)
        at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3238)
        at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3173)
        at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:587)
        at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:950)
        at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:519)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:140)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131)
        at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:1060)
        at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:131)
        at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:182)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:360)
        at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:271)
        at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:313)
        at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:151)
        at androidx.lifecycle.LifecycleRegistry.setCurrentState(LifecycleRegistry.java:121)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.updateLifecycle$wf1_core_android(WorkflowLifecycleOwner.kt:203)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.updateLifecycle$wf1_core_android$default(WorkflowLifecycleOwner.kt:193)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.onStateChanged(WorkflowLifecycleOwner.kt:175)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:360)
        at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:271)
        at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:313)
        at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:151)
        at androidx.lifecycle.LifecycleRegistry.setCurrentState(LifecycleRegistry.java:121)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.updateLifecycle$wf1_core_android(WorkflowLifecycleOwner.kt:203)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.updateLifecycle$wf1_core_android$default(WorkflowLifecycleOwner.kt:193)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.onStateChanged(WorkflowLifecycleOwner.kt:175)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:360)
        at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:271)
        at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:313)
        at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:151)
        at androidx.lifecycle.LifecycleRegistry.setCurrentState(LifecycleRegistry.java:121)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.updateLifecycle$wf1_core_android(WorkflowLifecycleOwner.kt:203)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.updateLifecycle$wf1_core_android$default(WorkflowLifecycleOwner.kt:193)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.onStateChanged(WorkflowLifecycleOwner.kt:175)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:360)
        at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:202)
        at com.squareup.workflow1.ui.androidx.RealWorkflowLifecycleOwner.onViewAttachedToWindow(WorkflowLifecycleOwner.kt:161)
        at android.view.View.dispatchAttachedToWindow(View.java:15544)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2916)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2923)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2923)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2923)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2923)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2923)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2923)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2923)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1530)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1258)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6351)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874)
        at android.view.Choreographer.doCallbacks(Choreographer.java:686)
        at android.view.Choreographer.doFrame(Choreographer.java:621)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Method.java:-2)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

from workflow-kotlin.

rjrjr avatar rjrjr commented on June 11, 2024

Fixed one variant (not the one whose stack trace is above) by eliminating a spot where we were driving a WorkflowViewStub via an RxJava Observable stream. Replaced that with direct calls to ScreenViewHolder.show, which also eliminates one use of WorkflowLifecycleOwner.

Absolutely no idea why that fixed anything, but at least we're getting an idea of what to wiggle.

from workflow-kotlin.

rjrjr avatar rjrjr commented on June 11, 2024

Fixed one variant

False.

from workflow-kotlin.

rjrjr avatar rjrjr commented on June 11, 2024

Found this comment in DisposableSaveableStateRegistry, while debugging where the SaveableStateRegistry:-1 key comes from (the key that causes the exception to be thrown from SavedStateRegistry, and thank you androidx team for a characteristically useless exception message):

    // The view id of AbstractComposeView is used as a key for SavedStateRegistryOwner. If there
    // are multiple AbstractComposeViews in the same Activity/Fragment with the same id(or with
    // no id) this means only the first view will restore its state. There is also an internal
    // mechanism to provide such id not as an Int to avoid ids collisions via view's tag. This
    // api is currently internal to compose:ui, we will see in the future if we need to make a
    // new public api for that use case.

Sure enough, if I provide generated (and therefore useless) ids for each ComposeView we instantiate, the crash goes away. This also breaks view persistence for Compose, but we're practically there already.

from workflow-kotlin.

rjrjr avatar rjrjr commented on June 11, 2024

Do we need to introduce a WorkflowSavedStateRegistryAggregator at every ComposeView boundary?

from workflow-kotlin.

rjrjr avatar rjrjr commented on June 11, 2024

Non-conflicting id's "fix" only worked once. How?

from workflow-kotlin.

rjrjr avatar rjrjr commented on June 11, 2024

More likely I'm punchy and missed a step in the repro recipe.

from workflow-kotlin.

rjrjr avatar rjrjr commented on June 11, 2024

We've found other, simpler recipes. AndroidView is not in the chain, dialog windows always are. Current theory is that on config change, dialog contents are getting restored before the activity is resumed -- maybe some kind of surprising depth first behavior where android lifecycle resumes children before parents?

Going to try making dialogs use the activity context as the parent lifecycle owner, instead of the owner of the BodyAndOverlaysContainer. That does seem very wrong, and prone to failing to tear down dialogs when their container vanishes, but let's see what happens.

from workflow-kotlin.

rjrjr avatar rjrjr commented on June 11, 2024

Possible fix! #1003. Running it against our internal test suite now.

from workflow-kotlin.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.