I know snapshot state read error been discussed a ...
# compose
k
I know snapshot state read error been discussed a few times in the past already, but I am still not able to figure out what could cause the error in our setup. I do not think we are leaking the snapshot state before it is applied from within compose. The model we have right now is to create a snapshot state on background thread and pass it over to a composable within recyclerview to be rendered and then when composable accesses the state it leads to snapshot state error. Now if my understanding is correct a snapshot state instantiated on a different BG thread would not necessarily cause this issue, because the changes would be applied and reflected in global state right away? Here is what the stacktrace looks like, it's a bit largish 😢 (in thread) Also this is being observed on Android 14 except one issue reported on Android 11 if that matters
o
> Here is what the stacktrace looks like, it's a bit largish 😢 Please delete the stack trace from the channel message and put it into a follow-up thread message. Users will appreciate it, in particular those on mobile.
👍 1
k
Copy code
java.lang.IllegalStateException: Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied
    at androidx.compose.runtime.snapshots.SnapshotKt.readError(Snapshot.kt:1865)
    at androidx.compose.runtime.snapshots.SnapshotKt.readable(Snapshot.kt:1849)
    at androidx.compose.runtime.SnapshotMutableStateImpl.getValue(SnapshotState.kt:130)
    at androidx.compose.runtime.SnapshotStateKt__SnapshotStateKt.getValue
    at com.atlassian.mobilekit.editor.AdfEditorState.getEnabled(AdfEditorState.kt:60)
    at com.atlassian.mobilekit.editor.AdfEditorKt.AdfEditor-IqSm-MA(AdfEditor.kt:224)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeContentRendererKt$Renderer$1.invoke(NativeContentRenderer.kt:61)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeContentRendererKt$Renderer$1.invoke(NativeContentRenderer.kt:59)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
   ...
    at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeContentRendererKt.Renderer(NativeContentRenderer.kt:49)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeRendererContainer.RendererAndEffects(NativeRendererContainer.kt:195)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeRendererContainer.access$getReadingAidsRendererTextSelectionManager$p(NativeRendererContainer.kt:76)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeRendererContainer.access$RendererAndEffects(NativeRendererContainer.kt:76)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeRendererContainer$bind$1$1$1.invoke(NativeRendererContainer.kt:149)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeRendererContainer$bind$1$1$1.invoke(NativeRendererContainer.kt:130)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
   ...
    at com.atlassian.confluence.editor.theme.ConfluenceTheme$invoke$1.invoke(ConfluenceTheme.kt:31)
    at com.atlassian.confluence.editor.theme.ConfluenceTheme$invoke$1.invoke(ConfluenceTheme.kt:30)
    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 com.atlassian.confluence.editor.theme.ConfluenceTheme.invoke(ConfluenceTheme.kt:28)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeRendererContainer$bind$1$1.invoke(NativeRendererContainer.kt:130)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeRendererContainer$bind$1$1.access$invoke$lambda$0(NativeRendererContainer.kt:128)
    at com.atlassian.android.confluence.core.feature.nativeeditor.ui.NativeRendererContainer$bind$1$1.invoke(NativeRendererContainer.kt:128)
    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.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.ui.platform.ComposeView.Content(ComposeView.android.kt:428)
    at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:252)
    at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:251)
    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.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:194)
    at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:123)
    at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:122)
   ...
    at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
    at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:114)
    at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke(Wrapper.android.kt:156)
    at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke(Wrapper.android.kt:155)
   ...
    at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
    at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:155)
    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.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    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:3373)
    at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3363)
    at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
    at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations
    at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3363)
    at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3298)
    at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:587)
    at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:966)
    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:1099)
    at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:131)
    at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:181)
    at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.kt:314)
    at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.kt:192)
    at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:138)
    at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131)
    at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:1174)
    at android.view.View.dispatchAttachedToWindow(View.java:22257)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3494)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3501)
    at android.view.ViewGroup.addViewInner(ViewGroup.java:5328)
    at android.view.ViewGroup.addView(ViewGroup.java:5114)
    at android.view.ViewGroup.addView(ViewGroup.java:5054)
    at androidx.recyclerview.widget.RecyclerView$5.addView(RecyclerView.java:950)
    at androidx.recyclerview.widget.ChildHelper.addView(ChildHelper.java:131)
    at androidx.recyclerview.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:9430)
    at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:9388)
    at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:9375)
    at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1676)
    at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1622)
    at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:687)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:4591)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4346)
    at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4919)
    at android.view.View.layout(View.java:24722)
    at android.view.ViewGroup.layout(ViewGroup.java:6450)
    at androidx.swiperefreshlayout.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:689)
    at android.view.View.layout(View.java:24722)
    at android.view.ViewGroup.layout(ViewGroup.java:6450)
    at com.google.android.material.appbar.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:149)
    at com.google.android.material.appbar.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:43)
    at com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:2376)
    at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:918)
    at android.view.View.layout(View.java:24722)
    at android.view.ViewGroup.layout(ViewGroup.java:6450)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
    at android.view.View.layout(View.java:24722)
Note
AdfEditorState
here is UI snapshot state holder for composable and may get instantiated on BE thread before being passed to compose.
c
The only case I can think of that would produce this result is if the object was created after the snapshot for composition was already taken. Is this the issue you are running into and can you ensure that the only values visible to composition are ones that have been created before composition starts?
Specifically this error is reported when no valid record can be found for a mutable state object. A record is valid if was created before the current snapshot and has not been explicitly marked invalid. A record is explicitly marked invalid if the modification it is recording is for a snapshot that is open and has yet been applied. New state objects are given a record in the snapshot they are created in so if that snapshot has not been applied yet then the object is not valid to read in any other snapshot until the snapshot creating the object is applied. Trying to read it before the snapshot it was created in has applied results in this error.
1.7.0 will change this slightly. In 1.7.0 newly created objects will be accessible in all snapshots with their initial state. For
mutableStateOf()
and related objects, this is the state passed in as a parameter when creating the object. In a sense this means all object are assumed to have always existed with their default state, they are just now reachable. This makes the above read error much harder to hit.
🎉 1
k
> The only case I can think of that would produce this result is if the object was created after the snapshot for composition was already taken. Is this the issue you are running into and can you ensure that the only values visible to composition are ones that have been created before composition starts? Thanks a ton, this seems to be the root cause of the crash, I assumed that even if the object was created after snapshot was taken and if the object was not available in current snapshot we would fallback to looking in parent/global snapshot
c
This is somewhat what 1.7 does but not quite.
This was changed to make the scenario that you are running into a bit easier to handle as it is often inconvenient to ensure the object's creating snapshot is applied.
👍 1
173 Views