cft

How to use dagger with retrofit and get rid of initialization!

If you’re an android developer and want to learn dagger but can’t find a good resource because all of ’em are too confusing then hey! stay calm I’m here to take you in dagger from zero to hero. After reading this article you’ll;


user

Shivam Bhasin

2 years ago | 7 min read

Hello and welcome!

If you’re an android developer and want to learn dagger but can’t find a good resource because all of ’em are too confusing then hey! stay calm I’m here to take you in dagger from zero to hero. After reading this article you’ll;

  1. Know the basics of dagger and how to set up a basic network module which you can use to make network calls in your app

2. Know about different annotations like module, provides and inject

3. Finally know how to make use of the module that we’ll be creating

4. Know about simple data model classes in kotlin(Bonus)

I’ll be using Retrofit and Rx java for creating Api service. If you don’t know how to use them yet then don’t worry, I’ll explain their usage separately

Enough with the introduction. Let’s start! I hope you’re ready with a new android project with just main activity. If not, then please create a new project with a simple activity.

1. Create module and set up dependencies

  • After creating you project first of all create a new module by going to File->New->New Module. You’ll see a popup window to select module type. Select Android library and click next to configure your library. Name you library networklibrary. Package name defaults to your app module but is editable. Select preferred language(Java or kotlin) and minimum SDK version and click finish.
  • This will create a module and a build.gradle file for your networklibrary under Gradle scripts (See the image below).
  • Add the following under dependencies section in your build.gradle file for network library.

dependencies {

//other dependencies

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

implementation 'io.reactivex:rxandroid:1.2.1' //

implementation 'io.reactivex:rxjava:1.3.0'

implementation "com.squareup.retrofit2:adapter-rxjava:2.4.0"

implementation 'com.google.code.gson:gson:2.8.6'

implementation 'com.squareup.okhttp3:logging-interceptor:4.2.1'

implementation 'com.squareup.retrofit2:converter-gson:2.4.0'

implementation 'com.google.dagger:dagger-android:2.20'

kapt 'com.google.dagger:dagger-android-processor:2.20'

kapt 'com.google.dagger:dagger-compiler:2.23.2'

implementation "com.airbnb.android:lottie:3.4.0"

}

  • Add the following dependencies to your app build.gradle file

dependencies

{

//other dependencies

implementation 'com.google.dagger:dagger:2.27'

implementation 'com.google.code.gson:gson:2.8.6'

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

implementation 'com.google.dagger:dagger-android:2.20'

kapt 'com.google.dagger:dagger-android-processor:2.20'

kapt 'com.google.dagger:dagger-compiler:2.23.2'

implementation project(":networklibrary") //<-- Name of your lib

implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'

implementation 'io.reactivex.rxjava3:rxjava:3.0.4'

}

  • Also make sure you have applied kotlin kapt plugin at the very top of your build.gradle files (app and networklibrary both)

apply plugin: 'com.android.library'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

apply plugin: 'kotlin-kapt' // <-- Important

2. Start coding!

Do all this inside your networklibrary

  • Create a file ApiService.kt in a new package “api” (in your networklibrary of course). Paste the following code in it. This is a simple retrofit service interface which allows us to do post and get api calls with different urls.

Please note that these functions return Observable object. As we’ll be using rxjava to subscribe and observe these methods later. You can use Call objects also with this but if you’re new to rxjava. Don’t worry I’ve your back!

  • We’ll be using a ApiManager to talk to our service and a ApiManagerListener which can be implemented by the class using our api and get onSuccess and onFailure methods. You also need a Base model which can be implemented by all our other data class models. (This will get clear later)

ApiManagerListener.kt

package io.shivamvk.networklibrary.api

interface ApiManagerListener {

fun onSuccess(dataModel: BaseModel?, response: String)

fun onFailure(dataModel: BaseModel?, e: Throwable) {}

}

BaseModel.kt

package io.shivamvk.networklibrary.models

import java.io.Serializable

interface BaseModel : Serializable

  • Also create a file PreferncesHelper.kt and paste the following code in it. This is a simple shared prefs class that can be used simply as prefs[] to get and set values.
  • In your network library under the default package create a class NetworkModule. Now what is a module? I got this from developer.google official site “A Dagger module is a class that is annotated with @Module. There, you can define dependencies with the @Provides annotation.” You can think of it as the main file in your library. Now what does your library intend to do? It is supposed to provide the instances of common classes.
  • You can paste the following code in the NetworkModule class. Take a deep breadth, everything will make sense soon.

Annotating your class with @Module informs dagger to use this class to provide instances. Now there is something common in all the functions in the class. They all have @Singleton and @Provides annotation with them. (Name of the function can be anything but it’s just a convention to start with provide).

Provides annotation is supposed to tell dagger to inject the returned instance wherever needed. Singleton makes sure to have only one instance throughout the application. Also, our class takes context as a constructor param and I’ll show you how to pass it in the next section.

As a complete newbie learning dagger, I used to search the whole articles or sometimes go through the whole videos to see where are these functions called. But the truth is they aren’t (At least by us). These are called internally by dagger and I’ll show you how to use them later. Now if you’ll look closely these functions also receive parameters and now you must wonder how does dagger know what to pass without me telling. Confused? Now I want you to look more closely to the return types and parameters of the methods of Network Module class. Noticed something? All the parameters that are required in the functions are provided by some other function in the same class. For example: providesRetrofit method receives a okHttpClient Object which is provided by providesOkhttpClient method which itself receives a interceptor object which is then provided by provideInterceptors method. Can you see the chain now?

Now move to your app module

  • What are components? Dagger can create a graph of the dependencies in your project that it can use to find out where it should get those dependencies when they are needed. To make Dagger do this, you need to create an interface and annotate it with @Component. Dagger creates a container as you would have done with manual dependency injection.
  • Create a file AppComponent inside a new package di and paste the following code in it.
  • Now is the time to initialize our NetworkModule class from networklibrary. But where? Create a class inside di package preferably with the name of your application like MyApplication.kt(EcommVendor in my case). Extend Application class and initialize your dagger inside the onCreate method. Here we’re initializing our network module class with the application context. We also have a getDeps method that returns the AppComponent instance which is built using DaggerAppComponent.

Please note the the DaggerAppComponent class is generated automatically by Dagger. The name of the class starts with dagger and ends with our component file name. Like Dagger<Your Component>, AppComponent in our case so DaggerAppComponent

  • One last thing before you actually use all this setup . Set name of your application to the class you just created above in manifest file like below. Note that it is the relative path to the application class. If you’re following the article this will be inside di package.

<application

android:name=".di.<ClassName>" //like ".di.EcommVendor"

// other tags

3. How to use

  • That was all for the setup of dagger. Do you think it’s too much? Well now you will see that how easy and efficient it is to use your api service with all that hard work for setup.
  • In your MainActivity’s onCreate() method call the getDeps() method by casting your application as the class you created in di package (EcommVendor in my case). Now if you remember this will return a AppComponent instance which provides a inject method.

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

(

application

as EcommVendor).getDeps().inject(this)

binding = DataBindingUtil

.setContentView(this, R.layout.

activity_main

)

}

  • Or in your fragments like this. But make sure add fun inject() in the app component interface with the calling fragment

override fun onCreateView(

inflater: LayoutInflater,

container: ViewGroup?,

savedInstanceState: Bundle?

): View? {

(

activity

!!.

application

as EcommVendor).getDeps().inject(this)

binding = DataBindingUtil

.inflate(

inflater,

R.layout.

fragment_orders

,

container, false

)

return binding.

root

}

  • Now after you’ve injected your activities/fragments you can simply use api service and prefrences like this. You don’t need to initialize them! They are already injected by dagger magically and you can use them as it is. Thanks to the @inject annotation.

Remember our network module class? There was a method provideApi which is returning the ApiService instance and a providePrefs method which returns SharedPreferences. It is because of them that we’re able to inject these. You can inject any instance just make sure it is returned from any method from the network module class

@Inject lateinit var apiService: ApiService

@Inject lateinit var prefs: SharedPreferences

  • You can use your ApiManager class now to make network calls like below. The api service instance to the view model by the fragment class and trust me i didn’t initialize it. You can also call it directly from your activity or fragments, just make sure to implement ApiManagerListener.

4. Data classes to create models(Bonus)

  • A simple user model looks like this in kotlin. Note that the class implements BaseModel.

I’ve created a package in networklibrary “models” for all models. I prefer it that that way but it’s totally up to you to decide their location

That’s it! Now you’re able to create a module and methods in it to create singleton instances of your service and preferences or anything you need? Try it out! For any doubts leave a comment below.

I’ve recently started writing articles on medium . Leave a comment with your feedback ^_^

Upvote


user
Created by

Shivam Bhasin

Simplifying things since childhood. Writes about JavaScript, application development, and self-help.


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles