Dagger 2 with Retrofit and OkHttp and Gson

What we will be Learning?

  • Use dagger2 with Retrofit and OkHttp and Gson
  • Inject dependency using @Inject  annotation to the Variables
  • Use Retrofit to make call to a API and display the result
  • We will be using Android studio and the code will be hosted on github

Lets get started

Step 1: Create a project with a Blank Activity

Screenshot (3).png

Step 2: Add the necessary dependency

Android Studio by default will not recognize a lot of generated Dagger 2 code as legitimate classes, but adding the android-apt plugin will add these files into the IDE class path and enable you to have more visibility. Add this line to your rootbuild.gradle:

dependencies {
     // other classpath definitions here
     classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
 }

Then make sure to apply the plugin in your app/build.gradle:

// add after applying plugin: 'com.android.application'  
apply plugin: 'com.neenbedankt.android-apt'

Add these three lines to your app/build.gradle file after this apply statement:

dependencies {
    // apt command comes from the android-apt plugin
    apt 'com.google.dagger:dagger-compiler:2.2'
    compile 'com.google.dagger:dagger:2.2'
    provided 'javax.annotation:jsr250-api:1.0'
}

In dependencies I added:

  • dagger library
  • dagger-compiler for code generation
  • javax.annotation for additional annotations required outside Dagger

After updating Dagger’s configuration, you can synchronize the project with the gradle files by clicking the button at the top.

dagger-2-gradle-sync.jpg

Step 3: Create packages to architecture our app in a clean way

  • We will be creating two packages called dagger and ui so that we add the respective classes in these packages
  • We will put all the user interface related classes such as MainActivity in the ui package
  • Further we create two more packages inside dagger packages called as module and component

This is how my app structure looks

2016-05-09_13h59_55.png

Step 4: Add Retrofit, OkHttp, Gson libraries to your app/gradle file

 

This is how my build.gradle file looks after i add the dependency

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'

    //Dagger
    apt 'com.google.dagger:dagger-compiler:2.2'
    compile 'com.google.dagger:dagger:2.2'
    provided 'javax.annotation:jsr250-api:1.0'

    //Retrofit
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    
    //OkHttp
    compile 'com.squareup.okhttp3:okhttp:3.2.0'
    compile 'com.squareup.okio:okio:1.7.0'

    //Gson
    compile 'com.google.code.gson:gson:2.6.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.1'
}

Also add INTERNET permission to your manifest

<uses-permission android:name="android.permission.INTERNET" />

Step 5: Create an AppModule that will provide context to other modules

  • Now because Retrofit and OkHttp will be used through the application we will created an AppModule that will be instantiated when the Application starts so that the app context is provided to Retrofit and OkHttp library
@Module
public class AppModule {
    Application mApplication;

    public AppModule(Application mApplication) {
        this.mApplication = mApplication;
    }

    @Provides
    @Singleton
    Application provideApplication() {
        return mApplication;
    }
}

Step 6: Create a NetModule that will provide Retrofit and OkHttp

@Module
public class NetModule {
    String mBaseUrl;

    public NetModule(String mBaseUrl) {
        this.mBaseUrl = mBaseUrl;
    }


    @Provides
    @Singleton
    Cache provideHttpCache(Application application) {
        int cacheSize = 10 * 1024 * 1024;
        Cache cache = new Cache(application.getCacheDir(), cacheSize);
        return cache;
    }

    @Provides
    @Singleton
    Gson provideGson() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
        return gsonBuilder.create();
    }

    @Provides
    @Singleton
    OkHttpClient provideOkhttpClient(Cache cache) {
        OkHttpClient.Builder client = new OkHttpClient.Builder();
        client.cache(cache);
        return client.build();
    }

    @Provides
    @Singleton
    Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
        return new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .baseUrl(mBaseUrl)
                .client(okHttpClient)
                .build();
    }
}

Step 7: Create NetComponent Interface

  • We create an Interface called NetComponent with AppModule and NetModule as its modules
  • We create a method called inject and pass activity in which we will require retrofit in our case we will be calling it only from MainActivity.(You can add other Activity or Fragments)
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface NetComponent {
    void inject(MainActivity activity);
}

Step 8: Create a class App that extend Application

  • Create a class App, extend it from Application class
  • Override onCreate method
public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
    }
}
  • Because we are overriding the default Application class, we also modify the application name to launch App. This way your application will use this application class to handle the initial instantiation.
<application
      android:allowBackup="true"
      android:name=".App">
  • Create a private variable of type NetComponent and in onCreate build the NetComponent
  • Create a public method called getNetComponent() that will return the netcomponent variable whenever we require this in our App
public class App extends Application {

    private NetComponent mNetComponent;

    @Override
    public void onCreate() {
        super.onCreate();

        mNetComponent = DaggerNetComponent.builder()
             .appModule(new AppModule(this))
             .netModule(new NetModule("http://www.jsonplaceholder.typicode.com/"))
             .build();
    }

    public NetComponent getNetComponent() {
        return mNetComponent;
    }
}

Make sure to rebuild the project (in Android Studio, select Build > Rebuild Project) if you cannot reference the Dagger component.

Step 8: Create a POJO class and interface to make GET request to a REST API

  • http://www.jsonplaceholder.typicode.com is a fake REST api that provides JSON data
  • Create a POJO class called Post with title and body as String variables
  • Also add getters and setters using Android Studio
public class Post {
    String title;
    String body;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}
  • Create an interface called Restapi that makes a GET request at /posts and get a List of  Post objects as return type
public interface Restapi {

    @GET("/posts")
    Call<List<Post>> getPosts();
}

Step 9: In MainActivity inject the retrofit dependency

  • The inject method will look for any variables annotated with @Inject and will provide dependency if there is any @Provides method that returns the same type
public class MainActivity extends AppCompatActivity {

    @Inject
    Retrofit retrofit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((App) getApplication()).getNetComponent().inject(this);
    }

}

Step 10: Make request using the Retrofit Object

public class MainActivity extends AppCompatActivity {

    @Inject
    Retrofit retrofit;
    TextView textView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((App) getApplication()).getNetComponent().inject(this);

        //Create textview and findViewByID
        textView = (TextView) findViewById(R.id.textview_post);
        //Create a retrofit call object
        Call<List<Post>> posts = retrofit.create(Restapi.class).getPosts();

        //Enque the call
        posts.enqueue(new Callback<List<Post>>() {
            @Override
            public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
               //Set the response to the textview
                textView.setText(response.body().get(0).getBody());

            }

            @Override
            public void onFailure(Call<List<Post>> call, Throwable t) {
                //Set the error to the textview
                textView.setText(t.toString());
            }
        });
    }
}

Final Output

Screenshot_2016-05-09-16-24-02.png

Conclusion

  • We use dagger 2 along with retrofit, OkHttp and Gson to make a request to a REST API and display the data in the textview.
  • We can see how dagger improves the architecture of the android application in making our code mode modular and clean

Github link for code

https://github.com/LadwaAditya/DaggerRetrofitOkhttp-Tutorial

 Reference

 

Advertisements

18 thoughts on “Dagger 2 with Retrofit and OkHttp and Gson

  1. if i have to explicitelly call

    ((App) getApplication()).getNetComponent().inject(this);

    what’s the point of “injecting” in this case? might as well have a default factory method there 😦

    Like

    1. If that works for your you can do that implicitly . For the sake of the tutorial I used it so i can inject in my MainActivity

      Like

  2. Thank you for this excellent tutorial. There was two little URL problems for me that needed to be fixed.

    The first is with the sample JSON baseUrl: http://www.jsonplaceholder.typicode.com/. I had to drop the “www.” or else I get an unresolved host exception from Retrofit.

    The second is with the trailing ‘/’ at the end of the baseUrl. When “/posts” gets appended, it ends up making the URL http://www.jsonplaceholder.typicode.com//posts which also fails. Either drop the / at the end of the baseUrl or at the beginning of /posts.

    Thanks for taking the time to share this with us! It’s really useful.

    Like

  3. Imagine that mBaseUrl, it’s dynamic. For example first Activy, gets the dynamic mBaseUrl, and then I populate, that url in a POJO.
    The second Activiy now calls the NetComponent:
    ((App) getApplication()).getNetComponent().inject(this);
    My problem is that when a device has a low memory, or it’s an old device, with Android 4.1, in some moment the Garbage Collector, cleans to null that POJO, and the app crash, becaus pojo.baseUrl = null.
    Any idea how to avoid this?

    @Provides
    @Singleton
    Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient, Pojo pojo) {
    return new Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create(gson))
    .baseUrl(mBaseUrl) ——-> subsitute mBaseUrl by pojo.baseUrl
    .client(okHttpClient)
    .build();

    Like

  4. I think you don’t need to compile these two:

    compile ‘com.squareup.okio:okio:1.7.0’
    compile ‘com.google.code.gson:gson:2.6.2’

    Because OkHttp sits on top of okio and retrofit2:converter-gson already includes gson.

    Like

    1. ‘com.neenbedankt.gradle.plugins:android-apt:1.8’ is also unnecessary since you can use annotationProcessor since the new gradle plugin 3.0 i think.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s