I have this component:
#Singleton
#Component(modules = OauthModule.class)
public interface OauthComponent {
void inject(LoginActivity a);
}
and the module:
#Module
public class OauthModule {
#Provides
#Singleton
Oauth2Service provideOauth2Service() {
return new Oauth2StaticService();
}
}
and this another component:
#Singleton
#Component(modules = LoggedUserModule.class)
public interface LoggedUserComponent {
void inject(LoginActivity a);
}
and I get this error:
Error:(15, 10) error: Oauth2Service cannot be provided without an
#Provides- or #Produces-annotated method.
If I change the LoggedUserComponent's inject method parameter to be another Activity, say AnotherActivity like this:
#Singleton
#Component(modules = LoggedUserModule.class)
public interface LoggedUserComponent {
void inject(AnotherActivity a);
}
compilation is ok. Why? Can't I have two components with the same inject signature?
I'm trying to understand how Dagger works so any help will be appreciated. Thanks.
Think of dagger as an object graph—which it actually is. You probably should not have 2 different components being able to inject the same object, other than for testing purposes (or if you want to include different behavior, not additional one).
If your LoginActivity depends on multiple modules, you should aggregate them in a single component, since as your error shows, dagger will fail if it can not provide all dependencies from a single component.
#Singleton
#Component(modules = {LoggedUserModule.class, OauthModule.class})
public interface LoggedUserComponent {
void inject(AnotherActivity a);
}
Looking at Oauth2Service, this could easily be something that multiple objects could use, so a higher scope could be adequate. In that case you should think about adding it with a #Singleton scope to your application component, or maybe create its own component with e.g. a #UserScope.
Then you would have to either make your LoggedUserComponent a #Subcomponent or declare this component a dependency using #Component(dependencies = OauthComponent.class) and providing a getter in OauthComponent for it. In both cases dagger would also be able to provide the dependency found higher in the graph, thus also resolving your error.
It's getting mad because you're saying you can inject into that class but you're not providing a class that it's expecting you to provide. You just need to add the OauthModule to your LoggedUserComponent. Try this
#Singleton
#Component(modules = {LoggedUserModule.class, OauthModule.class})
public interface LoggedUserComponent {
void inject(LoginActivity loginActivity);
}
Related
I am trying to understand an example for an app with offline support using retrofit and room:
You can find the code for it here:
This project is using dependency injections with Dagger2. I've never worked with it so I am trying to understand how things work together. I understand the purpose of dependency injection but I don't understand the implementation of the project above.
I found a very good introduction into Dagger2 here:
A Friendly Introduction to Dagger 2
Dagger 2 example Code:
I worked through it and got most of it. Back to the actual project I am trying to understand (link 2). It still doesn't make sense to me and here is why:
The interface AppComponent has one method which is used:
public void inject(MainActivity2ViewModel viewModelModule); The return type is void. In the Dagger2 sample project (link 3 and 4) they use WeatherReporter getWeatherReporter(); which makes sense because later they call this method to get a WeatherReporter-Instance and Dagger2 manages all of the instantation process in the background. But I get nothing if the return type is void. Why is the return type not an object?
There is one #Inject in MainActivity2ViewModel:
#Inject
public void setRepository(GitHubRepository2 repository) {
this.repository = repository;
}
repository is the only field of MainActivity2ViewModel so it is a dependency. The GitHubRepository2 constructor has 3 parameters:
#Inject
public GitHubRepository2(GitHubApi api, GitHubDao dao, Executor executor)
For each of them there is a module explaining how to create those objects. But why is there an AppModule and a NetModule? Maybe the AppModule is there because DaoModule needs an Application reference but why is there a NetModule and where is it used?
There's a lot of comprehensive tutorials about Dagger2 in Android. But I'll show you a glimpse of what it's used for. And minimal usage.
Ultimately, dagger will use the annotation #Inject which will provide(reference to the object or value) to the variable.
Injection is usually used on reusable or boilerplate objects like Dao, Repository, ViewModel, NetworkAdapter
class SomethingThatRequiresNetwork { // Activity, Fragment
#Inject
MyReusableNetworkAdapter myReusableNetworkAdapter;
String baseUrl; // for example purpose only
SomeDependency someDependency;
void init() {
// #NOTE: DaggerMyExampleComponent is a generated class. It will be red before compilation.
MyExampleComponent MyExampleComponent = DaggerMyExampleComponent.builder().build();
MyExampleComponent.inject(this); // the actual injection happens here
}
// yes, you can just use #Inject on the variables directly but this is another use.
#Inject
void methodInjection(String baseUrl, SomeDependency someDependency) {
this.baseUrl = baseUrl;
this.someDependency = someDependency;
}
}
// ANSWER to the two questions
// this is a pseudocode of the generated code. You do not write this
// MyExampleComponent class
void inject(SomethingThatRequiresNetwork obj) {
// #NOTE: modules are actually instantiated by MyExampleComponent. Not called statically. I just shortened it
obj.myReusableNetworkAdapter = NetModule.provideNetworkAdapter();
obj.methodInjection(NetModule.provideBaseUrl(), SomeModule.provideSomeDependency());
}
// these here are modules that provide by return TYPE
// you write these
#Module
class NetModule {
#Provides
#Singleton
String provideBaseUrl() {
return "www.some-url.com";
}
#Provides
#Singleton // will store the object and reuse it.
// #NOTE: provision can work internally within modules or inter-module. the input here is provided by provideBaseUrl
MyReusableNetworkAdapter provideNetworkAdapter(String baseUrl) {
return new MyReusableNetworkAdapter(baseUrl);
}
}
#Modules
class SomeModule {
#Provides
#Singleton
SomeDependency provideSomeDependency() {
return new SomeDependency();
}
}
// Component. uses modules
#Singleton // .build() will reuse
#Component(modules = {NetModule.class, SomeModule.class})
interface MyExampleComponent {
// the method name doesn't matter
// the class type does matter though.
void inject(SomethingThatRequiresNetwork somethingThatRequiresNetwork);
// some other class that needs injection. #NOTE: I did not give example for this
void inject(SomethingThatRequiresDependency some);
}
NOTE. This code is usually written from bottom to top lol. You start writing the Component then Module then Injections.
Just follow the calls from the top of this answer and you'll figure out how Dagger2 works.
In Dagger2 is it possible to request same class for injection from more than one component. Sample code below
#Component(modules = classA.class)
interface compA
{
void inject(MyActivity target);
}
#Component(modules = classB.class)
interface compB
{
void inject(MyActivity target);
}
If possible please explain with reason and any doc reference.
Thanks
Not at the same time. You can call either inject function you wish on it, but you can't inject it with compA then compB. You could however make a componentC that builds off of subcomponents A and B and inject it with that.
Im learning Dagger 2, i have noticed that in some examples there is a #Singleton in the module's methods and on other #Singleton on the Component's methods? What is the difference and what exactly a #Singleton annotation on a module's method and on an component's method mean?
Since you're a beginner, I highly recommend just trying stuff. Writing unit tests is easy enough, and it helps to understand and prove theories.
If you didn't already, read the User's Guide for some basic knowledge about dagger and scopes.
Annotating methods in components (provision methods) doesn't have any effect. You will have to annotate the class or providing method in a module. I want to quickly show how you can just quickly prove this yourself:
We have 2 Component, one using a scope #Singleton, the other one none:
#Singleton
#Component(modules = SingletonModule.class)
public interface SingletonComponent {
Object getObject();
}
#Component(modules = NormalModule.class)
public interface NormalComponent {
#Singleton
Object getObject();
}
With those components come 2 modules, one providing the singleton scoped object (same as the component) the other one just uses no scope:
#Module
public class SingletonModule {
#Provides
#Singleton
public Object provideObject() {
return new Object();
}
}
#Module
public class NormalModule {
#Provides
public Object provideObject() {
return new Object();
}
}
And now we just create a small test:
public class ComponentTest {
#Test
public void testSingletonComponent() {
SingletonComponent component = DaggerSingletonComponent.create();
Assert.assertEquals(component.getObject(), component.getObject());
}
#Test
public void testNormalComponent() {
NormalComponent component = DaggerNormalComponent.create();
Assert.assertNotSame(component.getObject(), component.getObject());
}
}
This test will succeed and prove that annotating methods in components doesn't do anything. Scoping objects in modules, or annotating the class itself when using constructor injection will result in the object being reused within the same scope / the same component.
Creating 2 components of the same scope will also lead to duplicate objects, as can be proven like this:
#Test
public void testTwoSingleonComponents() {
SingletonComponent component1 = DaggerSingletonComponent.create();
SingletonComponent component2 = DaggerSingletonComponent.create();
Assert.assertNotSame(component1.getObject(), component2.getObject());
}
Be sure to read some tutorials and be sure to try things out. The compiler will complain if you do things wrong! :)
Yes, I know this has been asked before, and yes, I know it is "by design".
But I'd like to do something like this:
#Component(modules = {RealmModule.class})
public interface RealmComponent {
Realm realm();
}
#Component(modules = {RepositoryModule.class})
public interface RepositoryComponent {
PersonRepository personRepository();
ScheduleRepository schedulesRepository();
}
#Component(dependencies = {RealmComponent.class, RepositoryComponent.class})
public interface AppDataComponent
extends RealmComponent, RepositoryComponent {
}
#ApplicationScope
#Component(dependencies = {AppContextComponent.class,
AppDataComponent.class,
AppDomainComponent.class,
AppPresentationComponent.class,
AppUtilsComponent.class})
public interface ApplicationComponent
extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent {
void inject(CustomApplication customApplication);
void inject(DashboardActivity dashboardActivity);
}
However, what I get is unscoped, every time I inject a JobManager or a ScheduleRepository or anything else, I get a new instance. The only way I could "fix" that was this.
#Module
public class JobManagerModule {
private JobManager jobManager;
#Provides
public JobManager jobManager(Context context) {
if(jobManager == null) {
jobManager = new JobManager(context, new Configuration.Builder(context).networkUtil(
new WifiOrMobileNetworkUtil(context)).build());
}
return jobManager;
}
}
Not a fan.
So, how is one meant to structure and rip apart the dependency tree, without making one big gigantic über blob component that has every single module listed and every single provision method (instead of these "subcomponent" component dependencies)?
I tried using subcomponents for this, but then you have to provide every single module for the final ApplicationComponent.
I'm not sure what to do here. I tried specifying #Singleton for every first-level component and #SubcomponentScope for every AppDataLevelComponent, I also tried making a new scope for every single subcomponent, but both of them failed with "cannot depend on multiple scoped components".
EDIT: Apparently in order to get scoped providers, marking the components with the scope is not enough - you must specify the scope for the #Provides annotated methods too.
#Module
public class RepositoryModule {
#Provides
#Singleton
public PersonRepository personRepository() {
return new PersonRepositoryImpl();
}
#Provides
#Singleton
public ScheduleRepository schedulesRepository() {
return new SchedulesRepositoryImpl();
}
}
In the meantime, I ended up with this übercomponent.
#Singleton
#Component(modules = {
AppContextModule.class,
DbMapperModule.class,
DbTaskModule.class,
RealmModule.class,
RepositoryModule.class,
InteractorModule.class,
ServiceModule.class,
PresenterModule.class,
XmlPersisterModule.class
})
public interface ApplicationComponent
extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent {
Where the xyzComponent classes are just interfaces to store the provision methods...
(Please note that this structure is an anti-pattern as described by Martin Fowler, and you should organize modules based on features / activities, and make them into subscoped components using component dependencies. Component dependencies are used to subscope your superscope components, and "inherit" dependency providers.)
I had same problems like you not while ago and ended using the same ubercomponent approach except I use #Subcomponents in order organize the things and not to have all modules listed in the ubercomponent (I call it "top" or "app's" component).
You may see an example here:
How to migrate missing inject from module with complete = false from Dagger 1 to Dagger 2
I have the following setup:
#ApplicationScope
#Component(
dependencies = {AppContextComponent.class, CertUtilsComponent.class, ServiceComponent.class, JobManagerComponent.class})
public interface ApplicationComponent
extends AppContextComponent, CertUtilsComponent, ServiceComponent, JobManagerComponent {
void inject(MainActivity mainActivity); //honestly, I won't need this
}
And I have the following subscoped component:
#PresenterScope
#Component(dependencies = {ApplicationComponent.class, PersistenceComponent.class})
public interface PresenterComponent
extends ApplicationComponent, PersistenceComponent {
void inject(HomePresenter homePresenter);
void inject(SendCertificateRequestInteractor sendCertificateRequestInteractor);
}
The problem is that PersistenceComponent has the following component as its dependency:
#Component(dependencies = {JobManagerComponent.class, RealmComponent.class, RepositoryComponent.class}, modules = {PersisterModule.class})
public interface PersisterComponent {
DummyCertPersister dummyCertPersister();
}
Which uses JobManagerComponent, which is the dependency of the ApplicationComponent.
Unfortunately, this component does not seem to be inherited from ApplicationComponent. I need to explicitly keep track of this component, and provide it for the builder like so.
//INJECTOR
ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
.appContextComponent(appContextComponent)
.certUtilsComponent(certUtilsComponent)
.jobManagerComponent(jobManagerComponent)
.serviceComponent(serviceComponent)
.build();
this.jobManagerComponent = jobManagerComponent;
this.applicationComponent = applicationComponent;
this.certUtilsComponent = certUtilsComponent;
this.appContextComponent = appContextComponent;
this.serviceComponent = serviceComponent;
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
public JobManagerComponent getJobManagerComponent() {
return jobManagerComponent;
}
And provide this through a getter when I build my persistence component:
PersisterComponent persisterComponent = DaggerPersisterComponent.builder()
.jobManagerComponent(Injector.INSTANCE.getJobManagerComponent()) //this should be subcomponent
.realmComponent(realmComponent)
.repositoryComponent(repositoryComponent)
.persisterModule(new PersisterModule())
.build();
I would like to have that JobManagerComponent inherited from ApplicationComponent. I'm guessing I need to make this into a #Subcomponent and provide a provision method for it, but so far, it hasn't worked (I don't get a builder method, but it still doesn't see the jobManager within JobManagerComponent.
Is this possible with #Subcomponent? Or do I need to keep track of the "subcomponents" of ApplicationComponent in case a child component depends on it?
The answer is that I was conceptually wrong about how Components work in Dagger2.
A component should only depend on another component if it subscopes that component. A component with multiple component dependencies cannot depend on scoped components; which means they cannot have scoped modules; which also means they cannot use scopes at all and unless the module keeps a reference to the new instance, you'll get a new instance each time you inject. Which is bad, and not what you want at all.
The proper way is to bind every module of the same scope to the same component. That way, the provided dependencies are accessible within the constructors, and you won't have an issue with sharing the same module within different components as well.
Therefore, the approach in the question is completely wrong.
Use this instead.