Thread
#compose
    Walter Berggren

    Walter Berggren

    1 year ago
    Hi! I’m running into the following exception when executing
    hiltNavGraphViewModel()
    in a NavHost:
    Expected an activity context for creating a HiltViewModelFactory for a NavBackStackEntry but instead found: android.app.ContextImpl@78d1695
    The culprit is overriding the locale in the main activity to be able to switch languages on the fly. My main activity’s setContent looks like this:
    setContent {
        OverrideLocale(language.value, this) {
            Navigation()
        }
    }
    With
    OverrideLocale
    defined as following:
    @Composable
    private fun OverrideLocale(language: String, mainActivity: AppCompatActivity, content: @Composable () -> Unit) {
        val configuration = LocalConfiguration.current
        configuration.setLocale(Locale(language))
        val context = LocalContext.current.createConfigurationContext(configuration)
        CompositionLocalProvider(
            LocalOnBackPressedDispatcherOwner provides mainActivity,
            LocalConfiguration provides configuration,
            LocalContext provides context
        ) {
            content()
        }
    }
    Looking at the exception’s stack trace the
    HiltViewModelFactory
    never seems to reach a point where it deems the context to be an activity:
    @JvmName("create")
    public fun HiltViewModelFactory(
        context: Context,
        navBackStackEntry: NavBackStackEntry
    ): ViewModelProvider.Factory {
        val activity = context.let {
            var ctx = it
            while (ctx is ContextWrapper) {
                if (ctx is Activity) {
                    return@let ctx
                }
                ctx = ctx.baseContext
            }
            throw IllegalStateException(
                "Expected an activity context for creating a HiltViewModelFactory for a " +
                    "NavBackStackEntry but instead found: $ctx"
            )
        }
    [...]
    I.e.,
    return@let ctx
    above is never called.
    Any thoughts on how the locale can be overridden correctly? Removing
    OverrideLocale
    makes the code run just fine.
    FunkyMuse

    FunkyMuse

    1 year ago
    Did you add
    @AndroidEntryPoint
    to the activity hosting the composables?
    Albert Chang

    Albert Chang

    1 year ago
    Walter Berggren

    Walter Berggren

    1 year ago
    @FunkyMuse Yes, I’ve added
    @AndroidEntryPoint
    @Albert Chang From what I can tell my implementation is pretty much identical to the one in the linked thread. That’s where I got my solution from, after all 😃
    Alright, looks like I found a solution. Instead of providing the context created by
    createConfigurationContext
    directly, I use ContextWrapper to update the
    getResources
    call to use the next context but use the MainActivity for all other calls:
    class ContextWithUpdatedResources(
        private val resources: Context,
        base: Context
    ) : ContextWrapper(base) {
        override fun getResources(): Resources {
            return resources.resources
        }
    }
    My
    OverrideLocale
    is defined as following:
    @Composable
    private fun OverrideLocale(language: String, mainActivity: MainActivity, content: @Composable () -> Unit) {
        val configuration = LocalConfiguration.current
        configuration.setLocale(Locale(language))
        val resources = LocalContext.current.createConfigurationContext(configuration)
        CompositionLocalProvider(
            LocalOnBackPressedDispatcherOwner provides mainActivity,
            LocalConfiguration provides configuration,
            LocalContext provides ContextWithUpdatedResources(resources, mainActivity)
        ) {
            content()
        }
    }
    i

    Ian Lake

    1 year ago
    Note that
    LocalOnBackPressedDispatcher
    also does the same context unwrapping, so overriding it isn't necessary
    Walter Berggren

    Walter Berggren

    1 year ago
    Thank you for the pointers! @Ian Lake @Albert Chang @FunkyMuse