· 3 min read
Dagger: Scoped object graphs (Part 3)
If you’ve been following this series, you already read about dependency injection basics on part 1 and Dagger fundamentals on part 2. This last part about Dagger and dependency injection Android is focused on scoped object graphs.
What’s the use of scoped graphs in Dagger?
When we instantiate Dagger singletons in application object graph, they live in memory until the app is destroyed. But there are some singleton dependencies that are useful only when another object is alive. A simple example is a view and its presenter. Most of times you will only use a presenter with an activity at the same time. In MVP, a presenter without a view is useless. We don’t need to keep it in memory after the activity is destroyed.
How to create a scoped graph?
It’s easy, we will add it to the application graph. I’m creating a module per activity. So let’s see an example in LoginActivity:
@Module(
injects = LoginActivity.class,
addsTo = AppModule.class
)
public class LoginModule {
private LoginView view;
public LoginModule(LoginView view) {
this.view = view;
}
@Provides
@Singleton
public LoginView provideView() {
return view;
}
@Provides
@Singleton
public LoginPresenter providePresenter(LoginView loginView, LoginInteractor loginInteractor) {
return new LoginPresenterImpl(loginView, loginInteractor);
}
}
This module injects LoginActivity, because it needs to inject the presenter to the activity directly, not via constructor. It will be added to AppModule when we create the activity graph. Both things must be declared at @Module annotation.
As you can see, I added a new dependency to LoginPresenter. Its LoginInteractor will be injected from a new module called InteractorsModule. It’s a simple and standard module:
@Module(
library = true
)
public class InteractorsModule {
@Provides
public FindItemsInteractor provideFindItemsInteractor() {
return new FindItemsInteractorImpl();
}
@Provides
public LoginInteractor provideLoginInteractor() {
return new LoginInteractorImpl();
}
}
Add it to AppModule as you previously did with DomainModule:
@Module(
injects = { App.class },
includes = { DomainModule.class, InteractorsModule.class }
)
public class AppModule {
...
}
Let’s create the object graph. It will be created by calling plus() to application graph and passing new modules. So I created this method in App:
public ObjectGraph createScopedGraph(Object... modules) {
return objectGraph.plus(modules);
}
And now in Activity we inject the presenter instead of instantiating it, create the graph and inject the activity:
public class LoginActivity extends Activity implements LoginView, View.OnClickListener {
@Inject
LoginPresenter presenter;
...
private ObjectGraph activityGraph;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
...
activityGraph = ((App) getApplication()).createScopedGraph(new LoginModule(this));
activityGraph.inject(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
activityGraph = null;
}
...
}
Set it to null in onDestroy so that it will be freed by garbage collector as soon as possible. Now you will have presenter, view and model injected using Dagger.
Conclusion
Dagger is a powerful tool, but its learning curve is larger than other libraries because it’s important that main concepts are embraced and that you understand why it is useful. I hope this set of articles helped you resolve most of difficulties you may find at the beginning.
I updated the code and created a BaseActivity that encapsulates the repetitive work of instantiating the scoped graph.
If you have any doubts or think that another post will be useful to clarify any concept, please write a comment.