An Introduction to Dagger 2 (Android DI) – Part 1
Dagger 2 is a dependency injection (DI) framework. It's based on the javax.inject annotations standard. Here's an overview of getting started with Dagger 2, from a module to initializing a dependency graph.
Join the DZone community and get the full member experience.
Join For FreeDagger 2 is a dependency injection framework that is built on the standard javax.inject
annotations (JSR 330). Dependency injection is a software design pattern that implements inversion of control for resolving dependencies. Implementing proper dependency injection in our apps allows us to have:
- Testable classes.
- Re-usable and interchangeable components.
In Android, there are a lot of dependency injection frameworks that you can use. However, one of the greatest advantages of Dagger is that is based on Code generation not on Reflection like Google RoboGuice which makes Dagger more efficient.
In Dagger 2, you can inject dependencies on fields and constructors as shown in the following examples. Injecting dependencies on methods is also possible.
// Field Injection Example
@Inject
HelloService helloService;
// Constructor Injection Example
HelloService helloService;
@Inject
public MyClass(HelloService helloService) {
this.helloService = helloService;
}
In order to understand Dagger, it is important to identify Dagger main terms:
- Module.
- Component.
Module
Before defining what a Dagger module is and since this is a first basic example to show how Dagger 2 works, assume that we have only one simple service interface (HelloService
) that is defined below.
public interface HelloService {
public String greet(String userName);
}
HelloServiceManager
is the simple implementation for HelloService
interface as shown below.
public class HelloServiceManager implements HelloService {
@Override
public String greet(String userName) {
return "Hello " + userName + "!";
}
}
In order to inject HelloService
interface implementation, we need to define a Dagger module.
A dagger module provides the way that constructs the objects which will be injected. In order to define a dagger module, create a class and annotate it with @Module
annotation and define the provider methods that return the instances. Provider methods have to be annotated by @Provider
annotation as shown below.
@Module
public class MainModule {
DaggerApplication app;
public MainModule(DaggerApplication application) {
app = application;
}
@Provides
@Singleton
protected Application provideApplication() {
return app;
}
@Provides
@Singleton
HelloService provideHelloService() {
return new HelloServiceManager();
}
}
Here in this module, we provide two singleton instances of an Android application class (DaggerApplication
will be discussed later) and the HelloService
implementation class.
Component
A dagger component can be seen as an intermediate object which allows accessing to objects defined in Dagger modules.
One of the cool functions of a Dagger component is that it allows injecting non private field members to provided object as argument. In some cases, constructor injection is not possible, for example, the instances that are created and managed by the platform such as Android activity.
This is why we need to create a component interface that allows describing for which types we want to use members injection as shown below.
@Singleton
@Component(modules = {MainModule.class})
public interface DaggerGraphComponent {
void inject(MainActivity mainActivity);
static final class Initializer {
private Initializer() {
}
public static DaggerGraphComponent init(DaggerApplication app) {
return DaggerDaggerGraphComponent.builder()
.mainModule(new MainModule(app))
.build();
}
}
}
A dagger component can be created by annotating the class with @Component
annotation, you need also to specify the component’s associated modules which is a single module MainModule
in our case.
Since we have a single activity, we will have a single inject(MainActivity)
method in our Dagger component interface.
Once you annotate your component class with @Component
, Dagger will generate a builder class for our component class with the prefix (Dagger
). Using the builder class you can initialize the Dagger 2 dependency graph as follows.
DaggerDaggerGraphComponent.builder()
.mainModule(new MainModule(app))
.build();
Now, let’s see how to initialize dependency graph and consume services.
Initializing Dependency Graph
In order to initialize the Dagger 2 Dependency graph, we need to create an application class to call the component init()
method for initializing the Dagger 2 dependency graph and to keep the instance of created graph throughout application’s lifecycle.
The code below shows our Android Application class.
public class DaggerApplication extends Application {
private static DaggerGraphComponent graph;
private static DaggerApplication instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
buildComponentGraph();
}
public static DaggerGraphComponent component() {
return graph;
}
public static void buildComponentGraph() {
graph = DaggerGraphComponent.Initializer.init(instance);
}
}
Do not forget to register the application class in AndroidManifest.xml
as follows.
<application
...
android:name=".service.di.DaggerApplication">
...
</application>
Injecting HelloService in Activity
Finally, in order to inject HelloService
in your activity, do not forget to call DaggerApplication.component().inject(this)
in the Activity onCreate()
method as shown below.
public class MainActivity extends AppCompatActivity ... {
@Inject
HelloService helloService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerApplication.component().inject(this);
// ...
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.greet) {
// you can call helloService.greet("user1") for example ...
}
}
}
Check Out the Code
Check the sample app code in GitHub:
https://github.com/hazems/Dagger-Sample/tree/dagger-sample1
What is Next?
So in the next articles, I will discuss how Dagger 2 DI can also be very useful if you are utilizing Android Build variants and how can we apply unit testing techniques for Dagger 2 applications.
Published at DZone with permission of Hazem Saleh, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
The Role of Automation in Streamlining DevOps Processes
-
Understanding Data Compaction in 3 Minutes
-
Core Knowledge-Based Learning: Tips for Programmers To Stay Up-To-Date With Technology and Learn Faster
-
New ORM Framework for Kotlin
Comments