Dagger 2.11 With Android

Published Nov 23, 2017
Dagger 2.11 With Android

Dagger2 is a fully static, compile-time dependency injection framework for both Java and Android. It is an adaptation of an earlier version created by Square and is now maintained by Google.

Dagger-Android is an Android specific helper for Android, specifically it auto generates sub components using a new code generator.

The new Dagger version introduces new annotations, which make our Android applications further conform to the rule of dependency injection against previous versions.

Let's learn how we can inject this to our application.

Add dependencies in your build.gradle file:

compile 'com.google.dagger:dagger:2.11'
compile 'com.google.dagger:dagger-android-support:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'
  1. Create our Module class
@Module
public abstract class MainActivityModule {
@Binds
abstract NewClass bindsNewClass(NewClass newClass);
@Provides
@Named("unique_string_id") 
static String provideName(){
    return "I love Medium"
}
   
}

We declared an abstract class because we need abstract methods in the class.

@Binds supports only abstract classes. @Binds methods are a drop-in replacement for @Provides methods that simply return an injected parameter.

Since abstract classes require subclasses to provide implementations for the abstract methods, Dagger does this for us. Use binds when you just want to return a new instance of the parameter.

I used the named annotation because I might want to provide more than one string from this class, so that serves as a unique identifier.

Remember to use it when injecting a parameter in another class, e.g:

@Inject @Named(“unique_string_id”)
String s;

Note: @Binds methods must have a single parameter whose type is assignable to the return type of the method. If you ever want to put an @Provides annotated method in the abstract class, it must be static.

  1. We create another module for activity binding. This module class helps Dagger know our activities in compile time.

We will use @ContributesAndroidInjector. With this annotation, we can easily attach activities/fragments to the Dagger graph.

In a nutshell, since we are going to use dependencies in this Activity, this provides an injector factory for the activity, i.e Dagger knows this activity will need dependencies.

@Module
public abstract class ActivityBindingModule {
    @ContributesAndroidInjector(modules = MainActivityModule.class)
    abstract MainActivity mainActivity();
}

An alternative to the above snippet would be:

@Module
public abstract class ActivityBindingModule {
@Binds
@IntoMap
abstract AndroidInjector.Factory<? extends Activity>        bindMainActivity(MainActivitySubComponent.Builder builder);

}

The above snippet means that we would have to create a MainActivitySubcomponent interface (this inherits our main Component interface) annotated with Sub-component.

The class can then take in the MainActivityModule. An example of the SubComponent will look like this:

@Subcomponent(modules = MainActivityModule.class)
public interface MainActivityComponent extends AndroidInjector<MainActivity> { 
@Subcomponent.Builder 
abstract class Builder extends AndroidInjector.Builder<MainActivity {}
}

The first snippet for Step 3 solves that for us using
@ContributerAndroidInjector.

  1. Create our AppComponent class
    We can have as many modules as we need but we will have one component class.
@Component(modules = {AndroidSupportInjectionModule.class, ActivityBindingModule.class, MainActivityModule.class})
public interface AppComponent extends 
AndroidInjector<AppController> {

    @Override 
    void inject(AppController instance);

    @Component.Builder
    interface Builder {
        @BindsInstance
        AppComponent.Builder application(Application application);
        AppComponent build();
    }

}

The AndroidSupportInjectionModule class is a class from the Dagger library.

  1. Create the Application class.
public class AppController extends Application implements HasActivityInjector { 
@Inject 
DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector; 
@Override 
public void onCreate() { 
    super.onCreate(); 
    DaggerAppComponent.builder().application(this)
        .build().inject(this);
}
@Override 
public DispatchingAndroidInjector<Activity> activityInjector() { 
   return activityDispatchingAndroidInjector; 
}
But since we imported the support library, we can just extend DaggerApplication instead
public class AppController extends DaggerApplication {
    
    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        AppComponent appComponent = DaggerAppComponent.builder().application(this).build();
        appComponent.inject(this);
        return appComponent;
    }

   
}
  1. Then finally, in your
    MainActivity.java
    Class
    You can either use this:
public class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector  {
// The dependency you needed
@Inject NewClass newClass;
@Inject    
DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;
@Override
    protected void onCreate(Bundle savedInstanceState) {         
         AndroidInjection.inject(this);          
         super.onCreate(savedInstanceState);
        //...
}
@Override    
public AndroidInjector<Fragment> supportFragmentInjector() {        return fragmentDispatchingAndroidInjector;
}   
}

or use the support library:

public class MainActivity extends DaggerAppCompatActivity {
    @Inject NewClass newClass;    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //... 
    }
   
}

For fragments, you use:

@Override
public void onAttach(Context context) {
    AndroidSupportInjection.inject(this);
    super.onAttach(context);
}

or you extend DaggerFragment.

The NewClass will look like this:

public NewClass {
@Inject
public NewClass() {
}
}

If we are injecting a class that has a parameter, one of the modules must provide the data type of the parameter to be injected, e.g. if our NewClass is like this:

public NewClass {
@Inject
public NewClass(@Named("unique_string_id") String m) {
}
}

That means one of our modules must provide a method that returns a String, just like our MainActivityModule does.

@Provides
@Named("unique_string_id") 
static String provideName(){
    return "I love Medium"
}

We’re done! I hope this was useful. Thanks!

Discover and read more posts from Idorenyin Obong
get started