Android retrofit mvvm dagger livedata rxjava

Android retrofit mvvm dagger livedata rxjava

This blog is all about implementing REST API in the Android app using Android retrofit mvvm dagger livedata rxjava, Android Architecture Components introduce by Google and Dagger 2 which make our code more clear and reusable and easy to modify if needed.

Most of the Android developer have a habit to write more than thousand line boilerplate code in single activity/fragment without using any design pattern. So its time to improve coding standard by using new API like RxJava, dagger and etc. that is already introduced for application building. So before using Retrofit(for rest API call), we should have known about what basically MVVM, Dagger, and RxJava are. The first question comes to our mind that what does mean and use of MVVM. So Let’s start with MVVM.

There are three parts of the Model-View-ViewModel architecture:

  1. Model is used to write Business logic. The model represents the actual data and/or information we are dealing with.
  2. View is used to consume data/result received from ViewModel and inform ViewModel of user interaction.In simple way, we can say that it is used to display data to user.
  3. ViewModel works as a bridge between Model and View. It is responsible to process data using Model and send back the result to View to consume it. It contains UI Logic that involving both View and Model. A ViewModel is retained as long as the scope of its Activity/Fragment is alive, including when the Activity/Fragmentis destroyed and recreated due to a configuration change; This allows ViewModel to make UI data available to the recreated activity or fragment instance. Wrapping UI data stored within the ViewModel with LiveData provides the data an observable lifecycle-aware home.

You can see MVVM app archeture flow from attached image on top.

Now start building an app using this.A quick look at the Gradle of the app.

dependencies { implementation fileTree(dir: ‘libs’, include: [‘*.jar’]) implementation ‘com.android.support:appcompat-v7:27.1.1’ implementation ‘com.android.support.constraint:constraint-layout:1.1.0’ testImplementation ‘junit:junit:4.12’ androidTestImplementation ‘com.android.support.test:runner:1.0.2’ androidTestImplementation ‘com.android.support.test.espresso:espresso-core:3.0.2’implementation ‘com.jakewharton:butterknife:8.8.1’ annotationProcessor ‘com.jakewharton:butterknife-compiler:8.8.1’/* dagger dependency for DI*/ implementation “com.google.dagger:dagger:2.13” annotationProcessor “com.google.dagger:dagger-compiler:2.13” compileOnly ‘javax.annotation:jsr250-api:1.0’ implementation ‘javax.inject:javax.inject:1’/*Retrofit lib*/ implementation ‘com.squareup.retrofit2:retrofit:2.3.0’ implementation ‘com.squareup.retrofit2:converter-gson:2.3.0’/*RxJava lib*/ implementation ‘io.reactivex.rxjava2:rxandroid:2.0.1’ implementation “io.reactivex.rxjava2:rxjava:2.1.8” implementation ‘com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0’/* LiveData lib*/ implementation “android.arch.lifecycle:extensions:1.1.1” implementation “android.arch.lifecycle:runtime:1.1.1” annotationProcessor “android.arch.lifecycle:compiler:1.1.1”}

View 
Here We use LoginActivity as View which subscribe to receive basically three event while intracting with ViewModel.
1. Start rest api intraction
2. Get result from rest api
3. Get any kind of error while process

public class LoginActivity extends AppCompatActivity {@Inject ViewModelFactory viewModelFactory;@BindView(R.id.phone_no) EditText phoneNo;@BindView(R.id.password) EditText password;LoginViewModel viewModel;ProgressDialog progressDialog;@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.login_activity); progressDialog = Constant.getProgressDialog(this, “Please wait…”);ButterKnife.bind(this); ((MyApplication) getApplication()).getAppComponent().doInjection(this);viewModel = ViewModelProviders.of(this, viewModelFactory).get(LoginViewModel.class);viewModel.loginResponse().observe(this, new Observer() { @Override public void onChanged(@Nullable ApiResponse apiResponse) { consumeResponse(apiResponse); } }); } @OnClick(R.id.login) void onLoginClicked() { if (isValid()) { if (!Constant.checkInternetConnection(this)) { Toast.makeText(LoginActivity.this,getResources().getString(R.string.errorString), Toast.LENGTH_SHORT).show(); } else { viewModel.hitLoginApi(phoneNo.getText().toString(), password.getText().toString()); }} }/* * method to validate $(mobile number) and $(password) * */ private boolean isValid() {if (phoneNo.getText().toString().trim().isEmpty()) { Toast.makeText(LoginActivity.this,getResources().getString(R.string.enter_valid_mobile), Toast.LENGTH_SHORT).show(); return false; } else if (password.getText().toString().trim().isEmpty()) { Toast.makeText(LoginActivity.this,getResources().getString(R.string.enter_valid_password), Toast.LENGTH_SHORT).show(); return false; }return true; } }

We can see here the main purpose of LoginActivity is to call rest API and consume its response. Now you can see a lot of interesting thing in this code such as annotation like @Inject, @BindView and ViewModelFactory and LoginViewModel etc. so don’t get bored or panic I will explain it properly one by one before going forward in code.

First thing lets see about @Inject this annotation is used for injecting object, now an interesting point injecting of the object comes to mind what that means.So That means you create the object once and reuse it throughout your application where required and in this by just inject that object, there is a lot of way of dependency injection but here we will use Dagger API.

I used here dagger:2.13, you can learn more from this article about dagger.

See how we will use the dagger in our application. Look at UtilsModule.java and AppModule.java classes.

@Module public class UtilsModule {@Provides @Singleton Gson provideGson() { GsonBuilder builder = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); return builder.setLenient().create(); }@Provides @Singleton Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {Retrofit retrofit = new Retrofit.Builder() .baseUrl(Urls.BASE_URL) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create(gson)) .build();return retrofit; }@Provides @Singleton ApiCallInterface getApiCallInterface(Retrofit retrofit) { return retrofit.create(ApiCallInterface.class); }@Provides @Singleton OkHttpClient getRequestHeader() {OkHttpClient.Builder httpClient = new OkHttpClient.Builder();httpClient.addInterceptor(chain -> { Request original = chain.request(); Request request = original.newBuilder().build(); return chain.proceed(request); }) .connectTimeout(100, TimeUnit.SECONDS) .writeTimeout(100, TimeUnit.SECONDS) .readTimeout(300, TimeUnit.SECONDS);OkHttpClient client = httpClient.build(); return client; }@Provides @Singleton Repository getRepository(ApiCallInterface apiCallInterface) { return new Repository(apiCallInterface); }@Provides @Singleton ViewModelProvider.Factory getViewModelFactory(Repository myRepository) { return new ViewModelFactory(myRepository); } }@Module public class AppModule { private Context context;public AppModule(Context context) { this.context = context; }@Provides @Singleton Context provideContext() { return context; } }

You have to create a module class using annotation @Module which will create objects by using @Provides and @Singleton annotation. I created here few objects what is needed for this project. For consuming rest API you need to have the retrofit object so I create here Retrofit object and we will inject it wherever it needed like “@Inject Retrofit retrofit;”.

Now look at the ViewModelFactory class.

public class ViewModelFactory implements ViewModelProvider.Factory {private Repository repository;@Inject public ViewModelFactory(Repository repository) { this.repository = repository; }@NonNull @Override public T create(@NonNull Class modelClass) { if (modelClass.isAssignableFrom(LoginViewModel.class)) { return (T) new LoginViewModel(repository); } throw new IllegalArgumentException(“Unknown class name”); } }

Repository class is injected here and it passes into LoginViewModel constructor for its further use, so we will save our time of making Repository class object in LoginViewModel which is actually a ViewModel, this class used repository object for implementing business logic. Now let’s have a look at LoginViewModel and Repository classes.

First, see LoginViewModel which is used as ViewModel for LoginActivity.

public class LoginViewModel extends ViewModel {private Repository repository; private final CompositeDisposable disposables = new CompositeDisposable(); private final MutableLiveData responseLiveData = new MutableLiveData<>();public LoginViewModel(Repository repository) { this.repository = repository; }public MutableLiveData loginResponse() { return responseLiveData; }/* * method to call normal login api with $(mobileNumber + password) * */ public void hitLoginApi(String mobileNumber, String password) {disposables.add(repository.executeLogin(mobileNumber, password) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe((d) -> responseLiveData.setValue(ApiResponse.loading())) .subscribe( result -> responseLiveData.setValue(ApiResponse.success(result)), throwable -> responseLiveData.setValue(ApiResponse.error(throwable)) )); }@Override protected void onCleared() { disposables.clear(); } } view rawLoginViewModel.java

Here we go with a lot of new amazing things like CompositeDisposable, MutableLiveData etc. Don’t get panic I will explain it what purpose of these object. First, see in above class that is extended by ViewModel which has some its callback function like onCleared().

ViewModel is part of MVVM design pattern which we have already discussed in starting. But few interesting things about it is that ViewModel class is designed to store and manage UI related data in a lifecycle conscious way. It allows data to survive even in the configuration change.

If the system recreated UI, for example, you rotate your screen then activity get recreated in such case before ViewModel concept you generally used to use onSaveInstanceState() and restore its data by using bundle in onCreate() this process was suitable for small amount of data that you can easily be serialized and deserialized, another problem that supposes you make an asynchronous call that is taking some time to return data then UI controller needs to manage these call and ensure the system cleans them up after it’s destroyed to avoid memory leaks. To handle all these problems you can easily use ViewModel which is lifecycle aware and it will manage this kind of UI related problem.

Now comes to code again here we used CompositeDisposable which is a concept of RxJava.

I made REST API call using RxJava instead of any thread or async task. So let’s discuss few things about RxJava.
What is RxJava?
“RxJava is a Java VM implementation of Reactive Extensions. It has become the single most important skill for Android development.”

RxJava works on Observer pattern. It has basically three major component.
1.Observable
2.Subscriber
3.Observer
 
To understand it in better way go to this “link”.

In our code we used subscribe() this means where we want to subscribe process generally we use IO thread by using Schedulers.io(), the second function is observeOn() which indicate where user wanted to consume data comes from observable and where we want to consume it in our case we use MainThread by using AndroidSchedulers.mainThread().
We use CompositeDisposable to add each subscription and clear this inside onCleared() callback of ViewModel.
Now comes to MutableLiveData, before understanding MutableLiveData first let’s have a look of LiveData.

What is LiveData?
LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state. For More information go to this “article” or “this.

The advantages of using LiveData
1
 .Ensures your UI matches your data state.
2.
 No memory leaks.
3.
 No crashes due to stopped activities.
4.
 No more manual lifecycle handling.
5.
 Sharing resources.

LiveData has no publicly available methods to update the stored data. So basically we need MutableLiveData.
The MutableLiveData class exposes the setValue(T)and postValue(T)methods publicly and you must use these if you need to edit the value stored in a MutableLiveData object. Usually, MutableLiveData is used in the ViewModel and then the ViewModel only exposes immutable MutableLiveData objects to the observers. We are setting value in MutableLiveData object like:

Now its time to move further in code, we used Repository class here you can see the implementation of this class here.

public class Repository {private ApiCallInterface apiCallInterface;public Repository(ApiCallInterface apiCallInterface) { this.apiCallInterface = apiCallInterface; }/* * method to call login api * */ public Observable executeLogin(String mobileNumber, String password) { return apiCallInterface.login(mobileNumber, password); }} view rawRepository.java

In this class, we are using the ApiCallInterface object which is used to call REST API. ApiCallInterface is created in UtilsModule.

and we are passing ApiCalInterface object in repository class using same UtilsModule class.

Now I hope it would be more clear now so comes to next implementation.
Here we use ApiCallInterface which is basically class which includes the function to hit REST API using Retrofit. You can see its implementation here.

public interface ApiCallInterface {@FormUrlEncoded @POST(Urls.LOGIN) Observable login(@Field(“mobile”) String mobileNumber, @Field(“password”) String password); } view rawApiCallInterface.java

and Urls.java is:

public class Urls { public static final String BASE_URL = “http://xyz/”;//put your base url herepublic static final String LOGIN = “abc”;//put your end point here} view rawUrls.java

Here BASE_URL which is use while creating retrofit object in UtilsModule.
Urls.LOGIN is your endpoint.

Now most important class is used for data transfer is ApiResponse.java

public class ApiResponse {public final Status status;@Nullable public final JsonElement data;@Nullable public final Throwable error;private ApiResponse(Status status, @Nullable JsonElement data, @Nullable Throwable error) { this.status = status; this.data = data; this.error = error; }public static ApiResponse loading() { return new ApiResponse(LOADING, null, null); }public static ApiResponse success(@NonNull JsonElement data) { return new ApiResponse(SUCCESS, data, null); }public static ApiResponse error(@NonNull Throwable error) { return new ApiResponse(ERROR, null, error); }} view rawApiResponse.java hosted with ❤ by GitHub

and Status class is nothing but enum class. It is use just for status of response.

public enum Status { LOADING, SUCCESS, ERROR, COMPLETED } view rawStatus.java

Now come to the LoginActivity.java class again which is our View as we discussed this activity at the starting.

First see this code here we bind this activity with AppComponent for using injecting object defined in UtilsModule.java class.
AppComponent interface is :

@Component(modules = {AppModule.class, UtilsModule.class}) @Singleton public interface AppComponent {void doInjection(LoginActivity loginActivity);} view rawAppComponent.java

AppComponet interface work here as a bridge between Modules and our activity. It comes under dagger concept.

To implement Dagger we have to bind AppComponent with the application here we use application class to achieve this.

public class MyApplication extends Application { AppComponent appComponent; Context context;@Override public void onCreate() { super.onCreate(); context = this; appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).utilsModule(new UtilsModule()).build(); }public AppComponent getAppComponent() { return appComponent; }@Override protected void attachBaseContext(Context context) { super.attachBaseContext(context); } } view rawMyApplication.java

To create appComponent object we have to use code written in onCreate() 
appComponent DaggerAppComponent.builder().appModule(new AppModule(this)).utilsModule(new UtilsModule()).build();
For this You have to just add Dagger in name before your component class like DaggerAppComponent and after this just build the project to remove error like “can not resolve” at DaggerAppComponent. For more information read “dagger article ”.

After these things let’s look at the remaining point of LoginActivity.

In the above code, we have created an object of LoginViewModel using viewModelFactory object and we call loginResponse() function of our viewmodel class and observe it because return type of loginResponse() function is of type MutableLiveData, so whenever we make any changes in MutableLiveData object by using setValue() or postValue() function will onChanged() function will always be called.In this function we will consume response coming from apiResponse. Here consumeResponse function is:

Here we can get three type of response either Loading , success or error.We manage our UI according to this and consume its data in case of success and parse JsonElement response in my case using Gson.

That was all about this article, you can refer these article for more knowledge.
1. https://medium.com/google-developers/lifecycle-aware-data-loading-with-android-architecture-components-f95484159de4
2. https://medium.com/mindorks/tagged/rxjava
3. https://medium.com/@kurtisnusbaum/rxandroid-basics-part-1-c0d5edcf6850
4. https://developer.android.com/topic/libraries/architecture/livedata
5.https://medium.com/upday-devs/android-architecture-patterns-part-3-model-view-viewmodel-e7eeee76b73b 
6.http://square.github.io/retrofit/

Do find the full source code from here:
https://github.com/saquib3705/MVVMWithDaggerAndRxJavaAndroid.git

(Visited 774 times, 6 visits today)

You May Also Like

About the Author: Android Developer

This is Mohammad I am Android Application Developer. I am the founder of Android Tutorial Online blog. I am programming lover and professional blogger from India. I spend most of my time doing programming and helping other programmers. This Android tutorial online blog for learning and share Android code.
My Chatbot
Powered by Replace Me