Reputation: 347
I'm learning Dagger 2 and am working on an app. I have a settings module which depends on a settings manager which depends on a shared preferences manager. My problem is that my Settings Module is not getting injected with a settings manager before it itself is being called. That settings manager needs a SharedPrefsManager which is also not being injected anywhere.
What am I doing wrong?
Snippets in order of dependency:
@Module
public class SettingsModule {
@Inject SettingsManager manager;
@Provides
@TimeControl
int[] provideResetTime(){
return manager.getResetTime();
}
@Provides
@ThemeControl
int provideThemeID(){
return manager.getTheme();
}
}
Depends on Settings Manager:
public class SettingsManager{
private SharedPreferencesManager manager;
@Inject
SettingsManager(SharedPreferencesManager manager){
this.manager = manager;
}
}
Depends on Shared prefs manager:
public class SharedPreferencesManager {
private static SharedPreferencesManager instance = null;
public static SharedPreferencesManager getInstance(){return instance;}
String prefsKey = "SHAREDPREFSKEY";
SharedPreferences sharedPrefs = null;
Context applicationContext = null;
@Inject
SharedPreferencesManager(@ApplicationContext Context applicationContext){
this.prefsKey = prefsKey;
this.applicationContext = applicationContext;
sharedPrefs = applicationContext.getSharedPreferences(prefsKey,Context.MODE_PRIVATE);
instance = this;
}
}
Upvotes: 2
Views: 1026
Reputation: 81539
@Module
public class SettingsModule {
@Inject SettingsManager manager;
@Provides
@TimeControl
int[] provideResetTime(){
return manager.getResetTime();
}
@Provides
@ThemeControl
int provideThemeID(){
return manager.getTheme();
}
}
Should be
@Module
public class SettingsModule {
@Provides
@TimeControl
int[] resetTime(SettingsManager manager) {
return manager.getResetTime();
}
@Provides
@ThemeControl
int themeId(SettingsManager manager) {
return manager.getTheme();
}
}
Beware that your providers aren't scoped, so (AFAIK) a call that obtains themeId()
and a call that obtains resetTime()
will most likely create a new SettingsManager
each time.
So you might want to put @Singleton
on your provided classes.
@Singleton
public class SharedPreferencesManager {
private SharedPreferences sharedPrefs = null;
String prefsKey = "SHAREDPREFSKEY";
Context applicationContext = null;
@Inject
SharedPreferencesManager(Context applicationContext) {
this.applicationContext = applicationContext;
sharedPrefs = applicationContext.getSharedPreferences(prefsKey, Context.MODE_PRIVATE); // why isn' this in a module?
}
}
@Singleton
public class SettingsManager{
private SharedPreferencesManager manager;
@Inject
SettingsManager(SharedPreferencesManager manager){
this.manager = manager;
}
}
Upvotes: 1
Reputation: 12866
I don't think you should have @Inject
annotations in the modules since they are built to be the ones that create the dependencies and only receive other ones through the object graph or a simple constructor.
Here's an example on how you could avoid that @Inject annotation in the Module and the constructor injectors after it.
SettingsModule.java
@Module
public class SettingsModule {
@Provides
@TimeControl
int[] provideResetTime(SettingsManager manager) {
return manager.getResetTime();
}
@Provides
@ThemeControl
int provideThemeID(SettingsManager manager) {
return manager.getTheme();
}
@Provides
SettingsManager provideSettingsManager(SharedPreferencesManager sharedPreferencesManager) {
return new SettingsManager(sharedPreferencesManager);
}
@Provides
SharedPreferencesManager provideSharedPreferencesManager(@ApplicationContext Context context) {
return new SharedPreferencesManager(context);
}
}
SettingsManager.java
public class SettingsManager {
private SharedPreferencesManager manager;
SettingsManager(SharedPreferencesManager manager) {
this.manager = manager;
}
}
SharedPreferencesManager.java
public class SharedPreferencesManager {
private static SharedPreferencesManager instance = null;
private SharedPreferences sharedPrefs = null;
String prefsKey = "SHAREDPREFSKEY";
Context applicationContext = null;
SharedPreferencesManager(Context applicationContext) {
this.applicationContext = applicationContext;
sharedPrefs = applicationContext.getSharedPreferences(prefsKey, Context.MODE_PRIVATE);
instance = this;
}
public static SharedPreferencesManager getInstance() {
return instance;
}
}
With this, you would leave all your injection logic to your Module, and the concrete classes won't have to worry about injecting the classes themselves.
Upvotes: 0