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:

[java]
@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);
}
}
[/java]

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 be 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:

[java]
@Module(
library = true
)
public class InteractorsModule {

@Provides public FindItemsInteractor provideFindItemsInteractor() {
return new FindItemsInteractorImpl();
}

@Provides public LoginInteractor provideLoginInteractor() {
return new LoginInteractorImpl();
}
}
[/java]

Add it to AppModule as you previously did with DomainModule:

[java]
@Module(
injects = {
App.class
},
includes = {
DomainModule.class,
InteractorsModule.class
}
)
public class AppModule {

}
[/java]

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:

[java]
public ObjectGraph createScopedGraph(Object… modules) {
return objectGraph.plus(modules);
}
[/java]

And now in Activity we inject the presenter instead of instantiating it, create the graph and inject the activity:

[java]
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;
}


}
[/java]

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.

Dagger example at Github

If you have any doubts or think that another post will be useful to clarify any concept, please write a comment.

42 thoughts on “Dagger: Scoped object graphs (Part 3)”

  1. Great Post. I have been keeping following this series posts. I am wondering whether there is any plan to combine Retrofit into this to make it more powerful as a standard Framework for any Android Project. This would be greatly helpful to those who is not satisfying the current development process.

    1. Antonio Leiva

      It’s quite straightforward from here. You only need to create your data layer and call it from interactors. What you use to provide data (Retrofit, database, volley) doesn’t matter anymore.

  2. Have you looked at Square’s Mortar and Flow libraries at all? They’re doing a very similar thing but eschew using Fragments, Activities etc.

    1. Antonio Leiva

      Yeah I did, but I’m not convinced that it will work on big projects and for smartphones and tablets. It maybe does, but I haven’t tested so far. Do you like it? The structure is good, but using only views for layouts is quite strange.

      1. I like some of the ideas but there’s so much biolerplate code to get up. And I have the same concerns with tablet vs phone layouts, etc. The presenters are dependent on Android SDK classes too, so you can’t unit test them outside of the Android framework which takes away a lot of the advantages of MVP on Android. I really want something in between.

      2. I think is OK to extract some code from complex activities… But why to complicate yourself following the “clean architecture”? In practice you are not reusing code in other platforms.

  3. A short question regarding the structure of modules: why have you decided to include InteractorsModule into AppModule? It seems to me that interactors does not logically belong to global app-wide scope? Would it be better to put every specific interactor into a local, scoped graph where it actually belongs to?

    1. Antonio Leiva

      I do it that way because interactors are reusable by definition. You would have to repeat the provider method everywhere you use that interactor. Besides, the interactors module is part of a different layer, so I find a good practice that every layer provides their own objects. As interactors are not singletons, they won’t be kept in memory when they are not used anymore.

  4. Thanks a lot for the posts so far! I would love to see post on how to modify the dagger object-graphs inside tests.

  5. Merci beaucoup, j’attendais la troisième partie avec impatience pour pouvoir débuter mes projets !
    Je vais enfin pouvoir coder proprement !

  6. Thank you very much for your last posts. They were really interesting. I read several times all the posts and I think I have a good big picture of the situation here, but I still wonder what is your approach with fragments. I read before in one of the last posts commentaries that you rely on the activity presenter to dispatch the fragments tasks to the interactor and send it back to the fragment view. At least in most cases.

    I personally prefer to decouple it and each fragment implement his own presenter and view interface. So I am facing the following doubt, should I create a dagger scopeGraph for each fragment to inject the fragment presenter? What is your approach in this case?.

  7. Please how can I get application context, for example in LoginInteractorImpl ? do I use @Inject Application app ? because if I do this I got a NullpointerException…

    I thank anyone who can help me !

      1. Thank you very much! plus I really didn’t expect that you will answer me in less than 5 minutes!

        You are great, it works very well !

      2. For those who are in same situation, InteractorsModule should look somethig like this:

        @Module(
        complete = false, // add this
        library = true
        )

        @Provides
        public LoginInteractor provideLoginInteractor(Application app) {
        return new LoginInteractorImpl(app); // you have to modify the constructor of LoginInteractorImpl, of course
        }

  8. Hi I have some doubts:

    – In LoginActivity you are getting the App object graph and doing “plus.(LoginModule)” when LoginModule dies?
    – You have a presenter, a module and a View for each activity/fragment, what is the function of the module? only provide view/presenter?
    – If you need to make network request who have to make it? the module?
    – In a configChange the onDestroy of an Activity will be called, and later the onCreate for recreating the activity (for example in a rotation change) a new loginModule is created, is this correct? Maybe you need to “retain” for no create two modules?
    – If you need to send a Bitmap instance (or something that is not serializable/parcelable) from LoginActivity to MainActivity, how will you achieve that?

    Thanks for your posts Antonio!!!

    1. Antonio Leiva

      Hi Christian. I answer in the same order:
      – The entire activityGraph dies when the LoginActivity dies, because this activity is the only reference to that class.
      – Yes, in this case that’s the function. More complex apps will need to inject more objects.
      – Nope, module only provides objects by creating their instances. Interactor will do the task of calling the server (or even domain) layer.
      – Yes, that is correct. If activity dies, activityGraph must die because it contains a reference to that activity. Retaining an activity (I thing you refer to not destroying on configChanges) is not always possible, and I personally don’t like, but may be an option.
      – That last question is apart from this context, because injection won’t handle it. Big (and not serializable) objects needs to be persisted on disk or cached in memory. You can imagine many mechanisms to do this. Bitmap is parcelable, but you will find lot of problems by using intents to send bitmaps.

      1. Thanks for your reply Antonio,

        Relative to network requests, i was not undestanding what “interactors” does, now is more clear 🙂

        I still having a doubt about this, if you make a network request for ex in LoginActivity / loginInteractor, method login(). And you make a rotation, the module and presenter will die, who will received this response, is lost? Also if you receive the response and you want to save a reference for later usage instead of request to network again, who will do this?

        Thanks again 🙂

      2. Antonio Leiva

        In this example, the request would be lost. I tend to use Otto on interactors to send the callback, so what would happen in that situation is that presenter would attach to bus again, and will receive the response when it finishes.
        If it’s the case of login, you would probably want to save some kind of token on SharedPreferences or someting similar. I would inject a handler for that preference into interactor. A good example about SharedPreferences injection is in U2020 app by Jake Wharton.

      3. mlavigne016

        Based on this example how would you handle the case where the presenter isn’t active when the login event is posted by your interactor. You mention that you could save the login state in the SharedPreferences but how would that help that particular use case?

        Would you also inject the SharedPreference into the Presenter so that the login state can be verified when it becomes active again?

  9. I apologize for my question, but it’s been days since I am trying to implement this for a fragment, a hint please?

    1. Antonio Leiva

      What problems are you finding? You only need to add those fragments to activity graph. After that, you will have everything you want injected.

      1. I am struggling to use your MVP approach with Fragments, I am having problems specifically with the provideFragmentPresenter method in the Activity module class which should be able to return the fragmentPresenterImpl.

        When creating the instance of the fragmentPresenterImpl in the provide method I am not sure how to set the fragment view. I am not using any “View” Interface, instead I am directly working on the actual Activity/Fragment, the problem is that fragment is always null when used in the provideFragmentPresenter method.

        I am injecting the Fragment onActivityCreated, but still there must be something I am doing wrong, any idea/advice on what could I be doing wrong?

        Thank you!

      2. Just in case anybody else comes across the same issue. I was not able to implement this approach (using a Module for both the Activity and the Fragment), as suggested somewhere else in the comments, I finally implemented a Module for each.

  10. I’m still not sure what interactors are out how to use them. Purple keep mentioning Otto, but I feel like I’m missing that piece of the conceptual puzzle. Do you have a reference you could point me to?

    1. Antonio Leiva

      The idea of interactor is not what I wanted to explain here, but I think it will need another separate article. The idea is taken from clean architecture by uncle Bob, you can read more about here: http://goo.gl/EYbFDD

  11. Hello, Antonio ! Thank you for your articles – great job !

    I have some thoughts about using Dagger with MVP. So, in one of your comments to the MVP-article, you wrote that “use scoped modules to prevent memory filling with singletons and object that won’t be used again” and in another comment – “You will also need to save current status to let the recreated activity know that a login operation is currently executing “. After reading this article everything became clear to me – we create Presenter as singleton (which won’t fill memory if I left from Activity, due to using Dagger’s scoped modules), we can perform async tasks in Presenter and save a status of the task in the Presenter to properly show UI during orientation changes. Looks very sweet. So I started my investigations. I done the same like you – I create Presenter’s module and graph in onCreate, onDestroy I assign null for the graph field, to allow the Garbage Collector to clean the memory it uses. But I didn’t noticed earlier, that every time on orientation change we new instance of Presenter’s module and it means that we create new instance of Presenter object. So the thing about storing the status of the async task in the Presenter becomes useless – why to store it if every time config changes occurs we have new instance of presenter.

    So what to do in that situations ? Maybe I’m loosing something ? It would be great to read your opinion and some words about the technique you use. Tahsnk you !

  12. Hi, please can you provide us a tutorial about how to organize the domain and data layers ? thanks !

  13. benjamin.duvivier@gmail.com

    Hi Antonio,

    Thank you very much for your articles about Dagger :). It really helped me getting into it. Good job !

    Ben.

  14. Hi Antonio,

    Will the LoginInteractorImpl objects be freed in onDestroy when you set the activityGraph to null?

    1. Antonio Leiva

      It will be freed, but it doesn’t have to do with the activityGraph. `LoginInteractor` is not provided as a singleton, so the graph doesn’t need to keep its instance, and it will be freed as soon as it is not used anymore (when the activity is destroyed).

  15. Thanks for the article. Curious if it would be possible to have a scope for multiple activities. Like say activity 1, 2 and 3 should share the same graph and singletons. Wondering how to have that work with the lifecycle, seems like we would want a shared static reference to that module somewhere (that knows when all the activities in the flow no longer need it, to release itself). Any ideas?

  16. Hi, Antonio!
    What do you think about AndroidInjector? I’ve added it to my project, but I’m worried about it. Someone doesn’t like this approach. What about you?

    Thanks

Comments are closed.