Not able to use dagger-injected objects in attachBaseContext() to update locale

Viewed 1031

I am using dagger and I have to update the locale in the attachBaseContext of the activity, I am keeping the locale update logic inside LocaleManager and LocaleManager instance is already inside appModule when I try to use this LocaleManager instance inside attachBaseContext I get null pointer exception as the activity's injections happen after attachBaseContext inside onCreate().

2 Answers

This is happening, as you said, because the injection is happening after attachBaseContext is called.

I'm actually not sure what the question is here, but I was facing the same problem, but unfortunately I could not solve it with dagger. I needed to create a new LocaleManager in the attachBaseContext like this:

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(new LocaleManager(base).updateContext());
}

where updateContext returns the context with the updated locale, like this:

public Context updateContext() {
    Locale locale = new Locale(DESIRED_LANGUAGECODE);
    Locale.setDefault(locale);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResourcesLocale(locale);
    }
    return updateResourcesLocaleLegacy(locale);
}


@SuppressWarnings("deprecation")
private Context updateResourcesLocaleLegacy(Locale locale) {
    Resources resources = mContext.getResources();
    Configuration configuration = resources.getConfiguration();
    configuration.locale = locale;
    resources.updateConfiguration(configuration, resources.getDisplayMetrics());
    return mContext;
}


@TargetApi(Build.VERSION_CODES.N)
private Context updateResourcesLocale(Locale locale) {
    Configuration configuration = mContext.getResources().getConfiguration();
    configuration.setLocale(locale);
    return mContext.createConfigurationContext(configuration);
}

The solution is to inject your object in the Application class so that it can be available as soon as the application gets start.

In your Application class (a class which extends Application)

 /**
     * Request UserLanguageProvider here so it's initialized as soon as possible and can be used by
     * [LocaleStaticInjector]
     */
    @Inject
    lateinit var userLanguageProvider: UserLanguageProvider

In BaseActivity.kt

    override fun attachBaseContext(newBase: Context) {
            val context: Context =  LanguageContextWrapper.wrap(newBase, LocaleStaticInjector.userLanguageProvider)
            super.attachBaseContext(context)
        }

In my custom class:

/**
 * We use  a static object to inject the locale helper dependency because it's used  in
 * [BaseActivity#attachBaseContext] which is called before the activity is injected!!
 */
    object LocaleStaticInjector {
         lateinit var userLanguageProvider: UserLanguageProvider
    }
Related