Dagger2 dependency injection

This video tutorial demonstrates how to implement Dependency Injection architectural pattern in Android using Dagger 2 dependency injection library.

In order to fit the tutorial in a reasonable amount of time, I was forced to assume that the watchers will know what Dependency Injection is and will have a basic understanding of Dagger 2 dependency injection library.

The required background can be established by reading the posts about Dependency Injection in Android and Dagger 2 Tutorial.

Below are the notes that were taken during the tutorial, aggregated by category and with some additional information.

Don’t use the “new” injection method defined in dagger.android package:

Latest versions of Dagger introduced a new method of performing dependency injection in Android which is defined in dagger.android package.

While this method of injection complicates the dependency injection code a lot, it doesn’t seem to have any advantage over a simpler approach demonstrated in this tutorial. Therefore, my advice is to avoid usage of this injection method.

Don’t use “fancy” Dagger’s features and try to keep the design simple:

Usage of features like producers, multibindings, named injections, lazy injections, etc. immediately delegate parts of application’s core functionality, which should be defined in Functional set, to Construction set. This undermines the primary goal of Dependency Injection architectural pattern (which is to achieve a clear separation between Construction and Functional sets of classes), increases the complexity and the coupling of the design, and will make a code maintenance much more difficult.

Therefore, my advice is to avoid usage of the “fancy” Dagger’s features, and to try and keep Construction set’s design as simple and as dumb as possible.

In very rare cases when lazy initialization of injected services is required, you can use Decoraptor pattern.

Components hierarchy:

Establish hierarchy between differently scoped Components using sub-components. I usually define a top level ApplicationComponent which has two sub-components: ControllerComponent and ServiceComponent.

Sub-components get a direct access to parent’s object graph, which makes it easier to maintain dependency injection code.

Scope of Context:

Since subclasses of Context are not interchangeable, Application should be provided in Application scope as a service, but not Context. Context should be provided in Controller and Service scopes, and resolve to either Activity or Service, respectively.

This convention will prevent accidental misuse of Application instead of Activity or Service, and vice-versa.

Global services:

Global services are services that must be instantiated only once during application’s lifecycle. All clients that depend on a global service get a reference to the same object.

Always annotate methods that provide global services with scope annotation (@Singleton, or a custom one), even if the internal implementation of the method ensures that the same object will always be returned.

This convention will make the intent of declaring a service as global explicit and evident, rather than dependent upon and hidden in the implementation of the providing method.

Which services to inject in Application scope:

As a general rule of thumb, the services that are being injected in Application scope should have one or more of the following characteristics:

  1. The service is global
  2. The service should be injected into Application
  3. The service is required by more than a single sub-component of ApplicationComponent

Divide the object graph into several Modules:

As the application progresses and grows, the object graph will grow accordingly. Having a single module per component can work initially, but as object graph grows beyond few tens of objects this approach becomes hard to maintain.

In order to avoid a mess of a single module that provides tens (or hundreds) of services, divide the services among different modules and make the components depend on multiple modules.

If you found this post useful or interesting, subscribe to our newsletter in order to receive notifications about new posts.

This article has 6 comments

  1. Dagger Newbie Reply

    I’ve read all your blog posts about Dagger and I found them really helpful. Thanks.
    Iā€™m also starting to play with it and I find the following code simpler and clean. So, how about this example:

    [Code omitted by blog admin]

    So, what do you think about it?
    Thanks for your time, regards.

    • Vasiliy Reply

      Hello,
      In this video I recommend not to use AndroidInjection and related classes.
      It also looks like you are using a module-per-activity approach. I find this approach to be cumbersome and it leads to unnecessary complexity and code repetition.
      My advice is to stick to the scheme shown in this video tutorial.
      P.S. I had to remove the code from your question because it was too long

      • Dagger Newbie Reply

        Hi,
        Ok I’ll look into it more carefully.
        Thanks for your answer and no problem regarding the code šŸ˜‰

  2. Nate Ebel Reply

    This was a very well done tutorial.

    I had a couple thoughts while watching the video

    1. How do you handle satisfying dependencies to your controllers that are specific to a controller? For example, perhaps you want to inject a viewmodel/presenter/data-store. Would you create modules for related sets of objects (PresentersModule, DataModule) and then simply allow your controller components to satisfy any of those dependencies?

    2. Regarding the 2nd issue dagger.android claims it’s attempting to solve:

    I do think there is a subtle difference between the newer approach of AndroidInjection.inject(this) vs the recommended approach here. In the newer approach, since everything is injected the same way, its closer to knowing that it IS injected rather than WHO injects it which I do think gets at the core philosophy of dependency injection. For example, when simply satisfying dependencies through a constructor the class doesn’t know who to ask specifically for those dependencies just that they will be provided.

    I certainly concede, however, that the dagger.android package adds a good deal of boilerplate that makes things harder to reason about, and if you effectively are only using 1-2 components anyways than the difference is so minimal that preferring the cleaner, less complex solution would definitely be the way to go.

    3. I agree with your approach to separating out your component layers, and thought it was one of the most clear explanations of how/why you would want to do this

    • Vasiliy Reply

      Hello Nate,
      Thanks for taking time and writing a comment.
      Regarding your points:

      1. Yes, I would do it like you proposed. You can have a look at application dependency injection code in my IDoCare app – this is exactly what you meant, right?

      2. Let’s observe this from controller’s point of view.
      While defining a controller you should make a choice – either it “knows” about AndroidInjection class, or it “knows” about ControllerComponent class. Either way, the controller “knows” who injects it.
      Are there any real advantages if the controller “knows” about AndroidInjection as opposed to ControllerComponent? I haven’t found any yet. However, as you noted, “knowing” about AndroidInjection complicates controller’s code.
      So, why this feature was introduced?
      I might be wrong, but it looks like the developer who worked on this feature had only one scheme in mind – each Activity should correspond to a standalone sub-component. If you inspect the code having this assumption in mind, it looks reasonable.
      However, such a design is not optimal either way and should not be used in my opinion.

      3. Thank you šŸ™‚

      • Nate Ebel Reply

        1. Yeah. That’s what I was thinking, and I think works out very cleanly Ā šŸ‘

        2. I agree with you. I think when viewing it from the idea that you will have closer to a 1-1 Activity to Component mapping than the AndroidInjection does become more generic. In practice though, I’m having a hard time coming up with practical situations where that’s actually the case and therefore worthwhile.

Leave a Comment

Your email address will not be published. Required fields are marked *