Wednesday, May 6, 2015

Component Dependency vs Submodules in Dagger 2

Dagger is a Dependency Injection library created for Java with Android in mind.

The first its version was by far not the easiest library to catch up. This might relate to the fact it is going well until you do something wrong. What I really like about its second release is its clarity. The generated code looks as a human wrote it, it is a pleasure to debug it, not to mention it is up to 13% faster. What's more, when you do something wrong it tells you what's exactly the problem. 

Android Community is quite loud about it and you can find a lot of really cool materials to familiarize yourself with the library or find comprehensive articles about a migration process, what wasn't really a case with it predecessor. These are just several of what I really enjoyed, I would totally recommend you to go through them:
Despite its clarity, there were some things I stuck with. Most of them are well covered in aforementioned articles but here is also a thing with previously called scoped graphs which exhibit as submodules now. 

What was cool about scoped graphs is that you were able to extend an object graph at runtime and not create a bunch of objects unless you really need them. I used to treat scoped graphs per Fragment, but I saw many people deal with their Activities as a standalone unit. That being sad, you could extend the graph with required dependencies (say 'fragment's dependencies' mean 'MVP pattern') for particular Fragment and use the memory somewhat wisely. Surely it is only one of many applications of scoped graphs.

If you refer to the official documentation there are two ways to achieve the same result: Component Dependency and Subcomponents. Authors are quite clear about the distinction but for me at first it was crystal clear when to use what. 

Component Dependency

Let's say, you have an ApplicationComponent which holds a Module with all Android related stuff like LocatioService, Resources, LayoutInflater, i.e. everything a Context is needed for

You also may want to have a DataComponent where you manage things for data persistence along with WebService APIs. 

The only thing you lack in DataComponent is a Context which resides in ApplicationComponent. That's where Component Dependency comes into play. You only need to declare a dependency of a DataComponent on Application component and you have a Context to deal with.

Here is one important note, you must have a Context explicitly declared in ApplicationComponent because it is the only way you can consume objects from a parent Component. All objects from its Modules aren't available to a child module.


Subcomponents

For me, subcomponents are the same scoped graphs. The main difference with Component Dependency is when you hook into parent Component you get an access to all objects from all modules it possesses without an explicit declaration of those dependencies in the parent Component. 

Let's assume you have another component solely for your LoginFragment dependencies - LoginComponent. It contains a Presenter where you move all business logic. The Presenter wants to invoke a WebSerivice's method to grab some data from a web service, so it has a dependency on the WebService which we know lives in DataComponent.

This time you don't need to specify anything in your LoginComponent, but you do in ApplicationComponent. You need to declare the ApplicationComponent could possibly be extended with LoginComponent and you just add something like:

LoginComponent plus(LoginModule module);

And you need to manually hook into ApplicationComponent to get its object's (all its objects) as something like:

getApplicationComponent().plus(new LoginModule(this));

Don't forget to annotate your child module with @Subcomponent instead of @Component if you'd like to treat it as a subcomponent.

8 comments:

  1. Good article. I am curious - how do you see testing with Dagger 2 vs Dagger 1? It used to be easier to mock/stub objects for testing in Dagger 1...

    ReplyDelete
  2. We don't test any Views (like Activity, Fragments or ViewGroups), all the business logic is in Presenters who has no framework relation. Presenters have their collaborators defined in their constructors, so you can easily mock them during object creation in your unit tests without Dagger intervention.

    ReplyDelete
    Replies
    1. What do you mean by 'collaborators'? Is there a sample I can see to understand the collaborator? Thanks.

      Delete
  3. What exactly mean "you must have a Context explicitly declared" in the Component Dependency section?

    ReplyDelete
    Replies
    1. Adding "Context context();" method into ApplicationComponent interface.

      Delete
  4. When would you use component dependency and when subcomponent?

    ReplyDelete
  5. How to know its is a sub-component of which component if it has more than one component.

    ReplyDelete