@Deprecated

I wrote this a while ago and even though I still agree with most ideas I've written here, I believe they're better expressed in the talk I recently gave at Android Makers.

Feel free to keep reading if you're not a video person, but if you're interested in the topic, I'd encourage you to take a look at the video later.

TL;DR:

Go with construction injection for all classes you own

classes you own Control scope with ViewModel s instead of subcomponents

s instead of subcomponents Forget dagger-android exists*

Let's get started

This article assumes you have some previous experience with Dagger. If that's not the case, it's probably a good idea to check some basic tutorials first. I particularly like this video by Jake Wharton, but there are many other beginner tutorials out there. Once you're done with it, you might also want to check these other two resources — they've had a large influence over what I'm writing here:

I created a dummy app where I applied all the concepts I discuss here. Feel free to skip the explanations and check out the code if you feel like it. There's a branch with lots of docs and comments that can help you go through the code. I tried to make it as simple as possible so anyone looking at it can focus exclusively on the Dagger bits.

Construction injection

One of the most overlooked features of Dagger is construction injection. Sometimes we're so used to work with modules that we forget we have the option to entirely avoid writing constructor boilerplate. And that's actually IMHO one of the key advantages of Dagger over Koin and Kodein.

The best part with construction injection is that we're able to keep all relevant information in the same spot: the class declaration. If the class is injectable, if it's a singleton or not, you get all that info with a quick glance over the class if you're using construction injection.

You can't run away from modules and constructor boilerplate if you don't own the class, but it's definitely a good idea to do that for any class you own. In summary, from my experience it's much better to have something like this:

Than something like this:

It's really easy to reach an ugly state when you start adding dependencies that have their own large list of dependencies and your modules start to grow uncontrollably.

Subcomponents and scopes

If subcomponents are super important to you, this strategy might not fit your needs. But from my experience, this will be enough for most projects. In fact, from what I've seen, most subcomponents usages were simply not necessary but were advocated for the sake of simply improving the dependencies organization. The documentation does contribute with this idea with the "Subcomponents for encapsulation" section, but I honestly disagree. Adding constructor boilerplate code that you could otherwise avoid with constructor injection won't really help you getting in a more organized state, especially in the long run.

Another purpose of subcomponents are custom scopes. However, I believe that today, with ViewModel s and the scope they provide for free, Dagger subcomponents and their scopes are even less valuable. Android now gives us Activity and Fragment scopes out of the box, so as long as your unscoped dependencies live in your ViewModel , they'll also be scoped and you don't have to worry about it.

There are still other use cases where subcomponents might be useful, like whenever we want to have an Activity in the graph, for instance (thanks Vasiliy Zukanov), even though there are definitely better tools for that. I'm not advocating against subcomponents everywhere, my point is that if you're using them only for organizing your dependencies or creating custom Activity/Fragment scopes, you're probably missing out an opportunity to make your Dagger setup simpler.

At first, injecting dependencies in a ViewModel with Dagger might seem tricky. If you look at Google's Android architecture samples, you can't find an example that includes both ViewModel s and Dagger playing along there, but if you look at the architecture components samples, you'll find the GithubBrowserSample that does include them together. And if you look at the GithubViewModelFactory , well, it's a little scary.

Ultimately, though, this can actually be simpler than you might think. All you need is to add the @Inject annotation on your ViewModel constructor and this beautiful ViewModelFactory will do the job for you:

Now you can simply inject that ViewModelFactory and use it to build any ViewModel you want, just like this:

Instead of wrapping the ViewModel in a Lazy in the ViewModelFactory , it's better to wrap it in a Provider , though, since we don't really need to hold the ViewModel reference for later. And the reason we wrap it in the first place is so we don’t unnecessarily recreate the ViewModel (and its dependencies) during orientation change, for instance. And if that injector looks odd to you, keep on reading.

We can also compare this with the Google I/O 2018 app. The setup there is different from the GithubBrowserSample. It's simpler, but there are multiple factories (one for each ViewModel ) and it's still more complicated than what we're doing here. But maybe I'm missing something since I honestly was never really able to fully grasp the whole setup there.

Edit: If you like this setup, you probably want to check this alternative that make things even simpler by Gabor Varadi. I only heard about it after publishing this, but I've created a branch with this implementation on my project so you can check it out!