This is what I currently have and it works:
#FragmentScope
#Component(dependencies = {FacebookComponent.class},
modules = {FragmentFacebookLoginModule.class})
public interface FragmentFacebookLoginComponent {
void inject(FragmentFacebookLogin fragment);
}
Now I want to add another dependency. I changed it to this:
#Component(dependencies = {FacebookComponent.class, AnotherComponent.class},
modules = {FragmentFacebookLoginModule.class})
But now I get this error message:
FragmentFacebookLoginComponent depends on more than one scoped
component
How can I solve this? How can I have more than one dependencies?
If I remove the scope from one component I get this error message:
AnotherComponent (unscoped) cannot depend on scoped components
I found the answer here: https://stackoverflow.com/a/29619594/1016472
At the end I created a AppComponent with the right scope and let FacebookComponent and AnotherComponent extends this AppComponent.
FacebookComponent and AnotherComponent does not have it's own scope (I removed it).
Looks now like this:
#AppScope
#Component
public interface AppComponent {
}
#Component(modules = {FacebookModule.class})
public interface FacebookComponent extends AppComponent {
}
#Component(modules = {AnotherModule.class})
public interface AnotherComponent extends AppComponent {
}
#FragmentScope
#Component(dependencies = {FacebookComponent.class, AnotherComponent.class},
modules = {FragmentFacebookLoginModule.class})
public interface FragmentFacebookLoginComponent {
void inject(FragmentFacebookLogin fragment);
}
You can't use scoped components in a dependencies array (which is quite strange I have to say), only unscoped, or one scoped + other unscoped.
But you can deceive dagger with "proxy" interfaces:
#Component
#Singleton
interface ComponentA {
fun provideSomeA()
}
interface ProxyComponentA : ComponentA
#Component
#Singleton
interface ComponentB {
fun provideSomeB()
}
interface ProxyComponentB : ComponentB
#Component(dependencies = [ProxyComponentA::class, ProxyComponentB::class])
#OtherScope
interface ComponentC
But in your ComponentC builder you should use proxy components implementations, which could easily be achieved with Kotlin:
class ProxyComponentAImpl(private val delegate: ComponentA) : ProxyComponentA, ComponentA by delegate
class ProxyComponentBImpl(private val delegate: ComponentB) : ProxyComponentB, ComponentB by delegate
componentA = DaggerComponentA.builder()...
componentB = DaggerComponentB.builder()...
componentC = DaggerComponentC.builder()
.componentA(ProxyComponentAImpl(componentA))
.componentB(ProxyComponentBImpl(componentB))
Works on dagger version 2.13, don't know about others
Also you could use vice versa inheritance ComponentA : ProxyComponentA to eliminate the need to create ProxyComponentAImpl, but it's not a good design choice if your ComponentA lays for example in a different gradle module
The solution was inspired by that issue discussion:
https://github.com/google/dagger/issues/1225
What you want to be determined to be within the ApplicationScope should be all defined without a scope, and linked together under the application scope only in the ApplicationComponent under the given scope.
For example,
#Component(modules = {FacebookModule.class})
public interface FacebookComponent {
FacebookThing facebookThing(); //assuming this is with #Provides in FacebookModule with NO SCOPE
}
#Component(modules = {AnotherModule.class})
public interface AnotherComponent{
AnotherThing anotherThing(); //assuming this is with #Provides in AnotherModule with NO SCOPE
}
Then you can do
#AppScope
#Component(dependencies={AnotherComponent.class, FacebookComponent.class})
public interface AppComponent extends AnotherComponent, FacebookComponent {}
After which you can do
#FragmentScope
#Component(dependencies=AppComponent.class)
public interface FragmentComponent extends AppComponent {}
Please note that unscoped providers create a new instance on every inject call. If you need the scoping, you should bind the modules to the same component, but components should only depend on other components with the intention of subscoping.
Now Dagger supports a component that can depends on more than 1 scoped dependencies. Just update your dagger version to 2.27
https://github.com/google/dagger/issues/1414
api 'com.google.dagger:dagger:2.27'
kapt 'com.google.dagger:dagger-compiler:2.27'
Include on your module the dependency module like this:
#Module(includes = FacebookModule.class)
public class AnotherModule {...
Related
I want to use Dagger in a project currently configured with Guice. I'm still very new to the concepts of DI, but I see that both Guice and Dagger use #Inject and #Provides notations. I have some understanding of the #Module and #Component annotations and how to set them up, but I'm wondering if the #Inject and and #Provides can basically be left as they are?
For example, let's say I have this in Guice:
public class ModuleA extends AbstractModule {
#Inject
public ModuleA() {
...
}
#Provides
#Singleton
protected InterfaceX() {
...
}
}
Could the following dagger implementation work the same, assuming there is also a component etc?
#Module
public class ModuleA {
#Inject
public ModuleA() {
...
}
#Provides
#Singleton
protected InterfaceX() {
...
}
}
One thing that confused me was that #Provides is used in Dagger to bind implementations to interfaces, and I'm not sure if that's what it is used for in Guice.
Again, I'm pretty new to this so any clarification would be really appreciated. Thanks!
NOTE: Have not used Dagger but can clarify on Guice side.
#Provides in Guice is for informing the Guice injector about which method to use to for creating the asked object at build time.
for eg : class Parent has implementation in 2 sub classes Child1 and Child2
Now you want to have a logic which defines when to inject Child1 and when to inject child2. This logic can be written in a method which can become the provider for Parent class impl. and to declare this provider method, #Provides annotation is used
class Parent {}
class Child1 extends Parent {}
class child2 extends Parent {}
GuieModule {
#Provides
Parent getParent() {
if(something)
return new Child1();
else
return new child2();
}
}
I am looking into Dagger 2 (Java) right now and came across an issue right upon the start. Sadly, I was not able find a anything yet in the Dagger 2 Documentation or on Stackoverflow about it, so if you guys know some resources I would really appreciate it.
I prepared a minimal example within this repository here to explain whats my issue: https://github.com/stackoverflow-samples/dagger2-dependency-cycle
So we got an Application class that should be constructed
public class Application {
#Inject
public Application(SomeDependency one) {
}
public static void main(String[] args) {
DaggerApplicationComponent.create().build();
}
}
... with a dummy dependency
public class SomeDependency {
#Inject
public SomeDependency() {
}
}
And of course the Dagger classes/interfaces ...
.. a component interface:
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
Application build();
}
.. and a module:
#Module
abstract class ApplicationModule {
#Provides
static SomeDependency provideDepdendencyOne() {
return new SomeDependency();
}
}
What I dont get is why Dagger forces me to register SomeDepdendency with #Provides annotation and does not allow to register it via #Binds:
#Binds
abstract SomeDependency bindDepdendencyOne(SomeDependency one);
Whenever I change the code from #Provides to #Binds it gives me the following errors:
[Dagger/DependencyCycle] Found a dependency cycle:
io.github.codejanovic.dagger2.example.SomeDependency is injected at
io.github.codejanovic.dagger2.example.ApplicationModule.bindDepdendencyOne(one)
io.github.codejanovic.dagger2.example.SomeDependency is injected at
io.github.codejanovic.dagger2.example.Application(one)
io.github.codejanovic.dagger2.example.Application is provided at
io.github.codejanovic.dagger2.example.ApplicationComponent.build()
Being unable to #Bind an implementation makes absolutely no sense to me. What do I oversee?
Thanks in advance.
You're wrong in assuming that you need #Binds or #Provides in the first place. You can and should be using constructor injection—not the pattern, but the Dagger generates the code for me kind.
You already have the constructor annotated with #Inject, thus Dagger knows about the class and how to create it. There's nothing else to do.
public class SomeDependency {
#Inject
public SomeDependency() {
}
}
You don't need any #Provides, no #Binds, not even a #Module for this simple use case of yours. Your example should work right out of the box since both constructors are annotated with #Inject.
#Component
public interface ApplicationComponent {
Application build();
}
If you need to specify a scope you can add it on the class.
#Provides should be used for code that you can't use constructor injection for, or that needs additional setup. Of course you can create all the objects manually (as you're doing in your example) but this has no real benefit and will just produce a lot of boilerplate that can be avoided.
#Binds is to be used with implementations that you need to bind to an interface. Optimally you'd use constructor injection for the implementation as well, but you can as well add it to the component builder (#BindsInstance) or create it in a #Provides annotated method.
#Binds MyInterface bindMyImplementation(MyImplementation implementation);
If your class is marked with an #Inject constructor:
public class SomeDependency {
#Inject // <----
public SomeDependency() {
}
}
Then you need #Binds (or #Provides) only if you need to "bind" it as an implementation of an interface, or at least a different type than its concrete type.
Also, if your object has an #Inject constructor, you would not need to instantiate it in the module, because Dagger already knows how to instantiate it.
So to fix your code, all you need to do is:
// #Module
// abstract class ApplicationModule {
// #Provides
// static SomeDependency provideDepdendencyOne() {
// return new SomeDependency();
// }
// }
Solved.
The issue I'm facing is about using App level and Activity level dependencies in single Activity.
Let's assume I have APP level dependency:
#Module
public class FormatModule {
#Provides
#Singleton
public DecimalFormat getDecimalFormat(){
DecimalFormat df = new DecimalFormat("0,000.00");
return df;
}
public class App extends Application {
private static AppComponent AppComponent;
public static AppComponent getAppComponent() {
return AppComponent;
}
#Override
public void onCreate () {
super.onCreate();
AppComponent = DaggerAppComponent
.builder()
.apiModule(new ApiModule())
.build();
}
}
and Component annotated #Singleton.
There is Activity level dependency:
#Module
public class MainActivityModule {
#Provides
Presenter getPresenter(){
return new Presenter();
}
#Component(modules = {MainActivityModule.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
In MainActivity I initialise component with this code:
MainActivityComponent mainActivityComponent =
DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule())
.contextModule(new ContextModule(this))
.build();
mainActivityComponent.inject(this);
And in classes that use ony App level dependencies:
App.getAppComponent().inject(this);
The question is how can I use both App and Activity level dependencies in MainActivity?
To make this work, you need to establish a component dependency from your MainActivityComponent onto your AppComponent.
#Component(
modules = {MainActivityModule.class},
dependencies = {AppComponent.class}) // <-- this
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
This tells Dagger that it may call zero-arg methods on AppComponent to supply dependencies that MainActivityComponent needs, including dependencies of objects that MainActivity injects. This makes it particularly well-suited for depending on other Dagger components, since you can add those zero-arg methods onto AppComponent and Dagger will supply the implementations. However, for the sake of clarity or avoiding dependency cycles, you might also choose to list an interface as the dependency and then have a DaggerAppComponent implementation provided instead.
You'll need to supply an implementation of AppComponent as a part of ActivityComponent's builder:
MainActivityComponent mainActivityComponent =
DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule())
.contextModule(new ContextModule(this))
.appComponent(App.getAppComponent()) // <-- this
.build();
mainActivityComponent.inject(this);
Important: The only bindings available to you in MainActivityComponent will be the ones that are exposed as zero-arg methods on the interface or class that you list as a dependency ("provision methods"). If you supply a binding using a #Provides method on an AppComponent module, it will not appear in MainActivityComponent unless you add a getter for it on AppComponent itself. This allows you to be specific about what you inherit from AppComponent, but can be seen as a maintenance burden.
#Component(modules = ModuleA.class) public interface ComponentA {
BindingOne bindingOne();
}
#Module public abstract class ModuleA {
#Provides static BindingOne getBindingOne() { return BindingOne.INSTANCE; }
#Provides static BindingTwo getBindingTwo() { return BindingTwo.INSTANCE; }
}
// ComponentB has access to BindingOne but not BindingTwo, because it can only see
// what is available in ComponentA, not ComponentA's module set that includes ModuleA.
#Component(dependencies = ComponentA.class) public interface ComponentB { /* ... *}
Side notes
If MainActivityModule has a default constructor or other public no-arg constructor, you don't need to supply it in your builder. Dagger will create one for you.
getDecimalFormat and getPresenter don't use any instance state, so you can make them static; Dagger will detect this and make static calls instead of virtual method calls that are slightly slower on Android. If you switch all of your #Module methods to static #Provides or abstract #Binds methods, you can change your Module to an interface or abstract class, which means that Dagger can and will skip instantiating the method at all.
You need to list all of the bindings from AppComponent that you want on MainActivityComponent because Dagger can generate code for AppComponent and MainActivityComponent separately. As an alternative to component dependencies, you can choose to use subcomponents, where Dagger generates code for MainActivityComponent as an implementation detail of AppComponent, and you get your builder from AppComponent instead of a static method on DaggerMainActivityComponent. This establishes a tighter coupling between MainActivityComponent and AppComponent, but allows you to skip defining the zero-arg methods on AppComponent because Dagger can inspect what MainActivityComponent needs at compile time and provide those bindings privately.
One existing framework for a subcomponent hierarchy of Android Application/Activity/Fragment injection is dagger.android, which automates the creation and installation of subcomponents for each Android-created object including BroadcastReceiver, ContentProvider, and Service. As you get more comfortable with Dagger architecture, it may be something to consider.
To simplify problem prerequisites suppose the following sources set:
src/main/java/di
ApplicationComponent.java:
#PerApplication
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(MyApplication target);
}
ApplicationModule.java
#Module
public class ApplicationModule {
#Provides #PerApplication
CoffeeMaker provideCoffeeMaker(CoffeeMakerImpl impl) { return impl; }
}
src/debug/java/di
DebugApplicationComponent.java:
#PerApplication
#Component(modules = {DebugApplicationModule.class})
public interface DebugApplicationComponent extends ApplicationComponent {}
DebugApplicationModule.java
#Module(includes = ApplicationModule.class)
public class DebugApplicationModule {
#Provides #PerApplication
Heater provideHeater(HeaterImpl impl) { return impl; }
}
src/main/java/app
CoffeeMakerImpl.java
class CoffeeMakerImpl implements CoffeeMaker {
#Inject CoffeeMakerImpl(Heater heater) {}
}
In MyApplication.java
#Inject CoffeeMaker coffeeMaker;
DaggerDebugApplicationComponent.
builder().
applicationModule(new ApplicationModule(application)).
debugApplicationModule(new DebugApplicationModule()).
build().
inject(this);
When compiling the project I got error:
Error:(18, 10) error: Heater cannot be provided without an #Provides-annotated method.
app.Heater is injected at
app.CofeeMakerImpl.<init>(heater)
app.CofeeMakerImpl is injected at
app.MyApplication
app.MyApplication is injected at
di.ApplicationComponent.inject(target)
I expect, that due DebugApplicationModule includes ApplicationModule, and I pass to DebugApplicationComponent both of these modules, DebugApplicationComponent, should see both Heater and CoffeeMaker.
What could be a reason, why Heater is not accessible in injection chain?
P.S. Thanks to #DavidMedenjak, solution is quite simple: just make ApplicationComponent a plain interface, removing #PerApplication #Component(modules = {ApplicationModule.class}) line.
See his answer, there are some useful advices there.
I expect, that due DebugApplicationModule includes ApplicationModule [...] should see both Heater and CoffeeMaker.
DebugApplicationModule compiles fine, the problem is that your ApplicationComponent cannot compile, since it does not know how to inject MyApplication.
#PerApplication
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(MyApplication target);
}
Here you declare that this component knows how to inject MyApplication, but it has no access or knowledge about Heater, as you can see in the compile error:
error:(18, 10) error: Heater cannot be provided without an #Provides-annotated method.
app.Heater is injected at
app.CofeeMakerImpl.<init>(heater)
app.CofeeMakerImpl is injected at
app.MyApplication
app.MyApplication is injected at <- trying to inject MyApplication
di.ApplicationComponent.inject(target) <- ApplicationComponent has the problem
Make sure to always look very closely at the compile errors.
You only add this knowledget to your DebugApplicationModule, but ApplicationComponent also says it can inject the class, which it can't.
To solve this the obvious solutions would be to remove the inject() signature from your ApplicationComponent and move it to your DebugApplicationComponent, since it just doesn't know how to inject it. The full information to inject your Application is within your DebugApplicationComponent, and later maybe also ReleaseApplicationComponent.
Since you probably want an interface that your components implement, you could also just remove the #Component annotation from ApplicationComponent.
public interface ApplicationComponent {
void inject(MyApplication target);
}
Make it a plain interface, and Dagger will not try to generate an implementation.
You could also have a look at component builder methods, where you could bind / add different objects / modules to a component.
I'm trying to wrap my head around scopes in Dagger 2, specifically the lifecycle of scoped graphs. How do you create a component that will be cleaned up when you leave the scope.
In the case of an Android application, using Dagger 1.x you generally have a root scope at the application level which you'd extend to create a child scope at the activity level.
public class MyActivity {
private ObjectGraph mGraph;
public void onCreate() {
mGraph = ((MyApp) getApplicationContext())
.getObjectGraph()
.plus(new ActivityModule())
.inject(this);
}
public void onDestroy() {
mGraph = null;
}
}
The child scope existed as long as you kept a reference to it, which in this case was the lifecycle of your Activity. Dropping the reference in onDestroy ensured the scoped graph was free to be garbage collected.
EDIT
Jesse Wilson recently posted a mea culpa
Dagger 1.0 badly screwed up its scope names ... The #Singleton annotation is used for both root graphs and custom graphs, so it's tricky to figure out what the actual scope of a thing is.
and everything else I've read/heard points towards Dagger 2 improving the way scopes work, but I'm struggling to understand the difference. According to #Kirill Boyarshinov's comment below, the lifecycle of a component or dependency is still determined, as usual, by concrete references. So is the difference between Dagger 1.x and 2.0 scopes purely a matter of semantic clarity?
My understanding
Dagger 1.x
Dependencies were either #Singleton or not. This was equally true of dependencies in the root graph and subgraphs, leading to ambiguity as to which graph the dependency was bound to (see In Dagger are Singletons within the sub-graph cached or will they always be recreated when a new activity sub-graph is constructed?)
Dagger 2.0
Custom scopes allow you to create semantically clear scopes, but are functionally equivalent to applying #Singleton in Dagger 1.x.
// Application level
#Singleton
#Component( modules = MyAppModule.class )
public interface MyAppComponent {
void inject(Application app);
}
#Module
public class MyAppModule {
#Singleton #Named("SingletonScope") #Provides
StringBuilder provideStringBuilderSingletonScope() {
return new StringBuilder("App");
}
}
// Our custom scope
#Scope public #interface PerActivity {}
// Activity level
#PerActivty
#Component(
dependencies = MyAppComponent.class,
modules = MyActivityModule.class
)
public interface MyActivityComponent {
void inject(Activity activity);
}
#Module
public class MyActivityModule {
#PerActivity #Named("ActivityScope") #Provides
StringBuilder provideStringBuilderActivityScope() {
return new StringBuilder("Activity");
}
#Name("Unscoped") #Provides
StringBuilder provideStringBuilderUnscoped() {
return new StringBuilder("Unscoped");
}
}
// Finally, a sample Activity which gets injected
public class MyActivity {
private MyActivityComponent component;
#Inject #Named("AppScope")
StringBuilder appScope
#Inject #Named("ActivityScope")
StringBuilder activityScope1
#Inject #Named("ActivityScope")
StringBuilder activityScope2
#Inject #Named("Unscoped")
StringBuilder unscoped1
#Inject #Named("Unscoped")
StringBuilder unscoped2
public void onCreate() {
component = Dagger_MyActivityComponent.builder()
.myApplicationComponent(App.getComponent())
.build()
.inject(this);
appScope.append(" > Activity")
appScope.build() // output matches "App (> Activity)+"
activityScope1.append("123")
activityScope1.build() // output: "Activity123"
activityScope2.append("456")
activityScope1.build() // output: "Activity123456"
unscoped1.append("123")
unscoped1.build() // output: "Unscoped123"
unscoped2.append("456")
unscoped2.build() // output: "Unscoped456"
}
public void onDestroy() {
component = null;
}
}
The takeaway being that using #PerActivity communicates your intention regarding the lifecycle of this component, but ultimately you can use the component anywhere/anytime. Dagger's only promise is that, for a given component, scope annotated methods will return a single instance. I also assume Dagger 2 uses the scope annotation on the component to verify that modules only provide dependencies that are either in the same scope or non-scoped.
In Summary
Dependencies are still either singleton or non-singleton, but #Singleton is now intended for application-level singleton instances and custom scopes are the preferred method for annotating singleton dependencies with a shorter lifecycle.
The developer is responsible for managing the lifecycle of components/dependencies by dropping references that are no longer needed and responsible for ensuring that components are only created once in the scope for which they are intended, but custom scope annotations make it easier to identify that scope.
The $64k Question*
Is my understanding of Dagger 2 scopes and lifecycles correct?
* Not actually a $64'000 question.
As for your question
What determines the lifecycle of a component (object graph) in Dagger 2?
The short answer is you determine it. Your components can be given a scope, such as
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ApplicationScope {
}
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityScope {
}
These are useful for you for two things:
Validation of scope: a component can only have unscoped providers, or scoped providers of the same scope as your component.
.
#Component(modules={ApplicationModule.class})
#ApplicationScope
public interface ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
}
#Module
public class ApplicationModule {
#ApplicationScope //application-scoped provider, only one can exist per component
#Provides
public Something something() {
return new Something();
}
#Provides //unscoped, each INJECT call creates a new instance
public AnotherThing anotherThing() {
return new AnotherThing();
}
}
Allows for sub-scoping your scoped dependencies, thus allowing you to create a "subscoped" component that uses the provided instances from the "superscoped" component.
This can be done with #Subcomponent annotation, or component dependencies. I personally prefer dependencies.
#Component(modules={ApplicationModule.class})
#ApplicationScope
public interface ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
ActivityComponent newActivityComponent(ActivityModule activityModule); //subcomponent factory method
}
#Subcomponent(modules={ActivityModule.class})
#ActivityScope
public interface ActivityComponent {
ThirdThingy thirdThingy();
void inject(SomeActivity someActivity);
}
#Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
//...
}
ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = applicationComponent.newActivityComponent(new ActivityModule(SomeActivity.this));
Or you can use component dependencies like so
#Component(modules={ApplicationModule.class})
#ApplicationScope
public class ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
}
#Component(dependencies={ApplicationComponent.class}, modules={ActivityModule.class})
#ActivityScope
public interface ActivityComponent extends ApplicationComponent {
ThirdThingy thirdThingy();
void inject(SomeActivity someActivity);
}
#Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
//...
}
ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule(SomeActivity.this)).build();
Important things to know:
A scoped provider creates one instance for that given scope for each component. Meaning a component keeps track of its own instances, but other components don't have a shared scope pool or some magic. To have one instance in a given scope, you need one instance of the component. This is why you must provide the ApplicationComponent to access its own scoped dependencies.
A component can subscope only one scoped component. Multiple scoped component dependencies are not allowed.