Abusing Dagger with Initializers

Bartek Lipinski
ProAndroidDev
Published in
3 min readJul 4, 2019

--

(source: https://tinyurl.com/y4fdp3bz)

I started writing this as a simple answer to Facilitating dependency initialization with Dagger multibindings, but it grew very quickly so I eventually decided that I should release it as a standalone post. So that more people are able to read it.

Don’t treat this as an “attack” against the author of the original post. This is an explanation of a common misconception & misuse that many people are unaware of.

To give you a very condensed version of the mentioned post:

  1. It suggests to use Initializer classes inside your Dagger setup.

2. And to initialize all of them, one by one using the multibindings feature:

While using multibindings in Dagger can be a super useful feature, passing around Initializer classes in Dagger can be very dangerous.

It has a really narrow work area and can be misused so easily, that I suggest not to use it at all.

It can cause serious distortion of the Dependency Graph which might not be easily detectable. Using manual initializers can really defeat the purpose of having the Dependency Injection (DI) library in your code.

The DI framework is designed to create (and provide) dependencies in the proper order.

When a particular dependency is created, it is available for injecting into other dependencies. That’s why the proper initialization should be
happening when actually creating the dependency.

When “delaying” the initialization until you call initialize() method, you make it look (to the DI framework) like the dependency is ready for use right after it is created, while it’s not. It still needs to be initialized.

It’s like telling your boss you’re completely ready for work when you haven’t had your morning coffee yet. Until you’re really woken up, your coworkers shouldn’t depend on what you can bring to the table.

Providing a dependency in the Dependency Graph does not take into account the manual initialization. That’s why you can end up trying to use a „seemingly” ready dependency, while the initialize() hasn’t been called on it yet.

The simplest case is an Initializer which uses another „initializable” component:

Now it all depends on the implementation of the @IntoSet of Dagger. If it puts TimberInitializer into the set before FooInitializer everything should be fine. Otherwise, you will lose an important log.

While having it directly in the initialize() might be easily spotted, having this deep down in the hierarchy should be managed by the DI framework (that’s what it’s for).

(the following examples uses JodaTimeAndroid from Daniel Lew as an example of the initialized library)

If you try to use JodaTime classes before initialization, your app will crash. This is exactly what will happen if you try to initialize() BarInitializer before initializing JodaTimeInitializer.

On a small scale you might be able to control that, by properly arranging provision methods, but it really defeats the purpose of having a Dependency Injection framework in your code.

It just simply doesn’t scale.

When putting Initializers @IntoSet of Dagger dependencies, you really depend on pure luck while you should be depending on pure logic of the graph.

You should just let Dagger take care of initialization order and not distort it with manual Initializers.

--

--

android engineer @whatnot | ex @reddit | ex @getthefabulous | recovering feature creep 💉 | https://github.com/blipinsk