I'm new to Dagger concepts, I've understood some extent I guess but keep having issues with injecting classes. I went through a lot of tutorials and sample codes but end up having an error when I have to multiple modules using a component and it mostly ends up with the shared preference module not being injected. Not able to understand the actual error or the mistake I'm making, need some assistance.
My Component class:
@Singleton
@Component(modules = {VehicleModule.class, AppPreference.class})
public interface AppComponent {
// void injectPreference(MainActivity activity);
void inject(MainActivity activity);
Vehicle provideVehicle();
}
My Shared Preference class:
@Module
public class AppPreference {
private SharedPreferences preferences;
private SharedPreferences.Editor edit;
@ApplicationScope
@Provides
@Inject
public SharedPreferences getPreferences() {
return preferences;
}
public AppPreference(Context context) {
// preferences = PreferenceManager.getDefaultSharedPreferences(context);
preferences = context.getSharedPreferences(context.getString(R.string.app_name), MODE_PRIVATE);
edit = preferences.edit();
}
@Singleton
@Provides
public String setDataPref(String strKey, String strValue) {
edit.putString(strKey, strValue);
commitPreference();
return strKey;
}
@Singleton
@Provides
public String removeFromPreference(String strKey) {
edit.remove(strKey);
return strKey;
}
public void commitPreference()
{
edit.commit();
}
@Singleton
@Provides
public String getDataPref(String strKey) {
return preferences.getString(strKey, "");
}
@Singleton
@Provides
public boolean clear() {
edit.clear();
commitPreference();
return true;
}
}
My Application Class:
public class AppInstance extends Application {
AppComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerAppComponent.builder().appPreference(new AppPreference(getApplicationContext())).build();
}
public AppComponent getComponent() {
return component;
}
}
Finally my Activity:
public class MainActivity extends AppCompatActivity {
// @Inject
// AppPreference preference;
private AppComponent appComponent;
Vehicle vehicle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
appComponent = DaggerAppComponent.builder().vehicleModule(new VehicleModule()).build();
vehicle = appComponent.provideVehicle();
((AppInstance) getApplicationContext()).getComponent().inject(this);
}
}
This code is able to build the DaggerAppComponent but once I inject the AppPreference in Mainactivity it doesn't work anymore.
What am I doing wrong in injecting the preference class?? Need help..
You've mistaken a couple of concepts and annotations.
You inject an object by annotating either a field or a constructor with @Inject
. In case of the Android activities you can only use the field method. So your MainActivity.class
should look more like this:
public class MainActivity extends AppCompatActivity {
@Inject
SharedPreference preference;
@Inject
Vehicle vehicle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Inject dependencies into MainActivity
((AppInstance) getApplicationContext()).getComponent().inject(this);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
}
You also don't need to use the @Inject
annotation in your AppPreferences module as you are providing the dependency, not injecting there.
Speaking of providing, methods annotated with @Provides
will be invoked whenever their return type is to be inject. If there are multiple provider methods with the same return type, you have to distinguish them using the @Named
annotation or a custom qualifier. You have multiple provider methods that return String
in your AppPreferences
module, however I don't think they are correctly marked as provider, they seem more like a couple of operation on the SharedPreferences
object. After cleaning up you should be left with this module:
@Module
public class AppPreference {
private SharedPreferences preferences;
public AppPreference(Context context) {
preferences = context.getSharedPreferences(context.getString(R.string.app_name), MODE_PRIVATE);
}
@ApplicationScope
@Provides
public SharedPreferences getPreferences() {
return preferences;
}
}
And you have to expose SharedPreferences
in the component like you did with the Vehicle
class:
@Singleton
@Component(modules = {VehicleModule.class, AppPreference.class})
public interface AppComponent {
void inject(MainActivity activity);
SharedPreferences sharedPreferences();
Vehicle vehicle();
}
Edit:
If you want some kind of wrapper for the SharedPreferences
functionalities you can create a custom class (which is neither Dagger Component nor Module), e.g. MyAppPreferences
:
public class MyAppPreferences {
private SharedPreferences preferences;
public MyAppPreferences(SharedPreferences preferences) {
this.preferences = preferences;
}
// put setDataPref, removeFromPref, etc. in here
}
And inject it like this:
@Module
public class AppPreferencesModule {
private Context context;
public AppPreferencesModule(Context context) {
this.context = context;
}
// Dagger will inject the SharedPreferences object using the providePreferences() provider
@ApplicationScope
@Provides
public MyAppPreferences provideMyAppPreferences(SharedPreferences preferences) {
return new MyAppPreferences(preferences);
}
@ApplicationScope
@Provides
private SharedPreferences providePreferences() {
return context.getSharedPreferences(context.getString(R.string.app_name), MODE_PRIVATE);
}
}
@Singleton
@Component(modules = {VehicleModule.class, AppPreferencesModule.class})
public interface AppComponent {
void inject(MainActivity activity);
// expose MyAppPreferences instead of SharedPreferences
MyAppPreferences myAppPreferences();
Vehicle vehicle();
}
public class MainActivity extends AppCompatActivity {
// inject MyAppPreferences instead of SharedPreferences
@Inject
MyAppPreferences myAppPreferences;
...
}