Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dagger.Android module

Dagger.Android module

In this talk, we will explore the usage of the new Dagger Android functionality. We will:
1. go through the Dagger Android module and will see how it can be used in Android applications;
2. compare the differences between how code looks like with using this module and usual way of using Dagger in Android;
3. talk about how this module helps with integration tests.

Dmytro Khmelenko

November 25, 2017
Tweet

More Decks by Dmytro Khmelenko

Other Decks in Programming

Transcript

  1. DEPENDENCY INJECTION “Dependency injection is a technique whereby one object

    supplies the dependencies of another object.” 2
  2. DAGGER • dependency injection framework started by Square, now maintained

    by Google • compile-time • is currently in active development 3
  3. MODULE 4 @Module abstract class NetworkModule { @Provides @Singleton static

    Retrofit retrofit() { return new Retrofit.Builder() .baseUrl("https://api.freeletics.com") .build(); } @Provides @Singleton static FreeleticsRestClient provideRestClient(Retrofit retrofit) { return new FreeleticsRestClient(retrofit); } }
  4. COMPONENT 5 @Singleton @Component(modules = {NetworkModule.class}) public interface BaseComponent {

    void inject(MainActivity activity); FreeleticsRestClient freeleticsClient(); }
  5. INJECTION 6 public class MyApp extends Application { private BaseComponent

    mBaseComponent; public void onCreate() { super.onCreate(); mBaseComponent = DaggerBaseComponent.create(); } public static MyApp instance() { return (MyApp) getApplicationContext(); } public BaseComponent activityInjector() { return mBaseComponent; } }
  6. INJECTION 7 public class MainActivity extends AppCompatActivity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyApp.instance().activityInjector().inject(this); } }
  7. SO WHAT’S WRONG WITH THAT? 9 @Override protected void onCreate(Bundle

    savedInstanceState) { super.onCreate(savedInstanceState); BaseComponent baseComponent = (BaseComponent) MyApp.get(this) .component(); WorkoutComponent component = baseComponent .workoutComponent(new WorkoutModule(this)); component.inject(this); }
  8. SO WHAT’S WRONG WITH THAT? 10 • copy-paste component/subcomponent injection

    in each activity/ fragment • activity/fragment needs to be declared for injection
  9. SO WHAT’S WRONG WITH THAT? 11 @Singleton @Component(modules = {NetworkModule.class})

    public interface BaseComponent { void inject(MainActivity activity); void inject(AuthActivity activity); void inject(RegistrationActivity activity); void inject(WorkoutActivity activity); void inject(WelcomeFragment fragment); }
  10. MODULE 13 @Module abstract class NetworkModule { @Provides @Singleton static

    Retrofit retrofit() { return new Retrofit.Builder() .baseUrl("https://api.freeletics.com") .build(); } @Provides @Singleton static FreeleticsRestClient provideRestClient(Retrofit retrofit) { return new FreeleticsRestClient(retrofit); } }
  11. BUILDER 14 @Subcomponent(modules = {NetworkModule.class}) public interface MainActivitySubcomponent extends AndroidInjector<MainActivity>

    { @Subcomponent.Builder abstract class Builder extend AndroidInjector.Builder<MainActivity> { } }
  12. ACTIVITY BINDING 15 @Module(subcomponents = MainActivitySubcomponent.class) public abstract class MainActivityModule

    { @Binds @IntoMap @ActivityKey(MainActivity.class) abstract AndroidInjector.Factory<? extends Activity> bind(MainActivitySubcomponent.Builder builder); }
  13. ACTIVITY BINDING 17 @Subcomponent(modules = {NetworkModule.class}) public interface MainActivitySubcomponent extends

    AndroidInjector<MainActivity> { @Subcomponent.Builder abstract class Builder extend AndroidInjector.Builder<MainActivity> { } } @Module(subcomponents = MainActivitySubcomponent.class) public abstract class MainActivityModule { @Binds @IntoMap @ActivityKey(MainActivity.class) abstract AndroidInjector.Factory<? extends Activity> bind(MainActivitySubcomponent.Builder builder); }
  14. ACTIVITY BINDING 18 @Module public abstract class MainActivityModule { @ActivityScope

    @ContributesAndroidInjector(modules = {NetworkModule.class}) abstract MainActivity contributeYourActivityInjector(); }
  15. INJECTION 20 public class MyApp extends Application implements HasActivityInjector {

    @Inject DispatchingAndroidInjector<Activity> mInjector; public void onCreate() { super.onCreate(); BaseComponent baseComponent = DaggerBaseComponent.create(); baseComponent.inject(this); } @Override public AndroidInjector<Activity> activityInjector() { return mInjector; } }
  16. INJECTION 21 public class MainActivity extends AppCompatActivity { @Override protected

    void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); super.onCreate(savedInstanceState); } }
  17. TESTING 26 @Module(subcomponents = TestMainActivitySubcomponent.class) public abstract class TestMainActivityModule {

    @Binds @IntoMap @ActivityKey(MainActivity.class) abstract AndroidInjector.Factory<? extends Activity> bind(TestMainActivitySubcomponent.Builder builder); }
  18. TESTING 28 public class TestApp extends Application implements HasActivityInjector {

    @Inject DispatchingAndroidInjector<Activity> mActivityInjector; @Override public void onCreate() { super.onCreate(); DaggerTestComponent.create().inject(this); } @Override public DispatchingAndroidInjector<Activity> activityInjector() { return mActivityInjector; } }
  19. TESTING 29 public class FreeleticsTestRunner extends AndroidJUnitRunner { @Override public

    Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { String appClassName = TestApp.class.getCanonicalName(); return super.newApplication(cl, appClassName, context); } }