Slide 1

Slide 1 text

Intro To Dependency Injection Or Bar

Slide 2

Slide 2 text

- What is a Dependency? - Dependency Injection - Dependency Inversion Principle - Dependency Injection Frameworks Agenda

Slide 3

Slide 3 text

A depends on B

Slide 4

Slide 4 text

public class Example {
 DatabaseHelper mDatabaseHelper;
 
 public Example() {
 mDatabaseHelper = new DatabaseHelper();
 }
 
 public void doStuff() {
 ...
 mDatabaseHelper.loadUsers();
 ...
 }
 }

Slide 5

Slide 5 text

- 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

Slide 6

Slide 6 text

public class Example {
 DatabaseHelper mDatabaseHelper;
 
 public Example() {
 mDatabaseHelper = new DatabaseHelper();
 }
 }

Slide 7

Slide 7 text

public class Example {
 DatabaseHelper mDatabaseHelper;
 
 public Example() {
 mDatabaseHelper = new DatabaseHelper();
 }
 } public class Example { 
 DatabaseHelper mDatabaseHelper;
 
 public Example(DatabaseHelper databaseHelper) {
 mDatabaseHelper = databaseHelper;
 }
 }

Slide 8

Slide 8 text

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;
 }
 }


Slide 9

Slide 9 text

public class Example {
 DatabaseHelper mDatabaseHelper;
 
 public Example() {
 }
 
 public void setDatabaseHelper(DatabaseHelper databaseHelper) {
 mDatabaseHelper = databaseHelper;
 }
 }

Slide 10

Slide 10 text

- Shared dependencies - Configure dependencies externally - Separation of modules - Inherent testability Why?

Slide 11

Slide 11 text

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();
 ...
 }
 }

Slide 12

Slide 12 text

- 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

Slide 13

Slide 13 text

A depends on B

Slide 14

Slide 14 text

A is coupled to B

Slide 15

Slide 15 text

- Bare bones ebook reader - Supports PDF files - Prints book contents to screen Ebook Reader

Slide 16

Slide 16 text

CoolEBookReader PDFReader DisplayPrinter

Slide 17

Slide 17 text

public class CoolEBookReader {
 public void loadPage(String bookUri, int PageNumber) {
 String pdfContent = getPdfContent(bookUri, PageNumber);
 displayPage(pdfContent);
 } }

Slide 18

Slide 18 text

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); 
 }
 }

Slide 19

Slide 19 text

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");
 }
 }
 }

Slide 20

Slide 20 text

- 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

Slide 21

Slide 21 text

CoolEBookReader PDFReader DisplayPrinter <> Reader <> Printer

Slide 22

Slide 22 text

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);
 }
 }

Slide 23

Slide 23 text

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);
 } }

Slide 24

Slide 24 text

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
 }
 }

Slide 25

Slide 25 text

- Dependency Injection - Dependency Inversion - Where are these dependencies come from What’s next?

Slide 26

Slide 26 text

- Handles object creation - Reduces boilerplate code - A central location for organizing dependencies - Implement common patterns natively (singleton, lazy loading, etc) Why use a framework?

Slide 27

Slide 27 text

- Dagger 1 - Dagger 2 - Guice and RoboGuice - PicoContainer - Spring - Many, many, many, many more options Common Frameworks

Slide 28

Slide 28 text

History lesson of DI on Android - RoboGuice - 2009 - Spring for Android - 2012 - Dagger 1 - 2013 - Dagger 2 - 2015 - Tiger - 2016

Slide 29

Slide 29 text

- @javax.inject.Inject - @Module - @Provides - @Component Dagger uses annotations

Slide 30

Slide 30 text

public class ConnectionHelper {
 private Context mContext;
 
 public ConnectionHelper(Context context) {
 mContext = context;
 }
 
 public boolean isConnected() {
 ConnectivityManager connectivityManager =
 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
 return connectivityManager.getActiveNetworkInfo().isConnected();
 }
 } ConnectionHelper connectionHelper = new ConnectionHelper(context);
 
 boolean isConnected = connectionHelper.isConnected();

Slide 31

Slide 31 text

public class ConnectionHelper {
 private Context mContext;
 
 @Inject
 public ConnectionHelper(Context context) {
 mContext = context;
 }
 
 public boolean isConnected() {
 ConnectivityManager connectivityManager =
 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
 
 return connectivityManager.getActiveNetworkInfo().isConnected();
 }
 } @Inject

Slide 32

Slide 32 text

@Module
 public class AppModule {
 
 } @Module

Slide 33

Slide 33 text

@Provides @Module
 public class AppModule {
 private final Context mContext;
 
 public AppModule(Context context) {
 mContext = context;
 } @Provides
 public Context providesContext() {
 return mContext;
 } @Provides
 public ConnectionHelper providesConnectionHelper(Context context) {
 return new ConnectionHelper(context);
 }
 }

Slide 34

Slide 34 text

@Component(modules = {AppModule.class})
 public interface AppComponent {
 
 void inject(MainActivity activity);
 } @Component

Slide 35

Slide 35 text

public class App extends Application {
 private AppComponent component;
 @Override
 public void onCreate() {
 super.onCreate();
 
 AppComponent component = DaggerAppComponent.builder()
 .appModule(new AppModule(this))
 .build();
 }
 
 public AppComponent getComponent() {
 return component;
 }
 } public class App extends Application {
 private AppComponent component;
 @Override
 public void onCreate() {
 super.onCreate();
 
 AppComponent component = DaggerAppComponent.builder()
 .appModule(new AppModule(this))
 .build();
 }
 
 public AppComponent getComponent() {
 return component;
 }
 }

Slide 36

Slide 36 text

public class MainActivity extends AppCompatActivity {
 
 @Inject
 ConnectionHelper mConnectionHelper;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 ((App) getApplication()).getComponent().inject(this);
 
 boolean isConnected = mConnectionHelper.isConnected();
 
 textView.setText(isConnected ? "Connected" : "Not Connected");
 }
 } public class MainActivity extends AppCompatActivity {
 
 @Inject
 ConnectionHelper mConnectionHelper;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 ((App) getApplication()).getComponent().inject(this);
 
 boolean isConnected = mConnectionHelper.isConnected();
 
 textView.setText(isConnected ? "Connected" : "Not Connected");
 }
 } @Inject - again

Slide 37

Slide 37 text

- More annotations - Scopes - Lazy injections - others Fun stuff

Slide 38

Slide 38 text

@Provides
 @Singleton
 public Context providesContext() {
 return context;
 } @Singleton @Singleton
 @Component(modules = {AppModule.class})
 public interface AppComponent {
 
 void inject(MainActivity activity); }

Slide 39

Slide 39 text

@Provides
 @Reusable
 public ConnectionHelper providesConnectionHelper(Context context) {
 return new ConnectionHelper(context);
 } @Reusable @Singleton @Reusable
 @Component(modules = {AppModule.class})
 public interface AppComponent {}

Slide 40

Slide 40 text

@Inject
 Lazy mConnectionHelper;
 ... mConnectionHelper.get().isConnected(); Lazy and Provider Injections @Inject
 Provider mConnectionHelper;
 ... mConnectionHelper.get().isConnected();

Slide 41

Slide 41 text

@Target(ANNOTATION_TYPE)
 @Retention(RUNTIME)
 @Documented
 public @interface Qualifier {} @Qualifier @Qualifier
 @Documented
 @Retention(RUNTIME)
 public @interface Named {}

Slide 42

Slide 42 text

@Provides @Singleton @Named(“Adapter 1”)
 public RestAdapter providesRestAdapter1() { return …; } @Qualifier @Provides @Singleton @Named(“Adapter 2”) public RestAdapter providesRestAdapter2() { return …; }

Slide 43

Slide 43 text

@Qualifier @Inject @Named(“Adapter 1”) RestAdapter mRestAdapter;


Slide 44

Slide 44 text

Subcomponents and Scopes - Subcomponents allow you to combine different modules at runtime - Scopes let you define the lifetime of a dependency

Slide 45

Slide 45 text

Testing and dagger - Constructors used for injections can be used for testing - Test Modules for espresso

Slide 46

Slide 46 text

Questions - @or_bar - [email protected] - orbar1.tumblr.com