Introduction to Dependency Injection in Android using Dagger 2

in #utopian-io7 years ago

Repository

https://github.com/aosp-mirror/

What Will I Learn?

  • You will learn what Dependency Injection is all about
  • You will learn how to use Dagger 2 in your android applications

Requirements

  • Android Studio 2.3 and above
  • Knowledge of native Android development using Java

Difficulty

  • Advanced

Tutorial Contents

DI.png
Image Source

Dependency Injection is a software engineering term that relates to how dependencies of classes are created and used in software applications. It is a design pattern that entails the injection of objects that classes depend on, into the classes from an external source rather than having the classes generate them.

This pattern effectively takes away the effect of reflection and promotes code decoupling thereby making sure that classes can be focused on what they are supposed to do rather than having to worry about how its objects/dependencies are created.
A basic example of dependency injection can be seen from the code below, consider a class Computer that depends on a class called Keyboard

public class Computer{

private Keyboard keyboard;

public Computer(){
keyboard = new Keyboard();
}
}

In this class, to use the keyboard object, it has to be created by the Computer class which leads to problem of the class having to always deal with instantiation of the object. A better approach is presented in the code below using dependency injection pattern,

public class Computer{

private Keyboard keyboard;

public Computer(Keyboard keyboard){
this.keyboard = keyboard;
}
}

From this, it can be seen that the keyboard object is injected into the class via its constructor at instantiation, this method is also known as constructor injection. Methods and fields can also be injected so as to use dependency injection pattern.

The Dependency Injection pattern has been in existence for a while now but only became popular with its usage in developing android applications. A number of libraries have been developed for dependency injection in android including Spring, Guice and Dagger 2. Dagger 2 however is the best solution and is preferred for this tutorial because it helps in code decoupling, does its verification at compile time unlike the others that do theirs at runtime and dagger 2 can also automatically generate code that would be needed for all injections within the android application.

To get started with dagger 2 in your application, add the following dependencies to your build.gradle file under the dependencies block and build,

implementation 'com.google.dagger:dagger:2.12'
implementation 'com.google.dagger:dagger-android:2.12'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.12'
annotationProcessor 'com.google.dagger:dagger-compiler:2.12'

Note- These versions may have been updated as at the time you may implement this tutorial.

These dependencies add the library files required by dagger 2 to work in your android application. To use dagger 2, a couple of annotations are used at different points, these annotations include,

@Inject

@Module

@Component

@Provides

The functions of these annotations will be explored shortly, in the meantime create a new class in your app that extends the android Application class, in my case this class is called MyApplication and add it to your manifest file under the application tag. This class would be the first created class of your application when it is launched and can be regarded as the root class of your application.

Thereafter create another class called MyApplicationModule and annotate it with the @Module annotation and type in the following lines of code that will be explained shortly.

@Module
public class MyApplicationModule{
private MyApplication myApplication;

public MyApplicationModule(MyApplication myApplication){
this.myApplication = myApplication;
}

@Provides
Context provideApplicationContext(){
return myApplication;
}
}

The class is annotated with @Module which means that the class acts as a module in dagger 2. A module class in dagger 2 is a class that supplies the dependencies/objects to other dependent classes when required. It holds all the possible objects that can be injected into other classes that needs them. In our module class, the root of the application is passed into its constructor and it is then returned in the method called provideApplicationContext which is annonated with the @Provides annotation which simply means that a context object is provided from the method that can be injected anywhere in the app.

Now create an interface called MyApplicationComponent, this interface is annotated with the @Component annotation and is a way for dagger 2 to know the various classes that it can inject with objects from a provided module. This interface is very important as without it, dagger 2 does not know which class to inject and will throw a compile time error when a class not listed as injectable in the interface is injected with an object.

@Component(modules = {MyApplicationModule.class})
public interface MyApplicationComponent{
void inject(MyApplication myApplication);
}

As seen, this interface has been provided with the module we created earlier and in any class that an injection is needed, the component interface looks for the required object in the module and if it is there, it provides it for injection using the earlier defined methods that have been annotated with @Provides.

Various methods can also be created in the interface to represent which class can be injected. In the code above, it is seen that the MyApplication class can be injected with an object from the module.

Now in the MyApplication class, type in the following lines of code,

public class MyApplication extends Application{
MyApplicationComponent myApplicationComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        myApplicationComponent = DaggerMyApplicationComponent.builder().myApplicationModule(new MyApplicationModule(this)).build();
        myApplicationComponent.inject(this);
    }

    public MyApplicationComponent getMyApplicationComponent(){
        return myApplicationComponent;
}
}

The code above would show an error when initially typed and this is where the beauty of dagger 2 comes into play. By clicking on rebuild project, dagger 2 automatically generates code and classes that would be needed for injection. Most of these generated classes are prefixed with Dagger. This code snippet above simply builds an AppComponent injector using the automatically generated class in the root of the application. This injector can be used anywhere in the app and is simply used to inject a class by calling the inject() method on it and passing in the class to be injected. The method in the code helps to return an instance of the Component injector.

These are the basic steps required to set up dagger 2 for our application, now to inject a class is a very straightforward process. Take for example we want to inject an Activity called BaseActivity with a Calendar object, first of all, we go to the module class where we provide the Calendar object,

@Provides
Calendar provideCalendar(){return Calendar.getInstance();}

we then go to the MyApplicationComponent interface to indicate that the BaseActivity class is to be injected by providing a method to do this,

void inject(BaseActivity baseActivity);

Finally in our BaseActivity onCreate(), we inject the activity and create a field object of Calendar with an @Inject annotation,

public class BaseActivity extends AppCompatActivity {

@Inject
Calendar calendar;

@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ((DaggerApplication)getApplication()).getMyApplicationComponent().inject(this);
}
}

There you go, the Calendar object can now be used as pleased. Do note that the BaseActivity class has no idea on how the Calendar object is instantiated, this helps it to focus more on using the object than actually creating it. Another good benefit of dagger 2 is that any activity that extends from BaseActivity can use this same calendar object without any need for further injection.

This solves the problem of creating many objects of the same type at a time thereby helping save memory, the policy is therefore inject once and use everywhere. Furthermore, the provided objects can even be further restricted to a single instance in the module by annotating the method that provides them with a @Singleton annotation which ensures that dagger 2 only creates a single instance of it for use in the whole application thus saving memory and reducing boilerplate code.

Conclusion

In conclusion, it is not just enough to code or develop an application that works but one that works effectively and efficiency and being able to manage android's limited resources, hence it is advised to incorporate the use of dependency injection in android applications as a means of coding with best practices. I hope you learned something from this, do ensure you start right away with dagger 2 in your android applications from today.

Proof of Work Done

To learn more on dependency injection check out code from an application i developed using dagger 2 via the link
https://github.com/demistry/MedManager/tree/master/app/src/main/java/com/medmanager/android

Sort:  

Thank you for your contribution.

Your contribution has been evaluated according to Utopian rules and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, Click here


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hey @davidemi
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Loading...