14

I need to access my SharedPreferences instance in the attachBaseContext of my activity (so I can set the locale there), but the injected SharedPreferences instance is not available there as the injection is happening in the onCreate method, which is running after the attachBaseContext call. I am using dagger2 for dependency injection.

Any idea how I can avoid creating a new SharedPreferences instance?

EDIT:

Ok, so I think the problem is that I am trying to use dagger too much, I think in this case it is simply not suitable. In the attachBaseContext of each activity I have to update the locale, and I extracted this updating logic to a LocaleManager which needs access to the SharedPreferences instance and the Context that I get in attachBaseContext. The SharedPreferences instance is already in the AppModule, but I still cannot @Inject it to the activities before the attachBaseContext call, as the activity`s injections happen after attachBaseContext.

Analizer
  • 1,594
  • 16
  • 30

2 Answers2

0

You can inject like this:

    @EntryPoint
    @InstallIn(SingletonComponent::class)
    interface PreferencesProvider {
    
        fun getPreferences(): Preferences
    }
    
    abstract class BaseActivity ... {
        private lateinit var preferences: Preferences

        override fun attachBaseContext(newBase: Context) {
           initPreferences(newBase)
           super.attachBaseContext(ContextLocaleWrapper.wrap(newBase,preferences.getLanguage()))
        }

        private fun initPreferences(context: Context) {
            preferences = EntryPointAccessors.fromApplication(
                context.applicationContext,
                PreferencesProvider::class.java
            ).getPreferences()
        }
    }
Coffe Milk
  • 21
  • 3
-2

As long as you can access your Component you could add a provision method

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {

    fun inject(myActivity: MyActivity)

    fun sharedPreferences(): SharedPreferences

    ...
}

and then access your SharedPreferences directly via the Component:

class MyActivity : AppCompatActivity() {

    override fun attachBaseContext(newBase: Context) {
        val sharedPreferences = component.sharedPreferences()
        ...
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        component.inject(this)
    }

}
laenger
  • 991
  • 1
  • 10
  • 20
  • 1
    Thanks for the answer! I am using the `@ContributesAndroidInjector` implementation and this way I am not creating any components. The ApplicationComponent is the only one I have, so this would result in moving the `SharedPreferences` to app level, but I am gonna look into that solution – Analizer Jun 19 '18 at 11:53
  • In this case, the call to `AndroidInjection.inject(this)` creates a component, the (generated) `MyActivitySubcomponent`. Activity scoping your `SharedPreferences` would therefore not help you with "avoiding new instances". And the answer above, even with the mentioned `dagger.android` package, should be an option. Besides refactoring your logic. – laenger Jun 27 '18 at 17:14
  • Hi can u please help my friend on the same problem, please check the link once https://stackoverflow.com/q/53277662/3946958 – Ravindra Kushwaha Nov 14 '18 at 06:54
  • 1
    Wont work because injecting at onCreate have to be called first but attachBaseContext called before onCreate so you'll have NullPointer – Valentin Yuryev Nov 28 '18 at 22:30