Dagger 2.11 with Android

Idorenyin Obong
Aug 24, 2017 · 3 min read

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 now maintained by Google.

Dagger-Android are Android specific helpers for Android, specifically the auto generation of sub components using a new code generator.

The new dagger version introduces new annotations which makes our android application further conform to the rule of dependency injection as against previous versions.

Lets learn how we can inject this to our application.

  1. 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'

2. 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. And since abstract classes require subclasses to provide implementations for the abstract methods, dagger does this for us. So, 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.

3. We create another module for activity binding. This module class makes Dagger know our activities in compile time. We will use @ContributesAndroidInjector. With this annotation, we can easily attach activities/fragments to dagger graph. In a nutshell, since we are going to use dependencies in this Activity, this provides an injector factory for the activity .

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

But the first snippet for step3 solves that for us using @ContributerAndroidInjector.

4. 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.

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


}

6. Then finally, in your MainActivity 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

References/resources
https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger/

https://medium.com/@iammert/new-android-injector-with-dagger-2-part-1-8baa60152abe

Idorenyin Obong

Written by

Android developer