What we will be Learning?

Use dagger2 with Retrofit, OkHttp, Gson and RxJava and RxAndroid

with and and Use Model View Presenter(MVP) Architecture to decouple the Business logic and the underlying implementation of the logic to produce more cleaner code

Architecture to decouple the Business logic and the underlying implementation of the logic to produce more cleaner code Use RxJava to make request to our REST API

to make request to our Use Retrofit to make call to a API and display the result

Learn about dependent components in dagger and creating custom scope for dependent components

in dagger and creating for dependent components 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

This slideshow requires JavaScript.

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 root build.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

library dagger-compiler for code generation

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.

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

We will be creating three packages called data and mainscreen and util that we add the respective classes in these packages

and and that we add the respective classes in these packages We create two more packages inside dagger packages called as module and component

and We will create all the files related to our mainscreen in the mainscreen package (MainActivity MainScreenContract)

This is how my app structure looks

Step 4: Add Retrofit, OkHttp, Gson, RxJava 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' //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' //RxJava compile 'io.reactivex:rxjava:1.1.2' compile 'io.reactivex:rxandroid:1.1.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.1' //Dagger apt 'com.google.dagger:dagger-compiler:2.2' compile 'com.google.dagger:dagger:2.2' provided 'javax.annotation:jsr250-api:1.0' }

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 SharedPreferences providesSharedPreferences(Application application) { return PreferenceManager.getDefaultSharedPreferences(application); } @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) { Retrofit retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create(gson)) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(mBaseUrl) .client(okHttpClient) .build(); return retrofit; } }

Step 7: Create NetComponent Interface

We create an Interface called NetComponent with AppModule and NetModule as its modules

called NetComponent with AppModule and NetModule as its modules Note that we will be using this Component as a dependency for our MainScreenComponent so we need retrofit as a dependency. Hence we expose its return type so that when MainScreen injects in any of the activities or fragments the MainScreenComponent can find and Inject Retrofit from this Module(May be confusing , continue reading to understand how this works)

@Singleton @Component(modules = {AppModule.class, NetModule.class}) public interface NetComponent { // downstream components need these exposed with the return type // method name does not really matter Retrofit retrofit(); }

Step 8: Create a class App that extend Application

Create a class App , extend it from Application class

, 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://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

is a fake api that provides data Create a POJO class called Post with title and body as String variables

class called Post with title and body as String variables Also add getters and setters using Android Studio

public class Post { private final Integer userId; private final Integer id; private final String title; private final String body; public Post(Integer userId, Integer id, String title, String body) { this.userId = userId; this.id = id; this.title = title; this.body = body; } public Integer getUserId() { return userId; } public Integer getId() { return id; } public String getTitle() { return title; } public String getBody() { return body; } }

Step 9: In mainscreen package create an interface called MainScreenContract

This interface will have two more inner interface called View and Presenter

called and View interface holds all the methods which we will implement in our MainScreen View (i.e in our case MainActivity )

(i.e in our case ) Presenter interface has all the methods that we will implement in our MainScreenPresenter (i.e only one method loadPost() )

public interface MainScreenContract { interface View { void showPosts(List<Post> posts); void showError(String message); void showComplete(); } interface Presenter { void loadPost(); } }

Step 10: Create MainScreenModule and MainScreenComponent

The purpose of creating MainScreenModule is to provide the View ( in our case MainActivity) to our Presenter when it is injected. The Presenter uses this view as a reference to our MainAvtivity to call the methods in the View (showError(),showComplete()) whenever the network operation are performed

is to provide the ( in our case MainActivity) to our when it is injected. The Presenter uses this view as a to our to call the methods in the View whenever the network operation are performed It is a means through which the View and the Presenter Communicate with each other

with each other In Dagger, two dependent components cannot share the same scope i.e (Our NetComponent and MainScreenComponent cannot share the scope of @Singlton ). So we create a custom scope called @CustomeScope to be used by our MainScreenComponent and MainScreenModule

This is our MainScreenModule class

@Module public class MainScreenModule { private final MainScreenContract.View mView; public MainScreenModule(MainScreenContract.View mView) { this.mView = mView; } @Provides @CustomScope MainScreenContract.View providesMainScreenContractView() { return mView; } }

This is our MainScreenComponent

@CustomScope @Component(dependencies = NetComponent.class, modules = MainScreenModule.class) public interface MainScreenComponent { void inject(MainActivity activity); }

This is our CustomeScope interface in util package

@Documented @Scope @Retention(RetentionPolicy.RUNTIME) public @interface CustomScope { }

Step 9: Create MainPresenter which will implement the methods to make network calls(Your apps logic)

MainPresenter implements methods from MainScreenContract.Presenter

public class MainScreenPresenter implements MainScreenContract.Presenter { @Override public void loadPost() { } }

We create an interface called PostService that makes a GET request at /posts and get a Observable of List of Post objects as return type

private interface PostService { @GET("/posts") Observable<List<Post>> getPostList(); }

Our MainPresenter requires retrofit to make the network calls and the View to which it will display the results of the network calls. So we provide the Retrofit and View (MainActivity) by injecting them in the constructor .

requires retrofit to make the network calls and the View to which it will display the results of the network calls. So we provide the Retrofit and View (MainActivity) by . So whenever a new object of MainPresenter is created Dagger will inject the dependency.

of MainPresenter is created Dagger will inject the dependency. The retrofit dependency will be provided by NetComponent and the MainScreenContract.View dependency will be provided by the MainScreenComponent whenever we inject it in our Views(in our case we will inject it in MainActivity)

Retrofit retrofit; MainScreenContract.View mView; @Inject public MainScreenPresenter(Retrofit retrofit, MainScreenContract.View mView) { this.retrofit = retrofit; this.mView = mView; }

Now in our MainPresenter we implement the method loadPost() to make NetworkRequest using the retrofit object and PostService

to make NetworkRequest using the retrofit object and PostService As we will be using RxJava we get an Observable of a List of Post Objects

@Override public void loadPost() { retrofit.create(PostService.class).getPostList().subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .unsubscribeOn(Schedulers.io()) .subscribe(new Observer<List<Post>>() { @Override public void onCompleted() { mView.showComplete(); } @Override public void onError(Throwable e) { mView.showError(e.getMessage()); } @Override public void onNext(List<Post> posts) { mView.showPosts(posts); } }); }

RxJava has 3 methods for us

has 3 methods for us onNext() is called when we recieve the data

is called when we recieve the data onError() is called obviously when we some error occures

is called obviously when we some error occures onCompleted() is called when the network call is finished

is called when the network call is finished We use the reference object mView and pass the results to the View via this reference variable which was injected in the View (i.e MainActivity)

This is how our MainPresenter class should look after all this

public class MainScreenPresenter implements MainScreenContract.Presenter { Retrofit retrofit; MainScreenContract.View mView; @Inject public MainScreenPresenter(Retrofit retrofit, MainScreenContract.View mView) { this.retrofit = retrofit; this.mView = mView; } @Override public void loadPost() { retrofit.create(PostService.class).getPostList().subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .unsubscribeOn(Schedulers.io()) .subscribe(new Observer<List<Post>>() { @Override public void onCompleted() { mView.showComplete(); } @Override public void onError(Throwable e) { mView.showError(e.getMessage()); } @Override public void onNext(List<Post> posts) { mView.showPosts(posts); } }); } private interface PostService { @GET("/posts") Observable<List<Post>> getPostList(); } }

Step 10: Create a Listview in activity_main.xml to display the list we receive

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".mainscreen.MainActivity"> <ListView android:id="@+id/my_list" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>

Step 11: Implement MainScreenContract.View in our MainActivity

We implement the 3 methods in our MainActivity public class MainActivity extends AppCompatActivity implements MainScreenContract.View { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void showPosts(List<Post> posts) { } @Override public void showError(String message) { } @Override public void showComplete() { } }

We create the necessary variables to deal with the listview

ListView listView; ArrayList<String> list; ArrayAdapter<String> adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.my_list); list = new ArrayList<>(); }

We create a variable for our MainScreenPresenter and use @Inject annotation to inject it. We will use this variable to call the loadPost() method which is implemented in MainPresenter

@Inject MainScreenPresenter mainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.my_list); list = new ArrayList<>(); DaggerMainScreenComponent.builder() .netComponent(((App) getApplicationContext()).getNetComponent()) .mainScreenModule(new MainScreenModule(this)) .build().inject(this); //Call the method in MainPresenter to make Network Request mainPresenter.loadPost(); }

Now we write the logic inside the methods showPosts(List<Post> posts) , showError(String message) , showComplete()

, , These methods will be called by our MainPresenter using the mView reference whenever the Network calls are made and the results will be passed to our MainActivity

@Override public void showPosts(List<Post> posts) { //Loop through the posts and get the title of the post and add it to our list object for (int i = 0; i < posts.size(); i++) { list.add(posts.get(i).getTitle()); } //Create the array adapter and set it to list view adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, list); listView.setAdapter(adapter); } @Override public void showError(String message) { //Show error message Toast Toast.makeText(getApplicationContext(), "Error" + message, Toast.LENGTH_SHORT).show(); } @Override public void showComplete() { //Show completed message Toast Toast.makeText(getApplicationContext(), "Complete", Toast.LENGTH_SHORT).show(); }

This is how our MainActivity looks finaly

public class MainActivity extends AppCompatActivity implements MainScreenContract.View { ListView listView; ArrayList<String> list; ArrayAdapter<String> adapter; @Inject MainScreenPresenter mainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.my_list); list = new ArrayList<>(); DaggerMainScreenComponent.builder() .netComponent(((App) getApplicationContext()).getNetComponent()) .mainScreenModule(new MainScreenModule(this)) .build().inject(this); //Call the method in MainPresenter to make Network Request mainPresenter.loadPost(); } @Override public void showPosts(List<Post> posts) { //Loop through the posts and get the title of the post and add it to our list object for (int i = 0; i < posts.size(); i++) { list.add(posts.get(i).getTitle()); } //Create the array adapter and set it to list view adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, list); listView.setAdapter(adapter); } @Override public void showError(String message) { //Show error message Toast Toast.makeText(getApplicationContext(), "Error" + message, Toast.LENGTH_SHORT).show(); } @Override public void showComplete() { //Show completed message Toast Toast.makeText(getApplicationContext(), "Complete", Toast.LENGTH_SHORT).show(); } }

Final Output

Conclusion

We use dagger 2 along with retrofit, OkHttp and Gson and RxJava to make a request to a REST API and display the data in the ListView

We used MVP architecture to decouple our Application logic with the underlining implementation details

Pros : MVP is great and recommended for large code base, and promotes cleaner code

Cons: MVP is writing too much of code to get things done (lot of boiler plate)

Github link for code

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

Reference