Skip to main content

Dagger: A Dependency Injection Framework for Android and Java

Dagger is a new dependency injection framework for Android and Java. I went to a meetup yesterday to learn more about it. These are my notes:

The talk was by Jake Wharton who works at Square.

Every single app has some form of DI. You can do DI even if you're not using a library for doing it. The goal of DI is to separate the behavior of something from its required classes. If you've ever used a constructor to receive stuff, you've done a simple version of DI.

Square used Guice heavily.

Problems with Guice:
Config problems fail at runtime. 
Slow initialization, slow injection, and memory problems.

These are worse on Android. It causes the OS to load all the code for your app at once. This caused their app to take 2 seconds to start.

They called Dagger "Object Graph" initially.

Goals of Dagger:

Static analysis of all dependencies and injections. 
Fail as early as possible--compile time, not runtime.
Eliminate the need to do reflection of methods and annotations at runtime. Reflection in Dalvik is really slow.
Have negligible memory impact.

Jesse Wilson wrote it over the course of 5 weeks. He previously worked on Guice and Dalvik.

Square switched from Guice to Dagger in a fairly short period of time.

The name Dagger refers to "directed acyclic graph".

An ObjectGraph is the central dependency manager and injector.

@Module + @Provides

@Inject

@Singleton

Modules are meant to be composed together.

@Inject is required.

Field injection or constructor injection.

Dependencies can be stored in private final fields.

If you have @Inject, you don't have to say @Provides.

Injected fields cannot be private or final. They can be package protected.

Object graphs can be scoped. One object graph is a superset of another. For instance, you might create a new object graph once the user logs in that contains all of the objects that are require a user object.

Android

The Android platform makes it really hard to test your apps. He showed how they deal with it.

The ObjectGraph is just another object. Hence, you can pass it around like a normal object.

There's one pain point in Dagger. All injection points must be listed on a module. This is used for aggressive static analysis.

Use overrides to facilitate testing.

He showed how to integrate with Gradle.

They have a "Debug Drawer" in their apps. It is hidden in the UI, but lets you configure all sorts of debug settings.

U+2020 is a sample app to show how to do all of this.

Using DI Incorrectly

Do NOT ignore the pattern.

Do NOT make every class use the pattern. Use it for the big things, such as the things that talk to a remote API.

Do NOT store dependencies as static fields.

Other Stuff

The Android docs say not to use DI. That advice is stale. Those complaints don't apply to Dagger.

Dagger is developer and debugger friendly.

The Future

Dagger has been out for 18 months.

They're working on the next major version, version 2.0.

Google is leading the development of the next version.

It won't use any reflection.

Dagger is not Android specific.

They're getting rid of injects lists.

Components encapsulate dependencies.

There will be dedicated annotations to denote scopes.

See squ.re/dagger2.

Questions

They use protocol buffers for their APIs. They use a schema for their APIs.

They have code that can generate a GraphViz file that shows you your dependency graph.

In their apps, they have a network module, an Android module, an app module, etc.

There's an IntelliJ plugin that lets you jump between @Inject and @Provides.

Comments

Popular posts from this blog

Drawing Sierpinski's Triangle in Minecraft Using Python

In his keynote at PyCon, Eben Upton, the Executive Director of the Rasberry Pi Foundation, mentioned that not only has Minecraft been ported to the Rasberry Pi, but you can even control it with Python. Since four of my kids are avid Minecraft fans, I figured this might be a good time to teach them to program using Python. So I started yesterday with the goal of programming something cool for Minecraft and then showing it off at the San Francisco Python Meetup in the evening.

The first problem that I faced was that I didn't have a Rasberry Pi. You can't hack Minecraft by just installing the Minecraft client. Speaking of which, I didn't have the Minecraft client installed either ;) My kids always play it on their Nexus 7s. I found an open source Minecraft server called Bukkit that "provides the means to extend the popular Minecraft multiplayer server." Then I found a plugin called RaspberryJuice that implements a subset of the Minecraft Pi modding API for Bukkit s…

Apple: iPad and Emacs

Someone asked my boss's buddy Art Medlar if he was going to buy an iPad. He said, "I figure as soon as it runs Emacs, that will be the sign to buy." I think he was just trying to be funny, but his statement is actually fairly profound.

It's well known that submitting iPhone and iPad applications for sale on Apple's store is a huge pain--even if they're free and open source. Apple is acting as a gatekeeper for what is and isn't allowed on your device. I heard that Apple would never allow a scripting language to be installed on your iPad because it would allow end users to run code that they hadn't verified. (I don't have a reference for this, but if you do, please post it below.) Emacs is mostly written in Emacs Lisp. Per Apple's policy, I don't think it'll ever be possible to run Emacs on the iPad.

Emacs was written by Richard Stallman, and it practically defines the Free Software movement (in a manner of speaking at least). Stal…

JavaScript: Porting from react-css-modules to babel-plugin-react-css-modules (with Less)

I recently found a bug in react-css-modules that prevented me from upgrading react-mobx which prevented us from upgrading to React 16. Then, I found out that react-css-modules is "no longer actively maintained". Hence, whether I wanted to or not, I was kind of forced into moving from react-css-modules to babel-plugin-react-css-modules. Doing the port is mostly straightforward. Once I switched libraries, the rest of the port was basically:
Get ESLint to pass now that react-css-modules is no longer available.Get babel-plugin-react-css-modules working with Less.Get my Karma tests to at least build.Get the Karma tests to pass.Test things thoroughly.Fight off merge conflicts from the rest of engineering every 10 minutes ;) There were a few things that resulted in difficult code changes. That's what the rest of this blog post is about. I don't think you can fix all of these things ahead of time. Just read through them and keep them in mind as you follow the approach above.…