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.
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
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.
Establish hierarchy between differently scoped
Components using sub-components. I usually define a top level
ApplicationComponent which has two sub-components:
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 should be provided in Controller and Service scopes, and resolve to either
This convention will prevent accidental misuse of
Application instead of
Service, and vice-versa.
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:
- The service is global
- The service should be injected into
- The service is required by more than a single sub-component of
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.