This document provides an introduction and overview of dependency injection and the dependency injection framework Dagger. It defines key concepts like dependencies, dependency injection, and the dependency inversion principle. It explains how dependency injection reduces coupling between classes and improves testability. The document demonstrates how to use Dagger annotations like @Inject, @Module, @Provides and @Component to implement dependency injection in an Android application. It also discusses additional Dagger features like scopes, lazy injection, qualifiers and subcomponents. In summary, the document is an introductory guide to dependency injection and how to implement it using the Dagger framework on Android.
4. public class Example {
DatabaseHelper mDatabaseHelper;
public Example() {
mDatabaseHelper = new DatabaseHelper();
}
public void doStuff() {
...
mDatabaseHelper.loadUsers();
...
}
}
5. - Dependency injection is a software design pattern that
implements inversion of control for resolving dependencies
- An injection is the passing of a dependency to a dependent
object to use
6. public class Example {
DatabaseHelper mDatabaseHelper;
public Example() {
mDatabaseHelper = new DatabaseHelper();
}
}
7. public class Example {
DatabaseHelper mDatabaseHelper;
public Example() {
mDatabaseHelper = new DatabaseHelper();
}
}
public class Example {
DatabaseHelper mDatabaseHelper;
public Example(DatabaseHelper databaseHelper) {
mDatabaseHelper = databaseHelper;
}
}
8. public class Example {
DatabaseHelper mDatabaseHelper;
public Example() {
mDatabaseHelper = new DatabaseHelper();
}
}
public class Example {
DatabaseHelper mDatabaseHelper;
public Example() {
mDatabaseHelper = new DatabaseHelper();
}
}
public class Example {
DatabaseHelper mDatabaseHelper;
public Example(DatabaseHelper databaseHelper) {
mDatabaseHelper = databaseHelper;
}
}
public class Example {
DatabaseHelper mDatabaseHelper;
public Example(DatabaseHelper databaseHelper) {
mDatabaseHelper = databaseHelper;
}
}
9. public class Example {
DatabaseHelper mDatabaseHelper;
public Example() {
}
public void setDatabaseHelper(DatabaseHelper databaseHelper) {
mDatabaseHelper = databaseHelper;
}
}
11. public class ExampleTest {
@Mock DatabaseHelper mockDatabaseHelper;
@Test
public void testExample_doStuff() {
Example example = new Example(mockDatabaseHelper);
example.doStuff();
mockDatabaseHelper.AssertGetDataWasCalled();
}
}
public class Example {
DatabaseHelper mDatabaseHelper;
public Example(DatabaseHelper databaseHelper) {
mDatabaseHelper = databaseHelper;
}
public void doStuff() {
...
mDatabaseHelper.loadUsers();
...
}
}
12. - High-level modules should not depend on low-level modules.
Both should depend on abstractions.
- Abstractions should not depend on details. Details should
depend on abstractions.
Dependency Inversion Principle
17. public class CoolEBookReader {
public void loadPage(String bookUri, int PageNumber) {
String pdfContent = getPdfContent(bookUri, PageNumber);
displayPage(pdfContent);
}
}
18. public class CoolEBookReader {
enum BookType {
PDF,
EPUB
}
public void loadPage(BookType bookType, String bookUri, int PageNumber) {
String pageContent;
if (bookType == BookType.PDF) {
pageContent = getPdfContent(bookUri, PageNumber);
} else if (bookType == BookType.EPUB) {
pageContent = getEpubContent(bookUri, PageNumber);
} else {
throw new IllegalArgumentException("Unknown book type");
}
displayPage(pageContent);
}
}
19. public class CoolEBookReader {
enum BookType {
PDF,
EPUB
}
enum PrinterType {
SCREEN,
VOICE
}
public void loadPage(BookType bookType, PrinterType printerType, String bookUri, int PageNumber) {
String pageContent;
if (bookType == BookType.PDF) {
pageContent = getPdfContent(bookUri, PageNumber);
} else if (bookType == BookType.EPUB) {
pageContent = getEpubContent(bookUri, PageNumber);
} else {
throw new IllegalArgumentException("Unknown book type");
}
if (printerType == PrinterType.SCREEN) {
displayPage(pageContent);
} else if (printerType == PrinterType.VOICE) {
readAloudPage(pageContent);
} else {
throw new IllegalArgumentException("Unknown printer type");
}
}
}
20. - High-level modules should not depend on low-level modules.
Both should depend on abstractions.
- Abstractions should not depend on details. Details should
depend on abstractions.
Dependency Inversion
22. interface Reader {
String read(String bookUri, int pagNumber);
}
interface Printer {
void print(String pageContent);
}
public class CoolEBookReader {
public void loadPage(Reader reader, Printer printer, String bookUri, int pageNumber) {
String pageContent = reader.read(bookUri, pageNumber);
printer.print(pageContent);
}
}
23. interface Reader {
String read(String bookUri, int pagNumber);
}
interface Printer {
void print(String pageContent);
}
public class CoolEBookReader {
public void loadPage(Reader reader, Printer printer, String bookUri, int pageNumber) {
String pageContent = reader.read(bookUri, pageNumber);
printer.print(pageContent);
}
}
public class CoolEBookReader {
public void loadPage(String bookUri, int PageNumber) {
String pdfContent = getPdfContent(bookUri, PageNumber);
displayPage(pdfContent);
}
}
24. public class CoolEBookReaderTest {
@Mock
Reader mockReader;
@Mock
CoolEBookReader.Printer mockPrinter;
@Test
public void TestExample_loadPage() {
CoolEBookReader coolEBookReader = new CoolEBookReader();
coolEBookReader.loadPage(mockReader, mockPrinter, "", 1);
// Assert Reader.read() is called
// Assert Printer.print() is called
}
}
25. - Dependency Injection
- Dependency Inversion
- Where are these dependencies come from
What’s next?
26. - Handles object creation
- Reduces boilerplate code
- A central location for organizing dependencies
- Implement common patterns natively (singleton, lazy loading, etc)
Why use a framework?
27. - Dagger 1
- Dagger 2
- Guice and RoboGuice
- PicoContainer
- Spring
- Many, many, many, many more options
Common Frameworks
28. History lesson of DI on Android
- RoboGuice - 2009
- Spring for Android - 2012
- Dagger 1 - 2013
- Dagger 2 - 2015
- Tiger - 2016