I'm trying to wrap my head around the use of Dagger 2 in my project with Retrofit, RxJava, MVP implementation. However, I'm starting small by reading guides and watching videos and just when I thought I understood how it works, it appears I don't. Here is the sample I'm trying to understand.
Module:
#Module
public class AppModule {
private App app;
public AppModule(App app) {
this.app = app;
}
#Provides #Singleton public SharedPreferences provideSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(app);
}
#Provides #Singleton public HelloModel provideHelloModel(SchedulerProvider schedulerProvider,
HelloDiskCache helloDiskCache, HelloService helloService, Clock clock) {
return new HelloModel(schedulerProvider, helloDiskCache, helloService, clock);
}
#Provides public HelloDiskCache provideHelloDiskCache(SharedPreferences prefs) {
return new HelloDiskCache(prefs);
}
#Provides public HelloService provideHelloService() {
return new HelloService();
}
#Provides public SchedulerProvider provideSchedulerProvider() {
return SchedulerProvider.DEFAULT;
}
#Provides public Clock provideClock() {
return Clock.REAL;
}
#Provides #Nullable public LayoutInflaterFactory provideLayoutInflaterFactory() {
return null;
}
Component
#Component(
modules = AppModule.class
)
#Singleton
public interface AppComponent {
HelloModel getHelloModel();
HelloDiskCache getHelloDiskCache();
MainActivity inject(MainActivity activity);
HelloFragment inject(HelloFragment fragment);
}
In the fragment, presenter is injected (where is this coming from?)
#Inject HelloPresenter presenter;
And in the presenter, there is a constructor injection
#Inject HelloPresenter(HelloModel helloModel) {
this.model = helloModel;
}
So, how come we can inject a presenter in the fragment, and why can we inject in the presenter? The answer does not have to be very elaborate I just feel stupid because I can't trace where it is coming from.
#Inject-annotated constructor is an alternative to a #Provides-annotated method for a dependency when there's not much configuration to do.
Since HelloPresenter has such constructor, Dagger discovers it automatically and is able to inject this dependency or use it to construct and provide other objects in the graph.
A class with an #Inject-annotated constructor can itself be annotated with a scope annotation (e.g., #Singleton). In this case, only components with the matching scope will be able to see it.
In general, this type of providing dependencies is less verbose, but not always you can use it (e.g., Activity, SharedPreferences). In such cases you have to go with a #Module and a #Provides method.
You can look at this sample where Dagger2 used with MVP Architecture
Dagger2 Android with MVP
Related
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.
I am using dagger for dependency injection, I apologize for not diving into deep and getting my hands on :)
I am using two modules(ApplicationModule, ContactServiceModule), with a component (AppComponent). I have initialized the Dagger in App.java, and I am trying to inject dependencies to a backgroud Service.
Here is the code snippet.
1)ApplicationModule.java
#Module
public class ApplicationModule {
private final App mApp;
private Service contactService;
public ApplicationModule(App app) {
mApp = app;
}
#Provides
#Singleton
public ContactModel contactModel(SQLiteDatabase database) {
return new ContactModel(mApp, database);
}
#Provides
#Singleton
public Context appContext() {
return mApp;
}
#Provides
#Singleton
public ContactController contactController() {
return new ContactController(mApp.getAppComponent());
}
//.....Some more code
}
2)ContactServiceModule.java
#Module
public class ContactServiceModule {
ContactService contactService;
public ContactServiceModule(ContactService contactService){
this.contactService =contactService;
}
#Provides
#Singleton
ContactService provideContactService() {
return this.contactService;
}
}
3)AppComponent.java
#Singleton
#Component(modules = {ApplicationModule.class,ContactServiceModule.class})
public interface AppComponent {
ContactController contactController();
Context appContext();
//...Some code
void inject(ContactController contactController);
//...Some code
void inject(ContactService contactService);
}
4)App.java
public class App extends Application {
private AppComponent mAppComponent;
#Override
public void onCreate() {
super.onCreate();
FlowManager.init(this);
mAppComponent = DaggerAppComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
public AppComponent getAppComponent() {
return mAppComponent;
}
}
5) ContactService.java
public class ContactService extends Service {
#Inject
Context appContext;
#Inject
ContactController contactController;
#Override
public void onCreate() {
super.onCreate();
getAppComponent().inject(this);
}
private AppComponent getAppComponent() {
return ((App)getApplication()).getAppComponent();
}
}
It could be an issue of dependencies of UI threads injected into background services. But I do not understand how should I achieve the same dependencies to be injected into services. Or what should be the Ideal way to communicate between application level dependencies and services. I want the service to be running always in the background and listening to various intents and also communicate to other dependencies like eventbus etc.
The error message:
contactServiceModule must be set at DaggerAppComponent$Builder.build(DaggerAppComponent.java)”
means that you have created a module with dependencies in the constructor (ContactServiceModule which has your Service as a parameter in the constructor). It follows that Dagger 2 cannot instantiate that module automatically and it must be instantiated in the builder when you create your component:
mAppComponent = DaggerAppComponent.builder()
.applicationModule(new ApplicationModule(this))
.contactServiceModule(contactService);
.build();
However there is an underlying issue with the architecture you are trying to create. Services, like Activities, are designed to be autonomous and instantiated by the Android OS. Much in the same way you wouldn't directly pass as an Activity as a dependency to another Activity, you shouldn't make a Service a dependency. Instead you need to use Intent, service binding, or EventBus events to communicate with the service. The Android Service documentation covers this and you should read it carefully before proceeding.
I'm very new to Dagger 2 and I'm trying to get this basic example working with some minor modifications.
This is what I have so far:
Component class
#Component(modules = {MyModule.class})
public interface MyComponent {
void inject(Object object);
}
Module class
#Module
public class MyModule {
#Provides
#Singleton
public Retrofit getRetrofit(){
return new Retrofit();
}
}
Static Injector
public class MyStaticInjector {
private static MyComponent di;
public static void inject(Object object){
if(di == null){
di = DaggerMyComponent.builder().build();
}
di.inject(object);
}
}
The problem is that whenever I do
MyStaticInjector.inject(this);
the annotated fields are still null. I suspect the problem is with the type Object in the interface method. In the example, there's an Activity instead. But I need to use DI in classes that are not activities.
Can anyone help me? Thank you.
Object has no #Inject annotated fields. Thus the injection works just fine—it just has nothing to inject.
You will have to use your actual classes with inject(MyClass) instead of Object, so that the code can be generated and fields can be injected.
Dagger generates source code at compile time. If it does not know about the actual class, it cannot create code for it.
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.
I am trying to convert my singleton CookieUtil to be injected with Dagger into LoginActivity. CookieUtil takes an application context therefor I have set up the following structure :
AndroidModule
#Module(
injects = {
CookieUtil.class,
LoginActivity.class
},
library = true
)
public class AndroidModule {
private final App application;
public AndroidModule(App application) {
this.application = application;
}
/**
* Allow the application context to be injected but require that it be annotated with
* {#link ForApplication #Annotation} to explicitly differentiate it from an activity context.
*/
#Provides
#Singleton
#ForApplication
Context provideApplicationContext() {
return application;
}
#Provides
#Singleton
CookieUtil provideCookieUtil() {
return new CookieUtil();
}
}
CookieUtil (What I want to inject into LoginActivity)
#Singleton
public class CookieUtil {
#Inject Context mContext; // gets injected with a app context. is this right ?
private PersistentCookieStore persistentCookieStore;
private CookieUtil() {
// use injected mContext
persistentCookieStore = new PersistentCookieStore(mContext);
// ...
}
}
LoginActivity (Where I want to inject CookieUtil)
public class LoginActivity extends BaseActivity {
#Inject CookieUtil cookieUtil;
#Override
protected void onCreate(Bundle savedInstanceState) {
// use CookieUtil ...
}
}
I have also set up all the bootstraping stuff from Dagger examples to enable everything to work
BaseActivity
public class BaseActivity extends ActionBarActivity {
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Perform injection so that when this call returns all dependencies will be available for use.
((App) getApplication()).inject(this);
}
}
App
public class App extends Application {
private ObjectGraph graph;
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(getModules().toArray());
// ...
}
protected List<Object> getModules() {
return Arrays.asList(
new AndroidModule(this),
new CupsModule() // Another module I haven't listed
);
}
public void inject(Object object) {
graph.inject(object);
}
}
ForApplication
#Qualifier
#Retention(RUNTIME)
public #interface ForApplication {
}
When I run the code, I get
No injectable members on android.content.Context. Do you want to add
an injectable constructor? required by CookieUtil for AndroidModule
What am I doing wrong ?
Everything still looks like magic to me as I don't fully aware of how to wire everything up, so detailed explanation would be very much appreciated.
Also, would be helpful if someone could point me to an explanation on dagger modules, when does it make sense to separate into two different modules ? What logical pieces do they usually bind ?
Thanks
EDIT
Changed suggested by Christian Gruber
#Singleton
public class CookieUtil {
private Context mContext;
private PersistentCookieStore persistentCookieStore;
#Inject
public CookieUtil(Context context) {
// use injected context
mContext = context
persistentCookieStore = new PersistentCookieStore(mContext);
// ...
}
}
Cookie cannot have a private constructor and still be created (provisioned) by Dagger. You can have a package-friendly constructor, and then it should work without #Provides CookiUtil .... Having the provides method for a class you control and could make injectable seems wasteful.
Generally speaking, Dagger considers a "binding" according to a "key" which is its type (with concrete type parameters, such as Foo<Bar>) along with any #Qualifier. So the type Foo<Bar> is different from #ForApplication Foo<Bar>. A binding is requested wherever #Inject occurs, and is supplied wherever #Provides occurs (or for unqualified bindings, if a class has an #Inject-marked constructor or fields, then an implicit binding is supplied. For every #Inject field or constructor parameter there must be a present binding for that key. Dagger needs to be able to see the methods it uses to create things, so generally private fields, methods, and constructors are not possible.
Also, please never simply inject Context without a qualifier. Or better, inject Application or Activity if that's the Context subtype you mean. Your graph WILL be impossible to manage if you don't distinguish between the 30,000 things that Android calls Context subtypes. (snark)