At this point, my understanding of Dependency Injection (DI) is only from this article. I'm interested to try, but I just need to clarify some things:
I know, comparing Dagger to RxJava is like comparing apple to orange. But in a sense, they are both a fruit just like Dagger and RxJava are third-party libraries that might make my project larger.
Dagger 2 walks through the dependency graph and generates code that is both easy to understand and trace, while also saving you from writing a large amount of boilerplate code you would normally need to write by hand to obtain references and pass them to other objects as dependencies.
Benefits of using Dagger Dagger frees you from writing tedious and error-prone boilerplate code by: Generating the AppContainer code (application graph) that you manually implemented in the manual DI section. Creating factories for the classes available in the application graph.
In Android, you usually create a Dagger graph that lives in your application class because you want an instance of the graph to be in memory as long as the app is running. In this way, the graph is attached to the app lifecycle. In some cases, you might also want to have the application context available in the graph.
It's officially deprecated and you can pretty much ignore it. Google's framework, which became dominant in Android ecosystem, was originally called Dagger 2. Sometimes we still refer to it as such, but, in most cases, we simply call it Dagger today.
You've combined two separate questions, which should be evaluated separately: "Why do we need dependency injection?" and "why do we need Dagger 2?"
Dependency injection (inversion of control) is useful because it allows the consumer of your component to provide your component's dependencies. Take a log formatter, for example: Without dependency injection you might need to write three different versions of your class that log to stdout
, a remote server, or a text file. By comparison, if you were to write a LogFormatter
that accepts a Writer
to which it writes, then you could write it once and pass in whichever Writer
is most appropriate, including a test double (a FakeWriter you make, or a StringWriter, or a mock-framework-created mockWriter instance) for testing. Though it's written for Guice instead of Dagger, I wrote a separate SO answer that talks about the value of dependency injection in production usage and also test cases; most of the tutorials you see will focus on tests under the presumption that "production" and "test" are the two cases you know about up front, where other opportunities for reuse and repurposing will present themselves later.
Once you embrace the modularity, reusability, and testability benefits that dependency injection provides you, you'll probably be left with one question: How do I manage these enormously-long constructors? After all, to carry forward the LogFormatter
example, you wouldn't be able to write your Application without caring where the logs go to.
MyApplication application = new MyApplication(
new LoggingService(new LogFormatter(new StdOutWriter())),
new DatabaseService(new MyApplicationDatabase(new File("my.db"))),
...);
This is where Dagger shines: It lets you have all the benefits of dependency injection while automatically managing the constructors for you. This allows it to encapsulate the responsibility of creating objects and make it cleaner and safer, the way that RxJava can encapsulate the responsibility of managing and propagating asynchronous events and make it cleaner and safer.
It's important to realize that Dagger 2's reduction in boilerplate is in comparison to manual dependency injection, not the raw constructor invocations that you're comparing to. If you stick with calling new
directly, you'll probably avoid much of this object construction boilerplate entirely, but you'll also find yourself going through difficult acrobatics trying to shard the work out to multiple developers or trying to test or reuse the code you've written. The collective pain is why dependency injection is so popular of a concept, and why libraries like Spring, Guice, and Dagger are gaining popularity.
I can vouch for the use of Dagger 2 in several particularly large, well-known, and well-used production Android applications. :)
I have only used Dagger 1 but this might still help you in some way or another:
Dagger builds up a (D)irected (a)cyclic (g)raph (thats also where i the name comes from) with modules for different target applications.
So within one app project we were able to build four different apps, pretty similiar to Jake Wharton's u2020 app. All these apps had different targets. One was internal testing, one was for the testing team (with a screenshot function), one was internal release and the other one was release.
So why do we need four different apps here? The answer is: So we don`t have to have debug or test code in our release application and we can separate code that does not belong together.
if(currentMode == Mode.DEBUG){
Timber.i(...);
}
Something like that is not necessary any more.
The screenshot functionality mentioned earlier, does not belong in the production code, so it was only in the testing code. When building an app, the framework used the correct module and injected it.
Note: I am sure there are other use cases for dagger than that.
EDIT: This will not change how you write code in a way RxJava does, but you have to use DI a lot in your modules.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With