#Singleton
public class AppPreferenceHelper implements PreferenceHelper {
static final String PREFS_APP_STATE = "prefsAppState";
static final String APP_STATE_LOGIN = "logIn";
String PREF_NAME ="appPreference" ;
private SharedPreferences sharedPreferences;
#Inject
AppPreferenceHelper(#ApplicationContext Context context) {
this.sharedPreferences = context.getSharedPreferences(PreferenceConstant.PREF_NAME,Context.MODE_PRIVATE);
}
#Override
public void setAppState(String state) {
sharedPreferences.edit().putString(PREFS_APP_STATE,state);
}
#Override
public String getAppState() {
return sharedPreferences.getString(PREFS_APP_STATE,APP_STATE_LOGIN);
}
}
#PerActivity
#Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
void inject(SplashActivity mainActivity);
void inject(LogInActivity logInActivity);
}
#Module
public class ApplicationModule {
private final Application mApplication;
public ApplicationModule(Application application) {
mApplication = application;
}
#Provides
#ApplicationContext
Context provideContext() {
return mApplication;
}
#Provides
Application provideApplication() {
return mApplication;
}
#Provides
#Singleton
AppPreferenceHelper providePreferencesHelper(AppPreferenceHelper appPreferencesHelper) {
return appPreferencesHelper;
}
}
#Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
mActivity = activity;
}
#Provides
#ActivityContext
Context provideContext() {
return mActivity;
}
#Provides
Activity provideActivity`enter code here`() {
return mActivity;
}`enter code here`
#Provides
#PerActivity
SpashMvpPresenter<SplashView> provideSplashPresenter(
SplashPresenter<SplashView> presenter) {
return presenter;
}
}
Error:(20, 10) error: com.d2u.android.data.preference.PreferenceHelper
cannot be provided without an #Provides-annotated method.
com.d2u.android.data.preference.PreferenceHelper is injected at
com.d2u.android.ui.splash.SplashPresenter.(preferenceHelper)
com.d2u.android.ui.splash.SplashPresenter
is injected at
com.d2u.android.di.module.ActivityModule.provideSplashPresenter(presenter)
com.d2u.android.ui.splash.SpashMvpPresenter
is injected at com.d2u.android.ui.splash.SplashActivity.mPresenter
com.d2u.android.ui.splash.SplashActivity is injected at
com.d2u.android.di.component.ActivityComponent.inject(mainActivity)
probably because you are injecting a PreferenceHelper, but your #Provides annotated method returns AppPreferenceHelper instead of PreferenceHelper
#Provides
PreferenceHelper providePreferencesHelper(AppPreferenceHelper appPreferencesHelper) {
return appPreferencesHelper;
}
Differently you could use #Binds
#Binds
abstract PreferenceHelper providePreferencesHelper(AppPreferenceHelper appPreferencesHelper);
for that you are gonna need a different abstract #Module, tho
Related
I was following some examples to work on dagger2. Here I was using dependencies on HomeFragmentComponent to provide reference of context from another scope but its not working.
ContextModule
#Module
public class ContextModule {
private final Context context;
public ContextModule(Context context) {
this.context = context;
}
#Provides
#ShikshyaScope
public Context context(){
return context;
}
}
Network Module :
#Module(includes = ContextModule.class)
public class NetworkModule {
#Provides
#ShikshyaScope
public File file(Context context){
File cacheFile = new File(context.getCacheDir(),"okhttp_cache");
cacheFile.mkdirs();
return cacheFile;
}
ShikshyaApplicationComponent:
#ShikshyaScope
#Component(modules = {NetworkModule.class, PicassoModule.class, StorageModule.class})
public interface ShikshyaApplicationComponent {
void injectShikshyaApplication(ShikshyaBusApplication shikshyaBusApplication);
}
Home Fragment Module :
#Module
public class HomeFragmentModule {
public final HomeFragment homeFragment;
public HomeFragmentModule(HomeFragment homeFragment) {
this.homeFragment = homeFragment;
}
#Provides
#HomeFragmentScope
public HomeFragment homeFragment(){
return homeFragment;
}
#Provides
#HomeFragmentScope
public HomeFragmentView homeFragmentView(HomeFragment homeFragment){
return (HomeFragmentView)homeFragment;
}
#Provides
#HomeFragmentScope
public HomeFragmentPresenter homeFragmentPresenter(HomeFragmentView homeFragmentView,MetaDatabaseRepo metaDatabaseRepo){
return new HomeFragmentPresenter(homeFragmentView,metaDatabaseRepo);
}
#Provides
#HomeFragmentScope
public DatabaseHelper databaseHelper(Context context){
return OpenHelperManager.getHelper(context,DatabaseHelper.class);
}
}
HomeFragmentComponent :
#HomeFragmentScope
#Component(modules = HomeFragmentModule.class,dependencies =ShikshyaApplicationComponent.class)
public interface HomeFragmentComponent {
void injectHomeFragment(HomeFragment homeFragment);
}
Now I get error as
error: android.content.Context cannot be provided without an #Provides-annotated method.
android.content.Context is injected at com.bihani.shikshyabus.di.module.HomeFragmentModule.databaseHelper(context)
com.bihani.shikshyabus.database.DatabaseHelper is injected at
You should include ContextModule as HomeFragmentModule dependency so Dagger2 be able to provide context to DatabaseHelper
#Module(includes = ContextModule.class)
public class HomeFragmentModule {
// Your stuff here
}
I am trying to learn Dagger2 from this medium article and pass RequestQueue as an activity level dependency:
https://proandroiddev.com/dagger-2-annotations-binds-contributesandroidinjector-a09e6a57758f
I can create application components just fine but I am facing a lot of trouble with ContributesAndroidInjector.
Application Class:
public class PokemonApplication extends Application {
private static AppComponent appComponent;
public static AppComponent getAppComponent(){
return appComponent;
}
#Override
public void onCreate() {
super.onCreate();
appComponent=buildMyComponent();
}
private AppComponent buildMyComponent() {
return DaggerAppComponent.builder().appmod(this).build();
}
}
AppModule:
#Module
public abstract class AppModule {
#ContributesAndroidInjector(modules = VolleyModule.class)
abstract MainActivity mainActivity();
#Provides
#Singleton
static SharedPreferences providePreferences(Application application) {
return application.getSharedPreferences("data", Context.MODE_PRIVATE);
}
#Provides
#Singleton
static Context getContext(Application application){
return application.getApplicationContext();
}
}
AppComponent:
#Singleton
#Component(modules = {RetrofitModule.class,AppModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity); //Error here.
#Component.Builder
interface Builder
{
AppComponent build();
#BindsInstance Builder appmod(Application application);
}
}
VolleyModule:
#Module
public abstract class VolleyModule {
#Provides
static RequestQueue getRequestQueue(Context context) {
return Volley.newRequestQueue(context);
}
}
MainActivity:
#Inject
RequestQueue requestQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PokemonApplication.getAppComponent().inject(this);
VolleyModule has to be also declared in the list of modules in your Component
#Singleton
#Component(modules = {RetrofitModule.class,AppModule.class, VolleyModule.class})
I am confused about Dagger2 in Android.
I use two scope. #Singleton, #PerActivity
This is my Code. I simplyfy my code.
//ApplicationComponent.java
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
#Named("packageName") String packageName();
}
//ApplicationModule.java
#Module
public class ApplicationModule {
#Provides
#Singleton
public Context provideApplicationContext() {
return MyApplication.getContext();
}
#Provides
#Singleton
#Named("packageName")
public String providePackageName(Context context) {
return context.getPackageName();
}
}
//UserComponent.java
#PerActivity
#Component(modules = {UserModule.class})
public interface UserComponent {
void inject(MainActivity activity);
}
//UserModule.java
#Module
public class UserModule {
String packageName;
public UserModule(String packageName) {
this.packageName = packageName;
}
#Provides
#PerActivity
UserRepositoryImpl provideUserRepositoryImpl() {
return new UserRepositoryImpl(packageName);
}
}
for inject appVersion, packagename in UserModule
DaggerChatComponent.builder()
.userModule(new UserModule(getApplicationComponent().packageName()))
.build();
but it looks not great. how can i inject when use different Scope??
your ApplicationModule.java is correct
#Module
public class ApplicationModule {
private Application application;
public ApplicationModule(Application application){
this.application = application;
}
#Provides
#Singleton
Context provideContext(){
return application;
}
#Provides
#Singleton
#Named("packagename")
public String providePackageName(Context context) {
return context.getPackageName();
}
}
and it's component class is also right ApplicationComponent.java
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
#Named("packagename") String providepackagename();
}
but in the UserModule.java you need not pass the package name object , dagger's object graph does this for you.
#Module
public class UserModule {
public UserModule() {
}
#Provides
#PerActivity
UserRepositoryImpl provideUserRepositoryImpl(#Named("packagename") String packageName) {
return new UserRepositoryImpl(packageName);
}
}
and the next step is while writing the component class for this module add the application component as a dependency ie, your UserComponent.java looks like this
#PerActivity
#Component(dependencies = {ApplicationComponent.class},modules = {UserModule.class})
public interface UserComponent {
void inject(MainActivity mainActivity);
}
with the activity scope as PerActivity.lava
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface PerActivity {
}
with this example UserRepositoryImpl.java as
class UserRepositoryImpl {
private String packagename;
public UserRepositoryImpl(String packagename){
this.packagename = packagename;
}
String getPackagename(){
return packagename;
}
}
you can finally inject this in your activity.(MainActivity.java)
public class MainActivity extends AppCompatActivity {
#Inject
UserRepositoryImpl userRepository;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ApplicationComponent component=DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(getApplication())).build();
UserComponent userComponent=DaggerUserComponent.builder().applicationComponent(component).userModule(new UserModule()).build();
userComponent.inject(this);
Log.e("name"," "+userRepository.getPackagename());
}
}
How can I provide activity context in mainModule class ? Thanks! The code looks like this:
#Singleton
#Component(modules = {AndroidInjectionModule.class, AppModule.class, ActivityBuilder.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MvmApp app);
}
Activtity builder:
#Module
public abstract class ActivityBuilder {
#ContributesAndroidInjector(modules = {MainModule.class})
abstract MainActivity bindMainActivity();
}
And I have an appModule, and a module for each activity:
#Module
public class AppModule {
#Provides
#Singleton
#ApplicationContext
Context provideContext(Application application) {
return application;
}
#Provides
#Singleton
DataManager provideDataManager(AppDataManager appDataManager) {
return appDataManager;
}
#Provides
#DatabaseInfo
String provideDatabaseName() {
return "carDatabase";
}
#Provides
#Singleton
AppDataBase provideAppDatabase(#DatabaseInfo String dbName, #ApplicationContext Context context) {
return Room.databaseBuilder(context, AppDataBase.class, dbName)
.build();
}
#Provides
#Singleton
DbHelper provideDbHelper(AppDbHelper appDbHelper) {
return appDbHelper;
}
}
AppClass:
public class MvmApp extends Application implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;
#Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder()
.application(this)
.build()
.inject(this);
}
#Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return activityDispatchingAndroidInjector;
}
}
All my activities extends a base activity which inject the Dagger dependecies.
public abstract class BaseActivity extends AppCompatActivity implements MvpView {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidInjection.inject(this);
}
}
In mainModule I need to provide the context of the activity.
#Module
public class MainModule {
#Provides
MainMvpPresenter<MainMvpView> provideMainPresenter(
MainPresenter<MainMvpView> presenter) {
return presenter;
}
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
CarAdapter provideCarAdapter( #ActivityContext Context context) {
return new CarAdapter(context);
}
}
The solution was:
#Module
public class MainModule {
#Provides
MainMvpPresenter<MainMvpView> provideMainPresenter(
MainPresenter<MainMvpView> presenter) {
return presenter;
}
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
CarAdapter provideCarAdapter(MainActivity activity) {
return new CarAdapter(activity);
}
}
For people facing a similar issue, I've made a project with Kotlin, and the new android-dagger extension with a lengthy explanation on how things work over here: https://github.com/Obaied/BareBonesAndroidDagger
I have two module, AppModule and SplashViewModule
For AppModule:
#Module
public final class AppModule {
#NonNull
private final MyApplication mApp;
public AppModule(#NonNull MyApplication app) {
mApp = app;
}
#Provides
public Context provideAppContext() {
return mApp;
}
#Provides
public MyApplication provideApp() {
return mApp;
}
#Singleton
#Provides
public UserManager provideUserManager() {
return new UserManager();
}
}
For SplashviewModule
#Module
public final class SplashViewModule {
#Inject
UserManager mUserManager;
#Provides
public SplashInteractor provideInteractor() {
return new SplashInteractorImpl(mUserManager);
}
#Provides
public PresenterFactory<SplashPresenter> providePresenterFactory(#NonNull final SplashInteractor interactor) {
return new PresenterFactory<SplashPresenter>() {
#NonNull
#Override
public SplashPresenter create() {
return new SplashPresenterImpl(interactor);
}
};
}
}
And I inject these to my activity like this:
#Override
protected void setupComponent(#NonNull AppComponent parentComponent) {
DaggerSplashViewComponent.builder()
.appComponent(parentComponent)
.splashViewModule(new SplashViewModule())
.build()
.inject(this);
}
But this does not work. The UserManager would be null. How can I get the singleton instance of UserManager created by AppModule and inject it to SplashViewModule?
You don't have to declare UserManager mUserManager; in SplashViewModule. Just add a UserManager parameter for the method provideInteractor.
#Provides
public SplashInteractor provideInteractor(UserManager userManager) {
return new SplashInteractorImpl(userManager);
}