cashapp / molecule

Build a StateFlow stream using Jetpack Compose
https://cashapp.github.io/molecule/docs/1.x/
Apache License 2.0
1.85k stars 80 forks source link

How to access `LocalContext` or `stringResources` in a Presenter? #268

Closed amitkma closed 1 year ago

amitkma commented 1 year ago

I am trying to access Context inside a presenter composable using LocalContext.Current, But I couldn't make it work. I am getting the following error ->

java.lang.IllegalStateException: CompositionLocal LocalContext not present
    at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.noLocalProvidedFor(AndroidCompositionLocals.android.kt:168)
    at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.access$noLocalProvidedFor(AndroidCompositionLocals.android.kt:1)
    at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$LocalContext$1.invoke(AndroidCompositionLocals.android.kt:54)
    at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$LocalContext$1.invoke(AndroidCompositionLocals.android.kt:53)
    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
    at androidx.compose.runtime.LazyValueHolder.getCurrent(ValueHolders.kt:29)
    at androidx.compose.runtime.LazyValueHolder.getValue(ValueHolders.kt:31)
    at androidx.compose.runtime.ComposerImpl.resolveCompositionLocal(Composer.kt:2090)
    at androidx.compose.runtime.ComposerImpl.consume(Composer.kt:2058)
    at com.dotmystyle.android.ui.feature.auth.LoginPresenterKt.LoginPresenter(LoginPresenter.kt:133)
    at com.dotmystyle.android.ui.feature.auth.LoginViewModel.models(LoginViewModel.kt:48)
    at com.dotmystyle.android.ui.feature.auth.LoginViewModel.models(LoginViewModel.kt:41)
    at com.dotmystyle.android.ui.core.presentation.BaseViewModel$models$2$1.invoke(BaseViewModel.kt:38)
    at com.dotmystyle.android.ui.core.presentation.BaseViewModel$models$2$1.invoke(BaseViewModel.kt:37)
    at app.cash.molecule.MoleculeKt$launchMolecule$2$3.invoke(molecule.kt:164)
    at app.cash.molecule.MoleculeKt$launchMolecule$2$3.invoke(molecule.kt:163)

Any advise or workaround it?

JakeWharton commented 1 year ago

You would have to provide it yourself at the entry point to your composable running within Molecule. Molecule is not Android-specific nor does it have to run in a location where a Context is available. If you have one that you want to make available, you can provide it like a normal composition local at the root of your composition.

winterDroid commented 8 months ago

@amitkma did you get this working? Would be great to get an example as part of this thread as probably others will run into it as well.

JakeWharton commented 8 months ago

The docs for providing composition local values is here: https://developer.android.com/jetpack/compose/compositionlocal#providing-values. If you have a context instance you provide it as LocalContext at the root (or wherever) of your Molecule-based composition.

winterDroid commented 8 months ago

I tried multiple variations but none of them seem to work as expected. Can you provide an example?

JakeWharton commented 8 months ago

I forgot the built-in one returns Unit.

You have to use your own variant that returns the inner lambda value. See https://issuetracker.google.com/issues/271871288 for both the feature request as well as code you can use.