Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compose resources fail in Android Studio preview #4932

Closed
malbanese opened this issue Jun 6, 2024 · 6 comments · Fixed by #4965
Closed

Compose resources fail in Android Studio preview #4932

malbanese opened this issue Jun 6, 2024 · 6 comments · Fixed by #4965
Assignees
Labels
external bug Bug in an external software other than CM/Skiko resources

Comments

@malbanese
Copy link

This bug could be filed under a number of different trackers, it is filed on the google tracker as well.

Jetpack Compose version: 1.6.1

Jetpack Compose component(s) used:
com.android.compose.screenshot (alpha-1)
org.jetbrains.compose.components:components-resources

Android Studio Build: #AI-241.17011.79.2412.11910988

Kotlin version: 2.0.0

Steps to Reproduce or Code Sample to Reproduce:

The Android studio preview appears to fail utilizing string resources when in the following configuration:

  1. Set up a KMP / Compose multiplatform module with Compose Resources
  2. Add the new Compose screenshot testing library
  3. Set up screen shot test which utilizes a compose string resource
  4. Observe that screenshot testing works fine, but preview fails to render

Stack trace:

org.jetbrains.compose.resources.MissingResourceException: Missing resource with path: composeResources/testapp.ui.home.generated.resources/values/strings.commonMain.cvr
        at org.jetbrains.compose.resources.ResourceReader_androidKt$getPlatformResourceReader$1.getResourceAsStream(ResourceReader.android.kt:40)
        at org.jetbrains.compose.resources.ResourceReader_androidKt$getPlatformResourceReader$1.readPart(ResourceReader.android.kt:13)
        at org.jetbrains.compose.resources.StringResourcesUtilsKt$getStringItem$2.invokeSuspend(StringResourcesUtils.kt:30)
        at org.jetbrains.compose.resources.StringResourcesUtilsKt$getStringItem$2.invoke(StringResourcesUtils.kt)
        at org.jetbrains.compose.resources.StringResourcesUtilsKt$getStringItem$2.invoke(StringResourcesUtils.kt)
        at org.jetbrains.compose.resources.AsyncCache$getOrLoad$2$deferred$1$1.invokeSuspend(AsyncCache.kt:19)
        at _layoutlib_._internal_.kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at _layoutlib_._internal_.kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
        at _layoutlib_._internal_.kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:277)
        at _layoutlib_._internal_.kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:95)
        at _layoutlib_._internal_.kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:69)
        at _layoutlib_._internal_.kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
        at _layoutlib_._internal_.kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:48)
        at _layoutlib_._internal_.kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
        at org.jetbrains.compose.resources.ResourceState_blockingKt.rememberResourceState(ResourceState.blocking.kt:15)
        at org.jetbrains.compose.resources.StringResourcesKt.stringResource(StringResources.kt:27)
        at com.malba.testapp.ui.home.BasicParticipantsTestScreenshots.ParticipantNameScreenTest(BasicParticipantsTestScreenshots.kt:14)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at androidx.compose.ui.tooling.ComposableInvoker.invokeComposableMethod(ComposableInvoker.jvm.kt:181)
        at androidx.compose.ui.tooling.ComposableInvoker.invokeComposable(ComposableInvoker.jvm.kt:226)
        at androidx.compose.ui.tooling.ComposeViewAdapter$init$3$1$composable$1.invoke(ComposeViewAdapter.android.kt:504)
        at androidx.compose.ui.tooling.ComposeViewAdapter$init$3$1$composable$1.invoke(ComposeViewAdapter.android.kt:502)
        at androidx.compose.ui.tooling.ComposeViewAdapter$init$3$1.invoke(ComposeViewAdapter.android.kt:539)
        at androidx.compose.ui.tooling.ComposeViewAdapter$init$3$1.invoke(ComposeViewAdapter.android.kt:497)
        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.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
        at androidx.compose.ui.tooling.InspectableKt.Inspectable(Inspectable.android.kt:61)
        at androidx.compose.ui.tooling.ComposeViewAdapter$WrapPreview$1.invoke(ComposeViewAdapter.android.kt:444)
        at androidx.compose.ui.tooling.ComposeViewAdapter$WrapPreview$1.invoke(ComposeViewAdapter.android.kt:443)
        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.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
        at androidx.compose.ui.tooling.ComposeViewAdapter.WrapPreview(ComposeViewAdapter.android.kt:438)
        at androidx.compose.ui.tooling.ComposeViewAdapter.access$WrapPreview(ComposeViewAdapter.android.kt:124)
        at androidx.compose.ui.tooling.ComposeViewAdapter$init$3.invoke(ComposeViewAdapter.android.kt:497)
        at androidx.compose.ui.tooling.ComposeViewAdapter$init$3.invoke(ComposeViewAdapter.android.kt:494)
        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.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:109)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
        at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:186)
        at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:119)
        at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:118)
        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.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
        at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:110)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke(Wrapper.android.kt:139)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke(Wrapper.android.kt:138)
        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.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:248)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:138)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:123)
        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.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:90)
        at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3302)
        at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3235)
        at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:725)
        at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:1071)
        at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:633)
        at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:619)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:123)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:114)
        at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:1289)
        at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:114)
        at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:164)
        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:121)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:114)
        at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:1364)
        at android.view.View.dispatchAttachedToWindow(View.java:21980)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3490)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497)
        at android.view.AttachInfo_Accessor.setAttachInfo(AttachInfo_Accessor.java:44)
        at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:372)
        at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:454)
        at com.android.tools.idea.layoutlib.LayoutLibrary.createSession(LayoutLibrary.java:120)
        at com.android.tools.rendering.RenderTask.createRenderSession(RenderTask.java:777)
        at com.android.tools.rendering.RenderTask.lambda$inflate$6(RenderTask.java:925)
        at com.android.tools.rendering.RenderExecutor$runAsyncActionWithTimeout$3.run(RenderExecutor.kt:203)
        at com.android.tools.rendering.RenderExecutor$PriorityRunnable.run(RenderExecutor.kt:317)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at java.base/java.lang.Thread.run(Thread.java:840)
@malbanese malbanese added bug Something isn't working submitted labels Jun 6, 2024
@terrakok terrakok added resources external bug Bug in an external software other than CM/Skiko and removed bug Something isn't working submitted labels Jun 6, 2024
@terrakok terrakok self-assigned this Jun 6, 2024
@terrakok
Copy link
Collaborator

terrakok commented Jun 6, 2024

I'm pretty sure it is a duplicate of this
#4476

@malbanese
Copy link
Author

@terrakok Looks similar.

Would it be viable to change the ResourceReader interface and local composition to not be internal?

internal val LocalResourceReader = staticCompositionLocalOf { DefaultResourceReader }

It's not a perfect solution, but would at least allow for customization when needed.

@terrakok
Copy link
Collaborator

terrakok commented Jun 6, 2024

How will it help you?

@malbanese
Copy link
Author

In this case, it would help me get preview code working by allowing me to override it.

My current solution is to expose my own composition local with my own version of the resource fetching methods, which ultimately call into the JB versions (or not).

Beyond that, I think allowing for overrides of it does present some interesting opportunities, but they would all be niche use cases. I also admit, it would mean exposing the internals of resource storage, which may not be something the team wants to do.

For example:

  1. In past apps we've exposed an option which allows the debug apps to swap string values with the backing keys, for visual debugging purposes.

  2. It also opens up interesting opportunities to allow for remotely updatable strings, possibly without creating an explicit wrapper API.

Both points can be done by just wrapping the API, but they are interesting use-cases, at least.

@terrakok
Copy link
Collaborator

#4965

@okushnikov
Copy link

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external bug Bug in an external software other than CM/Skiko resources
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants