Dagger 2 scope and subcomponents - java

I am trying to make my app better and code more maintainable using Dagger2 I caught general idea, but still cannot figure out how scopes are managed by Dagger2
I injected dagger into my project (sounds funny).
I created ApplicationComonent component and it works perfectly in my project.
Here is my code.
#Singleton
#Component(modules = {
ApplicationModule.class,
ThreadingModule.class,
NetworkModule.class,
DatabaseModule.class,
ServiceModule.class,
ParseModule.class,
PreferencesSessionModule.class})
public interface ApplicationComponent {
ActivityComponent activityComponent(ActivityModule activityModule);
void inject(BaseActivity baseActivity);
void inject(MainAppActivity mainAppActivity);
void inject(MyApplication application);
void inject(BaseFragment baseFragment);
void inject(MyService service);
void inject(RegistrationIntentService service);
}
I create my component instance in MyApplication class like this
private void initializeAndInjectComponent() {
mApplicationComponent =
DaggerApplicationComponent
.builder()
.threadingModule(new ThreadingModule(1))
.applicationModule(new ApplicationModule(this))
.networkModule(new NetworkModule(
MyService.API_SERVER_BASE_URL,
MyService.TIMEOUT))
.build();
mApplicationComponent.inject(this);
}
And I can obtain component in order to inject in in my Activities
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().inject(this);
Everything works perfectly.
To add each method as well as module class is annotated with #Singleton scope, all modules related to the ApplicationComponent
Now I want to make dependencies better and I have seen a lot of examples with custom scopes like #PerActivity, #PerFragment. I have a lot of questions, but about this later.
So I created ActivityComponent
#PerActivity
#Subcomponent(
modules = {
NetworkServiceModule.class,
ActivityModule.class,
PermissionModule.class
})
public interface ActivityComponent {
Activity activity();
void inject(BaseActivity baseActivity);
}
All modules looks like this
#PerActivity
#Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
this.mActivity = activity;
}
#Provides
#PerActivity
Activity provideActivity() {
return this.mActivity;
}
}
I have following dependencies in my BaseActivity
// Dependencies from ApplicationComponent
#Inject
protected ApplicationSettingsManager mApplicationSettingsManager;
#Inject
protected ScheduledThreadPoolExecutor mPoolExecutor;
// Dependencies from ActivityComponent
#Inject
protected SpiceManager mSpiceManager;
#Inject
protected PermissionController mPermissionController;
And in my onCreate() method I am injecting as following
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().activityComponent(new ActivityModule(this)).inject(this);
Before creating subcomponent ActivityComponent it was
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().inject(this);
Now I got an error
Error:(34, 10) error: com.octo.android.robospice.SpiceManager cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method.
BaseActivity.mSpiceManager
[injected field of type: com.octo.android.robospice.SpiceManager mSpiceManager]
I cannot figure out where is problem, what I missed.
My questions about scopes in dagger2.
Everything but #Singleton is ignored by Dagger 2, am I right ?
I don't understand how life of component is managed ? I have only one idea
When you use #Singleton annotation dagger is creating object in some static pool that will exist during whole application lifecycle, and will be destroyed when JVM process (dalvik VM,ART) instance will be destroyed.
When you use any other annotation is just for you as developer to better maintain code, #PerActivity, #PerFragment is just custom annotation nothing more. And in case you place #PerFragment component in Application class it will live as long as Application lives. Am I right ?
So I understand this like this, if dagger finds #Singleton annotation it will add static reference to component when it is created first time and in case of any other annotation it won't hold reference to component.
I would be very grateful for any help with problems described above.
UPDATE
Thank you David Medenjak for great answer, I got much better understanding of Dagger2.
I have also just found the problem, as far as I am using separate Activity component now, I forgot about two lines in ApplicationComponent and change inejction in my MainActivity to ActivityComponent instead of ApplicationComponent, so for sure it couldn't resolve dependencies from subcomponent.
void inject(BaseActivity baseActivity);
void inject(MainAppActivity mainAppActivity);
Now everything works perfectly, I like Dagger2 and separated architecture.

A bit radical, but to simplify things:
All Scope annotations are nothing but syntactic sugar—including #Singleton.
Scopes mostly just provide compile time checks. Cyclic dependencies, or errors about things that you might have missed. #Singleton is just like any other scope, the only difference is that it is an already existing annotation and you don't have to create it yourself. You could just use #MySingleton instead.
[...] dagger is creating object in some static pool that will exists during whole application lifecycle
No. Dagger does nothing static. You have component objects. Those components hold your objects created by modules. If an object in a component has the scope of the component, it will only be created once in that exact component. If you decide to create 2 AppComponent objects, you will have 2 objects of each #Singleton annotated object, each within its component. This is why you should keep the reference to the component. Most implementations that I have seen or used hence keep their AppComponent within their Application. If you do this, you can use it like a singleton—it is still just a POJO.
[...]you place #PerFragment component in Application class it will live as long as Application lives.
Yes. As already covered by the paragraph above, it is just an object. Keep the reference, you keep the objects. Throw it away or create a new one and you have new objects (defined within in this component / scope). You should although not keep activity or fragment scoped components any place besides in activities or fragments respectively, since keeping them e.g. in your app component will most likely lead to a memory leak. (If it doesn't, you probably would not have needed the activity or fragment scope.)
if dagger finds #Singleton annotation it will add static reference to component when it is created first time and in case of any other annotation it won't hold reference to component.
Again, no. Nothing static. Plain old java objects. You can have multiple #Singleton components with their own objects, but you probably shouldn't (Although this is what makes instrumentation testing possible / easy—just swap components.)
Your mentioned error
SpiceManager cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method.
This means that the component you are trying to inject your object with can not find any way to produce or provide a SpiceManager. Make sure you provide it from your AppComponent or some other place, are not missing any annotations, etc.

Related

Using Dagger 2.11 with android modular project

I started working on a new Android project from scratch. After understanding the project scope and requested features, I've came up with a modular architecture (basically wrapping every feature into a feature or android module) that looks as following
Everything looks perfect until I wanted to introduce dagger to glue all the modules. The problem is that I want every module to has its own dagger component/subcomponent and it's modules in order to provide dependencies and expose them the graph to be using by other component or the parent one.
Google official dagger documentation states that subcomponents has direct access to parent component dependencies' and not vice versa. However, in my case the base component require dependencies from the data module and this latter itself require dependencies from the network module.
is there any solution for this problem knowing that i want every android module to have its own sub-component preferably? If not, is there any solution anyway?
Thank you.
Edit:
Here is how my project structure looks like
And this is how I setup my dagger graph
My AppComponent(Dagger root)
#Singleton
#Component(modules = {
AppModule.class,
ActivityBuilder.class,
AndroidSupportInjectionModule.class
})
public interface AppComponent {
void inject(CatApp application);
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
}
My App Module
#Module(subcomponents = DataComponent.class)
public class AppModule {
#Provides
#Singleton
Context provideContext(Application application) {
return application.getApplicationContext();
}
}
My DataComponent (located at the data android module)
#Subcomponent(modules = DataModule.class)
public interface DataComponent {
#Subcomponent.Builder
interface Builder {
DataComponent build();
}
}
Data module (located at data android module) that should provide the implementation of SystemManager
#Module(subcomponents = NetworkComponent.class)
public class DataModule {
#Provides
#Singleton
ISystemManager provideSystemManager(SystemManager systemManager) {
return systemManager;
}
}
Network Component (located at Network Android Module)
#Subcomponent(modules = NetworkModule.class)
public interface NetworkComponent {
#Subcomponent.Builder
interface Builder {
NetworkComponent build();
}
}
Network Module (located at Network Android Module) and should provide implementation of INetWorkManager
#Module
public class NetworkModule {
#Provides
#Singleton
INetworkManager provideNetworkManager(NetworkManager networkManager) {
return networkManager;
}
}
I am using #Inject annotation at all constructors so my configurations is all setup but the issue is that dagger doesn't compiles these subcomponent for some reason and I get this error when compiled:
Error:(27, 8) error: [dagger.android.AndroidInjector.inject(T)] com.github.andromedcodes.network.INetworkManager cannot be provided without an #Provides-annotated method.
com.github.andromedcodes.network.INetworkManager is injected at
com.github.andromedcodes.data.SystemManager.<init>(networkManager)
com.github.andromedcodes.data.SystemManager is injected at
com.github.andromedcodes.data.di.DataModule.provideSystemManager(systemManager)
com.github.andromedcodes.domain.managers.ISystemManager is injected at
com.github.andromedcodes.domain.interactors.CheckSystemAvailability.<init>(systemManager)
com.github.andromedcodes.domain.interactors.CheckSystemAvailability is injected at
com.github.andromedcodes.chasseautrsor.views.Splash.SplashPresenter.<init>(checkSystemAvailability)
com.github.andromedcodes.chasseautrsor.views.Splash.SplashPresenter is injected at
com.github.andromedcodes.chasseautrsor.di.SplashModule.bindSplashPresenter(presenter)
com.github.andromedcodes.chasseautrsor.views.Contract.Presenter is injected at
com.github.andromedcodes.mvp.BaseActivity.mPresenter
com.github.andromedcodes.chasseautrsor.views.SplashScreenActivity is injected at
dagger.android.AndroidInjector.inject(arg0)
How can I fix this issue knowing that I want to provide ISystemManager implementation at Data android Module and INetworkManager at Network Android Module?
Thank you.
Subcomponents automatically have access to objects bound in the parent components' graph, which makes sense, because subcomponents have exactly one parent component—there's no ambiguity. Parent components do not have automatic access to subcomponents' graph because you can create as many subcomponent instances as you'd like; it's not clear which instance you're trying to access. In general, unless you need different variations on an object graph (which you'd do with private modules or child injectors in Guice) or unless you wanted to hide implementation details (e.g. internal network objects), you may be better off installing your modules all in the same Component and skipping the subcomponent strategy.
However, if you do want to separate your graph or create multiple subcomponent instances, you could also create a subcomponent instance in a scoped #Provides method. That way NetworkComponent has a separate graph with private bindings, but can also use dependencies you expose in AppComponent, and you can also ensure that there is exactly one copy of NetworkComponent and its relevant bindings in your graph. You'll also need to put a getter (provision method or factory method) on the Subcomponent, so you can access some of its bindings from outside, in exactly the same way that you need a getter or injector method on a #Component for it to be useful.
#Subcomponent(modules = NetworkModule.class)
public interface NetworkComponent {
/** Allow anyone with a NetworkComponent instance to get the INetworkManager. */
INetworkManager getINetworkManager();
#Subcomponent.Builder
interface Builder {
NetworkComponent build();
}
}
/**
* Creates a singleton NetworkComponent. Install this in AppComponent's module,
* or in your data module if that encapsulates network calls.
*/
#Singleton #Provides NetworkComponent networkComponent(
NetworkComponent.Builder builder) {
return builder.build();
}
/** Make the INetworkManager accessible, but not the NetworkManager impl. */
#Provides static provideNetworkManager(NetworkComponent networkComponent) {
return networkComponent.getINetworkManager(); // add this to NetworkComponent
}
For further reference, see the "Subcomponents for Encapsulation" section on in the Dagger 2 docs on Subcomponents:
Another reason to use subcomponents is to encapsulate different parts of your application from each other. For example, if two services in your server (or two screens in your application) share some bindings, say those used for authentication and authorization, but each have other bindings that really have nothing to do with each other, it might make sense to create separate subcomponents for each service or screen, and to put the shared bindings into the parent component.
In the following example, the Database is provided within the #Singleton component, but all of its implementation details are encapsulated within the DatabaseComponent. Rest assured that no UI will have access to the DatabaseConnectionPool to schedule their own queries without going through the Database since that binding only exists in the subcomponent.

Dagger 2 Injecting Constructors

I'm starting to use Dagger 2 in an application I'm developing but I have some questions about how Dagger 2 works.
I get the all the logic behind the #Provides methods and the #Inject annotation for initialising your dependencies, but the #Inject annotation to class constructors kind of bugs my mind.
For example:
Im my app, I have one module defined, the ContextModule, to retrieve the context of my application:
ContextModule.java
#Module
public class ContextModule {
private final Context context;
public ContextModule(Context context) {
this.context = context;
}
#Provides
public Context context() {
return this.context;
}
}
This module is used by my BaseActivityComponent:
BaseActivityComponent.java
#BaseActivityScope
#Component(modules = ContextModule.class)
public interface BaseActivityComponent {
void injectBaseActivity(BaseActivity baseActivity);
}
So far so good.. then I have an AuthController class, that depends on the context and I want to inject it in my BaseActivity. So in my AuthControllers.class I have something like:
public class AuthController {
private Context context;
#Inject
public AuthController(Context context) {
this.context = context;
}
public void auth() {
// DO STUFF WITH CONTEXT
}
}
And I inject it in my BaseActivity like:
public class BaseActivity extends AppCompatActivity {
#Inject
AuthController authController;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BaseActivityComponent component = DaggerBaseActivityComponent.builder()
.contextModule(new ContextModule(this))
.build();
component.injectBaseActivity(this);
authController.auth();
}
}
Now my question is, how does dagger knows that my AuthControllers is a dependency for BaseActivity? Just by declaring
#Inject
AuthController authController;
it's like the same thing as if I created a ControllerModule like:
#Module(includes = ContextModule.class)
public class ControllerModule {
#Provides
AuthController authController(Context context) {
return new AuthController(context);
}
}
And then in my BaseActivityComponent I would add my AuthController getter and change my dependency module to ControllersModule:
#BaseActivityScope
#Component(modules = ControllersModule.class)
public interface BaseActivityComponent {
void injectBaseActivity(BaseActivity baseActivity);
AuthController getAuthController();
}
When I call injectBaseActivity(this) it "tells" dagger that all #Inject annotations are dependencies of my class, and then it searchers my project for #Inject annotated constructors that matches that type?
I thought a good thing about Dagger 2 is that the Module files could be used as a "documentation" of my dependencies three. But if just add #Inject in all the constructors I have control of, couldn't it get a little confusing in the future, since you don't know what actually depends on what? (I mean, you know what depends on what, you just have to browse a lot of files to really find out)
Is there any best practices for when using #Inject annotations in constructors or when to add the #Provides method in Modules files?
I get that using #Inject in constructor I don't need to change the constructor definition in my Module file, but is there any downside?
Thanks.
When I call injectBaseActivity(this) it "tells" dagger that all #Inject annotations are dependencies of my class, and then it searches my project for #Inject annotated constructors that matches that type?
Exactly. But it's not done when you call injectBaseActivity, but it all happens during compile time. This is one way of annotation processing (another makes use of reflection at runtime).
When you build your project the dagger-annotation-processor you include (as a dependency)in your build.gradle file gets called with a list of all your fields, classes, etc annotated by the #Inject annotation and builds a dependency graph with it. It then resolves the graph, generating source code that provides all the dependencies for the items on the graph.
injectBaseActivity just executes the code which was generated before, and assigns all the dependencies to your object. It is proper source code, which you can read, and debug.
The reason this is a compile step—simply put—is performance and validation. (e.g. If you have some dependency cycle, you get a compile error)
how does dagger knows that my AuthControllers is a dependency for BaseActivity?
#Inject
AuthController authController;
By annotating the field #Inject dagger knows you want an AuthController. So far so good. Now dagger will look for some means to provide the controller, looking for it within the component, the components dependencies, and the components modules. It will also look whether the class can be supplied on its own, because it knows about its constructor.
How does dagger know about the objects constructor if you don't include it in any module?
#Inject
public AuthController(Context context) { /**/ }
By annotating the constructor with inject you also told dagger that there is a class called AuthController and you need a context for it to be instantiated. It is basically the same as adding it to your module.
A module #Provides method should be used if you don't have the source code to just add the #Inject annotation to the constructor, or if the object needs further initialization. Or in your case...
[...]the Module files could be used as a "documentation" of my dependencies tree [...]
Yes, of course you could do that. But as your project grows you will have to maintain a lot of unnecessary code, since the same could have been done with a simple annotation on the constructor.
Is there any best practices for when using #Inject annotations in constructors or when to add the #Provides method in Modules files?
If you want to provide different versions for a different context (e.g. implementing an interface in 2 different ways) there is also the #Binds annotation that tells dagger which class you wish to provide as implementation.
Other than that I believe you should always use constructor injection when possible. If something changes you don't have to touch any other parts of your code, and it is just less code that you write, and hence less places where you could include a bug.
Also Dagger can and does optimize a lot by knowing more, and if you implement unnecessary code it will have to work with the overhead you introduced
Of course in the end it is all up to what you think is best. After all it is you that has to work with your code ;)

Dagger 2 on Android. Different ways to store and access a #Singleton Component

This is the Nth question about how to store #Singleton scoped Dagger 2 Components whose lifetime should equal the application's lifetime.
In Android apps using Dagger 2 there is usually at least one Component which is #Singleton scoped and should last for all the application's lifetime: because of these requirements it is usually initialised and stored inside a custom Application class.
Since the instance of this Component must be reachable in all parts of our Application I've seen code like this:
1. Store the component in a public static variable inside the application class.
public class App extends Application {
public static AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this)).build();
}
}
This way it can be accessed anywhere else with:
App.appComponent.inject(this);
2. Store the component in a private variable inside the application instance and create a static accessor for it.
public class App extends Application {
private static AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this)).build();
}
public static AppComponent getAppComponent() {
return appComponent;
}
}
This way it can be accessed anywhere else with:
App.getAppComponent().inject(this);
3. Store the component in a private variable inside the application instance and create a non static accessor for it.
public class App extends Application {
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this)).build();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
This way it can be accessed only from class instances which hold a reference to a Context:
// From within an Activity.
((App) getApplication()).getAppComponent().inject(this);
// From within a Fragment.
((App) getActivity().getApplication()).getAppComponent().inject(this);
// From within any other class which holds a reference to a Context.
((App) context.getApplicationContext()).getAppComponent().inject(this);
This last way makes it pretty much compulsory to pass a Context reference to any class willing to access the Component (even if that Context isn't needed by that class for any other purposes).
IMHO having to "manually inject" a Context instance only to access the injector itself sounds a bit counter intuitive.
On the other side many advise against using static variables but: why? If an object must stay in memory for the application's lifetime (which means for the whole lifetime of the JVM instance) what's the problem if it's stored in a static variable?
Others say that static stuff can't be mocked in tests and it's true, though I'm not sure I totally get this because it is the DI pattern which enables easy mocking/testing and not the injector itself, so why would we want to mock the injector itself?
What are the pros and cons of these alternatives? Are there any other possible alternatives besides the ones already mentioned here?
With 1 and 2 you are using static references. This is a good thread about why to avoid them
Why are static variables considered evil?
So the only option left is the 3rd. That is what I am using on my projects.
About if you should pass the context as argument or not, depends on the architecture of your project and how you designed the Dagger dependencies. Personally I don't have that problem because I am only injecting in Activities/Fragments. Can you give me an example where you need to pass the context to inject dependencies?
I use method #2. The main problem with method #1 is that you're exposing a mutable field. If your module doesn't require a Context to construct, you could make the field final. But as a matter of style, I still prefer not to expose fields.
You should normally avoid global state, especially in Android because of the complex and sometimes unintuitive lifecycles of components and the VM itself. But Application is the exception to this rule. Exactly one instance of it exists per VM, and its onCreate() method is called exactly once, before any other component is created. This makes it an acceptable place to create and store a static singleton.

Getting Dagger Component without access to Application

I want to use injecting in classes like Adapter or custom object, which don't have access to MyApplication class which extends Application.
How can I get access to component?
Is it good approach to use static methods like below?
public class MyApplication extends Application {
private static MyComponent component;
#Override
public void onCreate() {
super.onCreate();
component = DaggerMyComponent.builder()
.appModule(new AppModule(this))
.helperModule(new HelperModule())
.build();
}
public static MyComponent getComponent(){return component;}
}
I think using static objects in this case would cause memory leaks.
What you might follow is "Inject everything" pattern shown in this great article.
What is it's essence? Try to inject the object that needs Component inside the object that is already injected. In this article Adapter and ViewHolder (any object) is injected into activity (and objects inside adapter too). This is what you are trying to achieve.
I also advise you to read all his articles about Dagger 2, as I haven't seen such a great and advanced tutorial on Dagger 2 features

Multiple independent component injection

My dagger configuration for an android project that i'm working on:
Note: I've provided all the needed #Component, #Module, #Provides annotations wherever needed.
MainActivity {
#Inject A a;
#Inject B b;
onCreate(){
ComponentX.inject(this);
ComponentY.inject(this);
}
}
ComponentX-> ModuleA ->providerA
ComponentY -> ModuleB -> providerB
As you can see, these are two completely independent components not related to each other in anyway except for at the point of injection.
During compilation I get the following error:
In file A.java
error: B cannot be provided without an #Provides- or #Produces-annotated method.
MainActivity.b
[injected field of type: B b]
Am I mistaken in thinking that multiple components can be used while using dagger 2 or is the application supposed to use one big component which takes care of all the injections?
Can anyone help me understand where i'm going wrong?
You do not have to have a single component, there are various ways to modularize them, but each object that you create, or inject values into, must have all its values provided by a single component.
One way you could restructure your code is to have ComponentY depend on ComponentX, or vice versa, e.g.
#Component(dependencies = ComponentX.class)
interface ComponentY {
void inject(MainActivity activity);
}
Or you could create a third Component, say ComponentZ, if ComponentX and ComponentY are completely orthogonal to one another.
#Component(dependencies = {ComponentX.class, ComponentY.class})
interface ComponentZ {
void inject(MainActivity activity);
}
Or you could just reuse the modules, e.g.
#Component(modules = {ModuleA.class, ModuleB.class})
interface ComponentZ {
void inject(MainActivity activity);
}
How exactly you decide to split it largely depends on the structure of your code. If the components X and Y are visible but the modules are not then use component dependencies, as they (and module depedencies) are really implementation details of the component. Otherwise, if the modules are visible then simple reuse them.
I wouldn't use scopes for this as they are really for managing objects with different lifespans, e.g. objects associated with a specific user whose lifespan is the time from when a user logs in to when they log out, or the lifespan of a specific request. If they do have different lifespan then you are looking at using scopes and subcomponents.
is the application supposed to use one big component
Kind of, you should think of it in scopes. For a given scope, there is one component. Scopes are for example ApplicationScope, FragmentScope (retained), ActivityScope, ViewScope. For each scope, there is a given component; scopes are not shared between components.
(This essentially means that if you want to have global singletons in the #ApplicationScope, there is one application scoped component for it. If you want activity-specific classes, then you create a component for it for that specific activity, which will depend on the application scoped component).
Refer to #MyDogTom for the #Subcomponent annotation, but you can also use component dependencies for the creation of subscoped components as well.
#YScope
#Component(dependencies = ComponentX.class, modules=ModuleB.class)
public interface ComponentY extends ComponentX {
B b();
void inject(MainActivity mainActivity);
}
#XScope
#Component(modules=ModuleA.class)
public interface ComponentX{
A a();
}
ComponentY componentY = DaggerComponentY.builder().componentX(componentX).build();
is the application supposed to use one big component which takes care
of all the injections?
You can use Subcomponent. In your case components declaration will look like this:
#Subcomponent(modules=ModuleB.class)
public interface ComponentY{
void inject(MainActivity mainActivity);
}
#Component(modules=ModuleA.class)
public interface ComponentX{
ComponentY plus(ModuleB module);
}
ComponentY creation: creationCompunentY = ComponentX.plus(new ModuleB());
Now in MainActivity you call only ComponentY.inject(this);
MainActivity {
#Inject A a;
#Inject B b;
onCreate(){
ComponentY.inject(this);
}
}
More information about sub components can be found in migration from Dagger1 guide (look at Subgraphs part), Subcomponent JavaDoc and Component JavaDoc (look at Subcomponents part).

Categories