If you’ve managed to avoid Dagger's hate trend and made it this far, you probably care about performance and want to make sure you’re getting everything you possibly can out of Dagger. If that’s the case, this article is for you.

This is spiritually the second part of Dagger 2 on Android: The Simple Way. The goal here isn't to make Dagger simple anymore, though. It's to make sure we're properly using it the way we're supposed to — which might often lead to a performance improvement, for instance. The good thing is that the guidelines I'll be talking about here are simple too, so don't you worry.

TL;DR:

Avoid unnecessary scoping.

Always go for static provide methods.

Expose the application context through a component builder instead of a module with constructor argument. Or even better: use the new factory!

Use @Binds instead of a @Provides method when simply delegating one type to another.

instead of a method when simply delegating one type to another. Switch dependencies on tests with a test component instead of overriding modules.

Avoid using Dagger on single-class unit tests — you simply don’t need it.

Scoping

Scoping is expensive, just avoid it whenever possible, it’s as simple as that. As Py ⚔ mentioned, @Singleton instances should be rare and only used in situations where it really makes sense: either the object is expensive to create, or it's an object that would be repeatedly created and thrown away.

But there’s a special scope annotation called @Reusable that you should know about. It basically tells Dagger you're fine if it reuses or recreates your dependency — and Dagger will basically make things better under the hood. The user guide mentions it, but there are some other interesting resources on it, like this Stack Overflow response by Jeff Bowman, this video by Gregory Kick, and this episode of Android Dialogs with Mike Nakhimovich.

In a nutshell, it’s mostly a good idea to make stateless utility classes @Reusable . But if their creation is expensive and you want to avoid going through it more than once, you might want to consider @Singleton . And if there’s state involved, you probably don’t want to share the same instance of that dependency, so @Reusable isn't a good fit and an unscoped dependency is your best bet. Or, as David Baker said:

Edit: according to Ron Shapiro, @Reusable has many of the same costs as @Singleton , and the real suggestion is to never scope unless you've profiled and seen a performance improvement by scoping — so use it at your own discretion. A new scope also inevitably contributes to the complexity of the setup, so I've been actually avoiding it now.

Static

This is the simplest and most fun guideline of all: make sure all your provide methods are static. That's it.

If your module only has static provide methods, Dagger will never need to instantiate it. And if you can't do that because your modules have state, you should probably revisit that.

This might be a super trivial guideline to follow, but it becomes tricky in Kotlin world since you can't simply have a static method in a class like you can in Java. You basically have two options: you can use a companion object, or make your module an object and annotate the provide methods with @JvmStatic . This last option is the one you want to follow.

Even though R8’s staticization is able to make an object 's method static when the instance is not needed, Dagger will still require them to be static at compile time, so we still need the @JvmStatic annotations there.

Edit: starting on version 2.25, @JvmStatic isn't necessary anymore thanks to this commit!

Edit: starting on version 2.26, Kotlin companion objects are now properly supported. The example above is still valid, but companion object support becomes especially useful when we want to have both @Binds and @Provides methods in the same Kotlin module:

Application context

One of the first steps of any Dagger setup is to expose the application context as a dependency. And that’s probably when people start looking at Dagger as this weird and complicated thing. The fact is, this is a very specific situation: we want to be able to inject an instance of an object we don't control creation and yet have a reference to it. In order to solve this, that’s the code we normally see:

We create a module that receives the application context as a constructor argument, and we create a provide method that exposes it. This works great, but then we can't have static @Provides methods anymore. And besides that, this strategy is actually going against the docs that are pretty explicit when it comes to this:

This is what you want instead:

The ApplicationComponent is a little more complicated now, but we don't need a module with state anymore. I actually prefer this code, even though it isn’t great either. The initialization chain now makes more sense, and the generated code tend to be simpler — especially in this case since it's one less module Dagger has to deal with.

…or instead of a builder you can use the new @Component.Factory ! It's been recently released and I wrote a dedicated blogpost about it:

@Binds

When we have a class that implements an interface and we want to bind it through the interface, we'd usually do something like this:

So whenever we ask Dagger an instance of BookPresenter , which is the interface, we'd get an instance of BookPresenterImpl , which is the implementation, usually with an @Inject -annotated constructor or maybe also part of the module. This is what we should do this instead:

This serves as a simple indicator to Dagger that whenever we request an instance of that interface, we want that implementation. The nice thing here is that there's no code generation involved — that's why the method is abstract, no one will ever call it. Dagger will simply use that as information when tying things together. We can actually make this slightly less verbose by going with an interface instead:

For some reason, the user guide doesn't mention the nice @Binds annotation, even though it's been around since Dagger 2.4, and that's probably one of the reasons some of us are still not familiar with it. You can learn more about it in Ron Shapiro and David P. Baker's talk, and also in these two other talks from Gregory Kick, though!

Testing

There are many reasons to switch dependencies when running tests. In general, or at least when the goal isn't an actual end to end test (because who wants to deal with Espresso idling resources, anyway?), it's a great idea to isolate your tests from the real world. And running your Espresso tests pointing to a mock API (MockWebServer and RESTMock FTW) through Dagger is one of the best ways to do it.

Surprisingly, Dagger’s documentation on testing is pretty good. There are many ways to switch Dagger dependencies on tests. It’s possible to override modules, and that’s actually what DaggerMock does under the hood. But even though this strategy looks cool at first, the documentation is explicit about avoiding it because of the limitations it brings. Also, since static methods can’t be overridden, we wouldn’t be able to have static provide methods this way.