Reputation: 1034
after search on web for learning about this feature most topics or post was using dependency injection for Retrofit
or other android useful libraries, but i have some custom class which i want to use that with DI and i can't done it, for example i have simple custom class for using SharePreference
and i'm using with that as an Singleton class
in my code i can't assign correct Dagger to component on SpApplication
class to use that on activities or fragments
public class SP {
private SharedPreferences preferences;
private Context context;
public SP(Context context) {
this.context = context;
}
private SharedPreferences getPrefs() {
return preferences = PreferenceManager.getDefaultSharedPreferences(context);
}
public String getString(SharedPrefsTypes propertyName) {
return getPrefs().getString(propertyName.toString(), "");
}
public int getInt(SharedPrefsTypes propertyName) {
return getPrefs().getInt(propertyName.toString(), 0);
}
...
public enum SharedPrefsTypes {
Login
}
}
now i'm trying to use DI for that:
AppModules class:
@Module
public class AppModules {
private Context context;
public AppModules(Context context) {
this.context = context;
}
@Provides
@Singleton
SP provideSharePreferences() {
SP sharePreference = new SP(context);
return sharePreference;
}
}
ApplicationComponent
class:
@Component(modules = AppModules.class)
public interface ApplicationComponent {
void inject(ActivityMain activity);
}
SpApplication
class:
public class SpApplication extends Application {
private static SpApplication self;
private ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
self = this;
component = DaggerApplicationComponent.builder().build();
}
public static SpApplication get(Context context) {
return (SpApplication) context.getApplicationContext();
}
public static SpApplication getInstance() {
return self;
}
public ApplicationComponent getComponent() {
return component;
}
}
and my ActivityMain
class:
public class ActivityMain extends AppCompatActivity {
@Inject
SP sharePreference;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((SpApplication) getApplication()).getComponent().inject(this);
sharePreference.setInt(SP.SharedPrefsTypes.Login, 0);
}
}
I get this error:
android.app.Application cannot be cast to com.pishguy.yendir.SpApplication
Thanks in advance
Upvotes: 3
Views: 1333
Reputation: 16228
I guess you are trying to inject into ActivityMain
, but since you did not provide its source, let me show you how you could inject into SpApplication
. Then just copy the relevant parts into your Activity
.
Few things I think you need to change.
Module:
Your AppModules
class is generally OK, but I just suggest you to change the way you make use of Context
- don't use it as a field, but inject it as any other service. It looks like this:
@Module
public class AppModules {
private Context context;
public AppModules(Context context) {
this.context = context;
}
@Provides // this can be non-scoped because anyway the same instance is always returned
Context provideContext() {
return this.context;
}
@Provides
@Singleton
SP provideSharePreferences(Context context) {
return new SP(context); // use method-local Context
}
}
Component:
Taking into account these two points, ApplicationComponent
should look like this:
@Singleton // injects @Singleton scoped services
@Component(modules = AppModules.class)
public interface ApplicationComponent {
void inject(SpApplication application); // SpApplication is DI client (injection target)
}
Client:
I'd change few things in your SpApplication
class:
ApplicationComponent
is incorrectget(Context)
and getInstance()
methodsIn addition, since I'm showing how you inject into SpApplication
, I will add the injection logic as well (which you should copy to your actual clients).
So, SpApplication
(which is DI client) should look similar to this:
public class SpApplication extends Application {
@Inject SP sp; // the dependency that should be injected
private ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
getComponent().inject(this); // this is when the actual injection takes place
}
public ApplicationComponent getComponent() {
if (component == null) {
// this is the way Dagger components should be instantiated
component = DaggerApplicationComponent.builder()
.appModules(new AppModules(this))
.build();
}
return component;
}
}
If you perform the above changes, I tend to believe that you'll be all right.
BTW, I recently completed a blog post about Dagger 2 scopes. You might want to check it if you are going to be serious about dependency injection.
Upvotes: 2