Skip to content

Instantly share code, notes, and snippets.

@benjamin-ict
Last active August 19, 2020 20:40
Show Gist options
  • Save benjamin-ict/9662b34c4adc67a710d16d0c6f936fac to your computer and use it in GitHub Desktop.
Save benjamin-ict/9662b34c4adc67a710d16d0c6f936fac to your computer and use it in GitHub Desktop.
Guide to Dagger

Guide to Dagger

Quick defs

Providing refers to the availability of an object in the Dagger graph. If something provides a class, it adds it to the graph. A class requires its dependencies to be provided in order to injected using Dagger.

Satisfying dependencies

  1. @Inject constructor

        @Inject
        public MyClass(Parameter p1) {
            this.p1 = p1;
        }
    • Used to provide instances of MyClass
    • This is the preferred way of injecting things
    • Tries to inject parameters; parameters must be provided
    • Requires that you assign fields manually
    • Cannot be used for external dependencies
    • Cannot be used in Android Application, Activity, or Fragment classes
  2. @Inject fields

    class MyClass {
        @Inject
        Field f1;
    
        @Inject
        Field f2;
    }
    • Does not allow for injecting instances of MyClass
    • Injects fields directly
    • All fields must be provided
    • Cannot be used for external dependencies
  3. @Provides

    @Provides
    MyClass provideMyClass(Parameter p1) {
        return new MyClass(p1);
    }
    • Allows for specific implementations of a class to be provided
    • Works with external dependencies
    • Parameters must be provided
    • Must be in a Module
  4. @Binds

    @Binds
    abstract MyClass bindMyClass(Parameter p1);
    • Used to provide simple instances of MyClass where the parameters of the method directly refer to the parameters required by MyClass
    • Works with external dependencies. Probably would never be used for internal dependencies since if this works, then @Inject constructor will work too, and @Inject constructor is preferred.
    • Parameters must be provided
    • Must be in a Module
  5. @BindsInstances

    @Component.Builder
    interface Builder {
        @BindsInstance Builder foo(Foo foo);
        @BindsInstance Builder bar( @Blue Bar bar);
    }
    
    // or
    
    @Component.Factory
    interface Factory {
        MyComponent newMyComponent(
            @BindsInstance Foo foo,
            @BindsInstance @Blue Bar bar
        );
    }
    • Not entirely sure how this one works tbh
  6. AndroidInjection.inject() (Android only)

    class MyActivity extends Activity {
        public void onCreate(Bundle savedInstanceState) {
            AndroidInjection.inject(this);
            super.onCreate(savedInstanceState);
        }
    }
    • Used to inject dependencies into an Activity or Fragment.
    • Requires a Subcomponent that extends AndroidInjector with this activity as the generic.
    • In an Activity, it must be called in onCreate, before the super call.
    • In a Fragment, it must be called in onAttach. It does not matter whether it is called before or after the super call.
  7. AndroidInjector (Android only)

    @Subcomponent
    interface MyActivitySubcomponet extends AndroidInjector<MyActivity> {
        @Subcomponent.Factory
        public interface Factory extends AndroidInjector.Factory<MyActivity> {}
    }
    • Use this to enable AndroidInjection.inject(this) on an Activity.
    • Require a base Application that implements HasAndroidInjector
  8. @ContributesAndroidInjector (Android only)

    @Module
    abstract class MyModule {
        @ContributesAndroidInjector
        abstract MyActivity contributeMyAndroidInjector();
    }
    • Generates an AndroidInjector Subcomponent within a Module.
    • Accepts Module dependencies
  9. DaggerActivity (Android only)

    class MyActivity extends DaggerActivty {
        @Override
        void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
    }
    • Removes the need to call AndroidInjection.inject(this);
    • Implements HasAndroidInjector, so it provides an injector for all children (Fragments, etc.)
  10. DaggerAppCompatActivity (Android only)

    • see DaggerActivty
  11. DaggerApplication (Android only)

    • see DaggerActivity
    • provides AndroidInjector at Application level
    • still needs AppComponent
    public class MyApplication extends DaggerApplication {
    
        @Override
        protected AndroidInjector<? extends AndroidSampleApp> applicationInjector() {
            return DaggerMyApplicationComponent.builder().create(this);
        }
    }
    • DaggerMyApplicationComponent is a generated class. This will probably show as an error until you compile the project as Dagger is a compile-time dependency.
  12. DaggerFragment (Android only)

    • see DaggerActivity
  13. DaggerAppCompatFragment (Android only)

    • see DaggerActivity

Building the graph

  1. @Module

    @Module
    abstract class MyClassModule {
        @Binds 
        abstract MyClass1 bindMyClass1();
    
        @Provides
        MyClass2 provideMyClass2(Parameter p1) {
            return new MyClass2(p1);
        }
    }
    • Container for @Binds and @Provides methods
    • Needs a Component to access non-static methods
    • May inherit from other Modules
    • Modules are usually abstract classes
  2. @Component

    @Component(modules = {MyClassModule.class})
    interface MyClassComponent {
    
    }
    • Allows you access non-static methods in a Module.

    • To create an instance, you must use the generated builder:

      MyClassComponent myClassComponent = DaggerMyClassComponent.builder()
          .myClassModule(new MyClassModule())
          .build();
    • If all dependencies have 0-arg constructors, then you can also do:

      MyClassComponent myClassComponent = DaggerMyClassComponent.create()
    • Components are usually interfaces

  3. @Subcomponent

    • They're basically just components that are children of other components. May be attached to modules in the Module annotation.
    • Typically set up like this (I think):
    @Subcomponent
    interface MySubComponent {
    
    }
    
    @Module(subcomponents = {MySubComponent.class})
    abstract class MyModule {
    
    }
    
    @Component(modules = {MyModule.class})
    interface MyComponent {
    
    }
    • Subcomponents are usually interfaces
  4. HasAndroidInjector (Android only)

    public class YourApplication extends Application implements HasAndroidInjector {
        @Inject DispatchingAndroidInjector<Object> dispatchingAndroidInjector;
    
        @Override
        public void onCreate() {
            super.onCreate();
            DaggerYourApplicationComponent.create()
                .inject(this);
        }
    
        @Override
        public AndroidInjector<Object> androidInjector() {
            return dispatchingAndroidInjector;
        }
    }
    • Used to allow injection into and Android project at the Application level.
    • May also be used in Activities or Fragments
    • Implementation must override androidInjector() and supply and instance of DispatchingAndroindInjector.
    • This is standard when using the dagger-android library.
    • A class may both implement HasAndroidInjector and use AndroidInjection.inject().

Provision methods

  • Lazy

    Lazy<MyClass> getMyClass();
    • Provides a single instance of a class. The instance is initialized until the first call to the method.
  • Provider

    Provider<MyClass> getMyClass();
    • Provides a new instance of a class everytime this is called.

Helpful examples

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment