First version of this post was originally written on my dev-blog: http://frogermcs.github.io/

This post is a part of series of posts showing Dependency Injection with Dagger 2 framework in Android. Today we’re going to take a look at Dagger Producers — an extension to Dagger 2 that implements asynchronous dependency injection in Java.

Here is the list of previous posts from series:

Initialization performance issues

We all know that Dagger 2 is very well optimized framework for Dependency Injection. But even with all those micro-optimizations, still there are possible performance issues with injected dependencies — the “heavy” 3rd parties and/or our main-thread-blocking code.

Dependency injection is a process of delivering requested dependencies in the right place in the shortest possible time — and this is what Dagger 2 does very well. But DI is also about creating those dependencies. What is the point of delivering dependencies in nano seconds if we need to spend hundred of milliseconds creating them?

Maybe it’s not so important later, when our app has created serious bunch of singletons which are now served instantly by Dagger 2. But still we need a time window when we create them — and in the most cases it’s app launch time.

The problem (and hints how to debug it) was described wider in one of my previous blog posts: Dagger 2 — graph creation performance.

In very short, let’s imagine this case — your app has initial screen (SplashScreen) which does all needed things immediately after app launch:

Initializes all tracking libs (Google Analytics, Crashlytics) and sends first bunch of data to them

Creates whole stack for API and/or database communication

Delivers logic to our views (Presenters in MVP, ViewModels in MVVM etc.)

Even if our code is very well optimized still there is a chance that some of external libraries need tens or hundreds of milliseconds to initialize. Before our launch screen will be presented all requested dependencies (and their dependencies) have to be initialized and delivered. It means that launch time is a sum of initialization times of each of them.

Example stack measured by AndroidDevMetrics can look like this:

User will see SplashActivity in about 600ms (+ additional system work) — sum of all initialization times.

Producers — asynchronous dependency injection

Dagger 2 has extension named Producers which more or less solve those problems for us.

The idea is simple — whole initialization process can be executed on background thread(s) and delivered later to app’s main thread.

Similar to Dagger synchronous injection we have a couple annotations which are used in injection process:

@ProducerModule

Same as @Module, this one is used to mark classes which deliver depedencies. Thanks to this, Dagger will know where to find requested dependencies.

@Produces

Similar to @Provide this annotation is used to mark methods in @ProducerModule annotated class which return dependencies. @Produces annotated methods can return ListenableFuture<T> or object itself (which also will be initialized in given background thread).

@ProductionComponent

Like @Component, it’s responsible for dependencies delivery. It’s a bridge between our code and @ProducerModule. The only difference from @Component is that we cannot decide about scope of dependencies. It means that each Produces method that contributes to the component will be called at most once per component instance, no matter how many times that binding is used as a dependency.

It means that each object served by @ProductionComponent will be a single instance (as long as we’re getting it from this particular component).