Kodeco Forums

Dependency Injection in Android with Dagger 2

The cry of ā€œYou must do dependency injection!ā€ is heard throughout modern software development teams. With such an imposing name, Dependency Injection (or DI for short) can put a fright into any software developer. It turns out that Dependency Injection is nowhere near as complex as its name implies, and is a key tool for [ā€¦]


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/660-dependency-injection-in-android-with-dagger-2

Hi,

Great post, I learned a lot!

I was thinking of not making the presenters as injection targets with their own Module, but something simpler like bellow:

public class FoodPresenterImpl implements FoodPresenter {
  private FoodView view;
  private UsdaApi usdaApi;

  public FoodPresenterImpl(UsdaApi usdaApi, FoodView view) {
    this.usdaApi = usdaApi;
    this.view = view;
  }
  .... 
}

Then in FoodActivity activity we could simply instantiate FoodPresenterImpl as per bellow:

@Inject
UsdaApi usdaApi;

@Override
protected void onCreate(Bundle savedInstanceState) {
   ...
   presenter = new FoodPresenterImpl(usdaApi, this);
   presenter.getFood(foodId);
}

This would decouple the two Presenters from Android API and making them easily testable with simple JUnit (I would even go as far as removing Log.e calls, etc) in effect making Presenters pure java classes.

I like your approach. I think you can take it one step further. If you modify the PresenterModule to include the Network module, you can modify the provider methods to get the UsdaApi from dagger, so your module will look like this:

@Module(includes = {NetworkModule.class})
public class PresenterModule {

    @Provides
    @Singleton
    FoodzPresenter provideFoodzPresenter(UsdaApi usdaApi) {
        return new FoodzPresenterImpl(usdaApi);
    }

    @Provides
    @Singleton
    FoodPresenter provideFoodPresenter(UsdaApi usdaApi) {
        return new FoodPresenterImpl(usdaApi);
    }
}

And the presenter can continue to be injected directly into the activity like they are now.

Thank you for taking your time and writing this blog, real interesting.
One question tho,
Why you passing context to the presenter?
I have build huge project and by passing context to the presenter I can see its
effect memory leak which is not good practice.
is there any way to avoid it. ?

are you trying to say context used on as static variables would make memory leakage?

Thanks for the tutorial. It goes along way to help understanding of DI and more specifically, Dagger 2. I am however, experiencing an issue with the starter project; it is unable to access the API - I checked the API_KEy and even did some API calls on postman, which work. The app, howevrr wont connect to it. Any ideas?

Thanks!

Thanks and glad the tutorial was useful! I re-downloaded the starter project today, opened it in Android Studio 2.3.3, and put my API key in Constants.java and was able to access the API. So, Iā€™m not sure what caused the problem for you. Were there any errors showing up in logcat?

Thanks for the reply. It turns out it was the network I was connected to, that was causing the issue with this API in the app for some reason. However in POST MAN it was fine. I tried the app on a different network and it worked just fine.

Thank you for your effort while writing this tutorial, but this is a real timewaster for Dagger beginners. This is not how a tutorial is written, because the reader is required to blindly copy-paste random lines of code (without proper explanation of these lines) of a library he/she is, obviously, not familiar with.
It is confusing and frustrating to implement a library (which requires a lot of effort to configure btw), just to achieve the same effect and state the app was in, before implementing that particular library.
The real question in this kind of tutorials that the tutors are failing to answer is Why?. Answers to questions like Why should I use Dagger when everything works fine without using it?, What are the benefits of using Dagger? should be answered when writing a tutorial which introduces a complex new library.

Sorry to hear you feel that way, azurh! I think we hit on the why quite a bit in this tutorial. Also, refactoring an app from one state (without DI) to another (with DI) is both a useful exercise and a common occurrence in professional software development (particularly when backed by a suite of unit and integration tests). After refactoring, the student can check out the diffs from the first state to the other in order to gain a grasp of the scope of implementing those changes. In any case, thanks for the feedback and best of luck to you!

I donā€™t agree with azurh. I think this was an excellently written tutorial. The why was covered both at the beginning and end of the tutorial. And having an app that behaves the same lets the reader know that everything is working as it should do except now with DI. I checked out a few Dagger tutorials whilst trying to learn it and this has been my favourite so far. Thanks Joe for this. Really appreciate it.

I think too that this is a great tutorial.

Itā€™s a starting point in a real example to get in touch with the tecnologyā€¦ I want to try it, so Iā€™ll do your tutorial and after it Iā€™ll see how, why and when put it in my projects and Iā€™ll learn more about dragger when needed.

I find it great, the best that Iā€™ve seen to get in touch with dragger2

Anywayā€¦

I have a question, because iā€™m not able to follow it at one point.

Iā€™ve following lines in my build.gradle:

annotationProcessor ā€œcom.google.dagger:dagger-compiler:2.11ā€
annotationProcessor ā€œcom.google.dagger:dagger-android-processor:2.11ā€
compile ā€œcom.google.dagger:dagger-android-support:2.11ā€

I use annotationProcessor instead of apt because of my version of gradleā€¦

classpath ā€˜com.android.tools.build:gradle:2.3.3ā€™

So I followed the tutorial until I reach the point of putting the DaggerAppComponent.buildā€¦ which gives me the ā€˜cannot find the variableā€™ error but, in my case, it doesnā€™t disappears when clicking twice in 'make module ā€˜appā€™"

What can be happening?

I loved this tutorial, and it really helped me grasp (a bit of) Dagger. It really shows nicely how the concept of a dependency graph works, and the generic steps to take. So I feel confident I understand the structure of it.

As it kept me hungry for more, it does leave me with a couple of questions.

Youā€™re passing the context to the presenter. In a lot of MVP documentation, I see that the presenter should be platform-independent. Passing the context to it, seems to break this?

The new paradigm for Android seems to be MVVM. Iā€™d love to see an example along the same way of explaining for this type of architecture.

Thanks for the kind words inigo!

I opened up the final project in Android Studio 3.0 Beta 4, and was able to build it with no changes, leaving the build tools at 24.0.4 and gradle plugin at 2.2.2. I also switched to using annotationProcessor and to both gradle plugin 2.3.3 and 3.0.0-beta4, and the app was still able to build for both of those plugins.

Could you try building the app in Android Studio 3.0 Beta 4 or later and see if you have the same issues? Also, does cleaning the project solve the issue?

Thanks so much fdomburg!

We didnā€™t get into testing in this tutorial, but youā€™re right that keeping the Android SDK out of the presenter would help in unit testing. See the comment from mtsahakis above.

MVVM is indeed gaining in popularity, especially with the introduction of Architecture Components. Iā€™m also a fan of Clean Architecture, using some version of MVP or MVVM in the presentation layer. Weā€™ll have more on this soon!

Thanks again!

Thanks very much the_new_mr!! I really appreciate the feedback!! :]

Awesome tutorial. I learned a lot and the addition of memes/images made this more entertaining than it would otherwise be. I do wish you included a couple of simple unit tests in the completed project to prove the benefit of dependency injection on testing.

Questionā€¦ You added this line to the presenters:

((DeezFoodzApplication)context).getAppComponent().inject(this);

Isnā€™t this bad practice? Because the presenters are no longer reusable since they depend on a concrete ā€œDeezFoodzApplicationā€.

Thanks for the feedback silentbyte. Passing in a UsdaApi into the presenter constructor would be one way to avoid the need to pass the context into the constructor.

Very clean & simple article to follow. I came from Spring background so had the dependency injection background but was not finding a good article in Android side which is so focused. So THANKS for taking time. Also seems few things changed in dagger and we may not need AppModule

protected AppComponent initDagger(DeezFoodzApplication application) {
return DaggerAppComponent.builder().presenterModule(new PresenterModule()).build();
}

We should add a reactive approach to this now :slight_smile: One concept at a time,

This tutorial is more than six months old so questions are no longer supported at the moment for it. We will update it as soon as possible. Thank you! :]