I have the following simple module:
#Module
public class ApplicationModule {
private CustomApplication customApplication;
public ApplicationModule(CustomApplication customApplication) {
this.customApplication = customApplication;
}
#Provides #Singleton CustomApplication provideCustomApplication() {
return this.customApplication;
}
#Provides #Singleton #ForApplication Context provideApplicationContext() {
return this.customApplication;
}
}
And the respective simple component:
#Singleton
#Component(
modules = ApplicationModule.class
)
public interface ApplicationComponent {
CustomApplication getCustomApplication();
Context getApplicationContext();
}
And I'm creating the component here:
public class CustomApplication extends Application {
...
private ApplicationComponent component;
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
#Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
It throws this error at compile time: Error:(22, 13) error: android.content.Context cannot be provided without an #Provides-annotated method, but as you can see it is annotated with #Provides.
It's really strange because the problem goes away when I take the qualifier annotation off.
Just in case, this is my #ForApplication qualifier:
#Qualifier #Retention(RUNTIME)
public #interface ForApplication {
}
This is practically a textbook Dagger2 example. What am I doing wrong?
After quite a while of trial and error I've seem to found the cause, it's the ambiguity of Context because #ForApplication is missing in some places where Context is needed.
Also it may be my frail understanding of Dagger2 at the moment, but this boilerplate is quite prone to developer errors.
Anyhow... for anyone that finds the problem you just have to add the qualifier annotations in every place that dependency is used:
#Singleton
#Component(
modules = ApplicationModule.class
)
public interface ApplicationComponent {
CustomApplication getCustomApplication();
#ForApplication Context getApplicationContext();
}
Related
I am writing an app where I am using Dagger2 for dependency Injection. I am new to dagger. I am getting confused on how it works and I am not able to figure it out how to use this library. I have tried writing below modules and components with the help of examples in blogs. I have mentioned the purpose of that module. Please correct me if I am wrong.
App Module and Component : It should generate a singleton instance across the application and I want to use this instance to access some android resources
#Module
public class AppModule {
private BaseApplication baseApplication;
public AppModule(BaseApplication baseApplication){
this.baseApplication = baseApplication;
}
#Provides
#Singleton
BaseApplication providesApplication(){
return baseApplication;
}
}
#Singleton
#Component(modules = {AppModule.class})
public interface AppComponent {
BaseApplication getBaseApplication();
}
Instantiation of AppComponent
public class BaseApplication extends Application {
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder().appModule(new
AppModule(this)).build();
}
public AppComponent getAppComponent(){
return appComponent;
}
}
The above code works fine. I am getting problems in the below code
Location Module and Component : Is it Ok if I don't have a constructor
for the below module?
#Module
public class LocationModule {
#IntDef(
{LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY,
LocationRequest.PRIORITY_HIGH_ACCURACY,
LocationRequest.PRIORITY_LOW_POWER,
LocationRequest.PRIORITY_NO_POWER})
#Retention(RetentionPolicy.SOURCE)
public #interface LocationPriority {}
#Provides
#Singleton
#Named("default")
LocationRequest providesLocationRequest(){
return new LocationRequest()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(Constants.LOCATION_UPDATE_INTERVAL_MS)
.setFastestInterval(Constants.LOCATION_UPDATE_FASTEST_INTERVAL_MS)
.setSmallestDisplacement(Constants.LOCATION_UPDATE_DISPLACEMENT_METERS);
}
#Provides
#Singleton
#Named("custom")
LocationRequest providesCustomLocationRequest(int interval, int
fastestInterval, #LocationPriority int priority, float updateDisplacement) {
return new LocationRequest()
.setPriority(priority)
.setInterval(interval)
.setFastestInterval(fastestInterval)
.setSmallestDisplacement(updateDisplacement);
}
#Provides
#Singleton
LocationSettingsRequest providesLocationSettingsRequest(LocationRequest
locationRequest){
return new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
.build();
}
#Provides
#Singleton
FusedLocationProviderClient providesFusedLocationClient(BaseApplication
baseApplication){
return LocationServices.getFusedLocationProviderClient(baseApplication);
}
#Provides
#Singleton
SettingsClient providesSettingsClient(BaseApplication baseApplication){
return LocationServices.getSettingsClient(baseApplication);
}
}
#Singleton
#Component(modules = {LocationModule.class, AppModule.class})
public interface LocationComponent {
**Do we Really need a method here?**
void inject(GetLocationUseCase getLocationUseCase);
}
I am getting the following error
error: cannot access Nullable class file for
javax.annotation.Nullable not found
after using #Inject in below class. If I remove #Inject the error goes away.
public final class GetLocationUseCase implements
UseCaseContract.BusinessLogic {
UseCaseContract.Mediator mediator;
#Inject
FusedLocationProviderClient fusedLocationProviderClientl;
#Override
public void onInitialize() {
BaseApplication application = mediator.requestUserContext();
DaggerLocationComponent.builder().appModule(new
AppModule(application)).locationModule(new
LocationModule()).build().inject(this);
}
Why am I getting that error? Any help would be appreciated. Thanks in advance.
You need to add missing modules in your Component ..
For example, you will get this error if you remove NetModule from below
#Component(modules = {AppModule.class, NetModule.class, MainModule.class})
public interface AppComponent {
...
In case someone like me out there. I forgot to add #Provides annotation to the Dagger Module.
In my case I had a class with #Inject annotated constructor which extended another 3rd party class which had #Nullable annotation on one of the method parameters. Once I removed this extension everything started to work normally.
After wasting about 1 day on this issue, I found out that I need to temporarily add findbugs dependency like this:
implementation 'com.google.code.findbugs:jsr305:3.0.2'
Then dagger will print the actual error.
According to official documents:https://google.github.io/dagger/subcomponents.html ,I add a subcomponent in #Module, like this:
#Module(subcomponents = {MainActivityComponent.class})
public class ContextModule {
private Context mContext;
public ContextModule(Context context) {
mContext = context;
}
#Provides
public Context provideContext() {
return mContext;
}
}
And declare my component and subcomponent like this:
#Component(modules = ContextModule.class)
public interface AppComponent {
Context provideContext();
MainActivityComponent getMainActivityComponent();
}
#Subcomponent(modules = {HardwareModule.class, SoftwareModule.class})
public interface MainActivityComponent {
void injectMainActivity(MainActivity activity);
}
But the code can not be compiled successfully. The error is this:
Error:(11, 1) : com.kilnn.dagger2.example.MainActivityComponent doesn't have a #Subcomponent.Builder, which is required when used with #Module.subcomponents
I don't know how to write a #Subcomponent.Builder , and if i remove the subcomponent declare in #Module, everything is ok. So i don't know what is the right way to use subcomponent.
Actually, the error is quite descriptive, all you need to do is add the Builder to your Subcomponent like this:
MainActivityComponent.class
#Subcomponent.Builder
interface Builder {
MainActivityComponent build();
}
For your current implementation, and since you don't have special dependencies you don't really need the Subcomponent.
Note: For convention's sake I recommend you to rename your Subcomponent to MainActivitySubcomponent
Android Studio 2.2.2
I have a NewsListModelImp class which is the model in the MVP.
I want to inject my retrofit service into the model. However, as NewsListModelImp doesn't contain any reference to a context or activity I cannot call getApplication(). Which is what you would do if you were in a activity or fragment. I don't want to pass any context or activity in the constructor of NewsListModeImp as that would have to come from the presenter and I want to avoid any android stuff there.
public class NewsListModelImp implements NewsListModelContract {
#Inject
NYTimesSearchService mNYTimesSearchService;
public NewsListModelImp() {
((NYTimesSearchApplication)getApplication()).getAppComponent().inject(this);
}
}
My Application class
public class NYTimesSearchApplication extends Application {
private AppComponent mAppComponent;
public void onCreate() {
super.onCreate();
/* Setup dependency injection */
createAppComponent();
}
private void createAppComponent() {
mAppComponent = DaggerAppComponent
.builder()
.retrofitModule(new RetrofitModule())
.build();
}
public AppComponent getAppComponent() {
return mAppComponent;
}
}
My provides module
#Module
public class RetrofitModule {
private Retrofit retrofit() {
return new Retrofit
.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
#Provides
#Singleton
public NYTimesSearchService providesNYTimesSearch() {
return retrofit().create(NYTimesSearchService.class);
}
}
My Appcomponent
#Singleton
#Component(modules = {RetrofitModule.class})
public interface AppComponent {
void inject(NewsListModelImp target);
}
Many thanks for any suggestions,
Dagger-2 works reccurently. So if inside Activity (or Fragment) object is injected and it's constructor is properly annotated with #Inject annotation, the constructor's parameters will be injected too.
Suppose inside the application you would like to inject:
#Inject NyTimesPresenter presenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((NYTimesSearchApplication) getApplication()).getAppComponent().inject(this);
}
The constructor of NyTimesPresenter must be annotated with #Inject:
public class NyTimesPresenter {
NewsListModelImp newsListModel;
#Inject
public NyTimesPresenter(NewsListModelImp newsListModel) {
this.newsListModel = newsListModel;
}
}
NewsListModelImp constructor must also be annotated with #Inject:
public class NewsListModelImp implements NewsListModelContract {
NYTimesSearchService mNYTimesSearchService;
#Inject
public NewsListModelImp(NYTimesSearchService nYTimesSearchService) {
this.mNYTimesSearchService = nYTimesSearchService;
}
}
Then everything will be injected properly.
Why the parameters should be passed to class as constructors' parameters? Such design pattern conforms SOLID principles. Object dependencies are injected into objects and not created inside it and such code is easily testable (in tests dependencies can be replaced ie. by Mock's)
EXTRA INFO:
It is possible to inject objects implementing specific interfaces. Such technique is described here. In your case NyTimesPresenter can have NewsListModelContract as it's dependency instead of NewsListModelImp. To do this add another module to your AppComponent:
#Singleton
#Component(
modules = {
RetrofitModule.class,
AppModule.class
})
public interface AppComponent {
AppComponent method to provide concrete class implementing interface should look like:
#Singleton
#Module
public abstract class AppModule {
#Binds
public abstract NewsListModelContract provideNewsListModelContract(NewsListModelImp newsListModelImp);
}
The implementation of NyTimesPresenter should change (just to replace concrete class with interface it implements):
public class NyTimesPresenter {
NewsListModelContract newsListModel;
#Inject
public NyTimesPresenter(NewsListModelContract newsListModel) {
this.newsListModel = newsListModel;
}
}
For example, I have following interface:
public interface Repository {
Observable<Pojo> getPojos();
}
And its implementation:
public class RepositoryImpl implements Repository {
public RepositoryImpl() {
}
#Override
public Observable<Pojo> getPojos() {
return null;
}
}
Module:
#Module
class AppModule {
public AppModule() {
}
#Provides
#Singleton
Repository provideRepositoryImpl() {
return new RepositoryImpl();
}
}
And component:
#Singleton
#Component(modules = { AppModule.class })
public interface AppComponent {
void inject(MainActivity mainActivity);
}
When I trying to build project, I receive error as in question title. What problem in my code?
Read your error carefully (emphasis mine):
Dagger 2 error: “RepositoryImpl cannot be provided without an #Inject constructor or from an #Provides-annotated method”
Generally this means you've tried to #Inject RepositoryImpl, not #Inject Repository. This is especially important because your Module directly calls the RepositoryImpl constructor rather than letting Dagger create your RepositoryImpl using an #Inject-annotated constructor. (If you had, you could make RepositoryImpl a parameter of your #Provides method or switch to a #Binds method, and you have your choice between injecting the interface versus the implementation.)
The way I setup Dagger 2 is in my projects Application I add the injection component. like so.
public class NyApplication extends Application {
InjectionComponent component;
#Override
public void onCreate() {
super.onCreate();
setDagger();
}
private void setDagger() {
component = DaggerAppComponent.builder()
.appComponent(new AppModule())
.build();
component.inject(this);
}
public InjectionComponent getComponent() {
return component;
}}
and then int my activity whatever it is. I inject on it's onCreate like this.
public class MainActivity extends Activity {
#Inject
Object object;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((MyApplication) getApplication()).getComponent().inject(this);
}}
I hope this helps you.
I'm playing around trying to learn Dagger2. Just when I thought I was getting it, I seem to have gotten stuck. My application has two components, ApplicationComponent (singleton) and StripeComponent (1:1 activity) , which inherit an empty interface for the sake of readability.
Then it has two modules, ApplicationModule and StripeModule.
#Singleton #Component(modules = ApplicationModule.class)
public interface ApplicationComponent extends AbstractComponent ...
#PerActivity #Component(modules = { StripeModule.class }) public interface StripeComponent
extends AbstractComponent ...
#Module public class ApplicationModule
#Module public class StripeModule
One of the objects ApplicationModule provides is a Navigator, and I'm fairly sure than the way it does it is fairly correct:
#Provides #Singleton Navigator provideNavigator() {
return new Navigator();
}
This is a very simple class with pretty much nothing in it yet:
#Singleton public class Navigator
Then when I generate the code, an extra provision factory is generated from StripeModule - StripeModule_ProvideNavigatorFactory. And then the compiler whines that I'm not providing it - which is true, and intentional. It should be provided by the application component only. The question is, why is this factory being generated then? Why doesn't Dagger2 understand that StripeModule is not supposed to provide a navigator?
Assuming you have a StripeActivity class that uses StripeComponent to inject itself, then you might end up with a scenario like this one
public class StripeActivity extends AppCompatActivity {
#Inject
Navigator navigator;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
CustomApplication application = (CustomApplication)getApplicationContext();
StripeComponent stripeComponent = createComponent(application);
stripeComponent.inject(this);
}
protected StripeComponent createComponent(CustomApplication application) {
return DaggerStripeComponent.builder()
.applicationComponent(application.getApplicationComponent())
.build();
}
}
public class CustomApplication extends Application {
ApplicationComponent applicationComponent;
#Override
protected void onCreate() {
super.onCreate();
applicationComponent = createApplicationComponent();
}
protected ApplicationComponent createApplicationComponent() {
return DaggerApplicationComponent.create();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
#Component(modules={ApplicationModule.class})
#Singleton
public interface ApplicationComponent {
Navigator navigator();
}
#Component(dependencies={ApplicationComponent.class}, modules={StripeModule.class})
#PerActivity
public interface StripeComponent extends ApplicationComponent {
void inject(StripeActivity stripeActivity);
}
#Module
public class ApplicationModule {
#Provides
#Singleton
Navigator navigator() {
return new Navigator();
}
}
#Module
public class StripeModule {
//#Provides
//#PerActivity
//...
}
#Scope
#Retention(RUNTIME)
public #interface PerActivity {
}
EDIT: For base class injection, you need to inject both the superclass and the subclass manually, and you need to specify both the superclass and the subclass in your component. In this case, it would work like this.
public abstract class BaseActivity extends AppCompatActivity {
#Inject
Navigator navigator;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
CustomApplication application = (CustomApplication)getApplicationContext();
ApplicationComponent component = createComponentAndInjectSelf(application);
component.inject(this);
}
protected abstract ApplicationComponent createComponentAndInjectSelf(CustomApplication application);
}
public class StripeActivity extends BaseActivity {
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
}
#Override
public StripeComponent createComponentAndInjectSelf(CustomApplication application) {
StripeComponent stripeComponent = DaggerStripeComponent.builder()
.applicationComponent(application.getApplicationComponent())
.build();
stripeComponent.inject(this);
return stripeComponent;
}
}
#Component(modules={ApplicationModule.class})
#Singleton
public interface ApplicationComponent {
Navigator navigator();
void inject(BaseActivity baseActivity);
}
#Component(dependencies={ApplicationComponent.class}, modules={StripeModule.class})
#PerActivity
public interface StripeComponent extends ApplicationComponent {
void inject(StripeActivity stripeActivity);
}
You haven't included the exact error, or the code that actually depends on the Navigator.
But I'll assume the class that depends on Navigator is provided from within StripeModule or another module installed into StripeComponent.
StripeComponent and ApplicationComponent have to be related in some way in order for bindings in StripeComponent to use bindings provided by ApplicationComponent.
You can relate them either using component dependencies or subcomponents.
If you use subcomponents, you'd make StripeComponent a subcomponent of ApplicationComponent, which would mean that it can use any of the bindings in modules installed in ApplicationComponent, including the one for Navigator.
If you want to use component dependencies, you'd make StripeComponent depend on ApplicationComponent, and you'd add a method Navigator navigator() to ApplicationComponent. Bindings in StripeComponent can depend on any type returned by a method on a component it depends on.