<p>This post is about how to build an Android app using RxJava, RxAndroid, Retrofit with MVVM pattern in Kotlin.</p> 
 
 
 
<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex"> 
<div class="wp-block-button aligncenter"><a class="wp-block-button__link has-background" style="background-color: #20057a;" href="https://github.com/arunk7839/MovieAppRxJavaRetrofit"><strong>DOWNLOAD CODE</strong></a></div> 
</div> 
 
 
 
<h4> </h4> 
<h4><strong><span style="color: #000080;">RxJava</span></strong></h4> 
<p>RxJava is a Java implementation of <strong><span style="color: #000080;"><a style="color: #000080;" href="https://reactivex.io/">Reactive Extension or ReactiveX</a></span></strong>. Basically, it’s a library that composes asynchronous events by following Observer Pattern.</p> 
<p>The library offers a wide range of amazing operators like map, combine, merge, filter, and a lot more that can be applied to the data.</p> 
<p>RxJava is all about two key components: Observable and Observer. In addition to these, there are other things like Schedulers, Operators, and Subscription.</p> 
<ul> 
<li><strong><span style="color: #0000ff;">Observable</span></strong>: Observable is a data stream that does some work and emits data.</li> 
<li><strong><span style="color: #0000ff;">Observer</span></strong>: Observer receives the data emitted by Observable.</li> 
<li><strong><span style="color: #0000ff;">Subscription</span></strong>: The bonding between Observable and Observer is called a Subscription. There can be multiple Observers subscribed to a single Observable.</li> 
<li><span style="color: #0000ff;"><strong>Operator</strong></span>: Operators modify the data emitted by Observable before an observer receives them.</li> 
<li><strong><span style="color: #0000ff;">Schedulers</span></strong>: Schedulers decides the thread on which Observable should emit the data and on which Observer should receive the data i.e background thread, main thread, etc.,</li> 
</ul> 
<h4><strong><span style="color: #000080;">RxAndroid</span></strong></h4> 
<p>RxAndroid is an extension of RxJava for Android which is used only in Android applications.</p> 
<p><strong><span style="color: #008000;">Schedulers</span></strong> are introduced in RxAndroid which plays a major role in supporting the multithreading concepts in android applications. Schedulers basically decide the thread on which a particular code runs whether on a background thread or main thread. </p> 
<p>Even though there are a lot of Schedulers available, The below two Schedulers are extensively used in android programming. </p> 
<ul> 
<li><span style="color: #0000ff;"><strong>Schedulers.io()</strong></span>: This is used to perform operations like making network calls, reading disc/files, database operations, etc., This maintains a pool of threads.</li> 
<li><strong><span style="color: #0000ff;">AndroidSchedulers.mainThread()</span></strong>: this provides us access to the main thread of the application to perform actions like updating the UI. We shouldn’t perform any intensive operations on this thread as ANR dialog can be thrown.</li> 
</ul> 
 
 
 
<h4><span style="color: #000080;"><strong>Creating new project</strong></span></h4> 
<p>1 . Create a new project by going to <span style="color: #008000;"><strong>File ⇒ New Android Project</strong>,</span> select <span style="color: #008000;"><strong>Empty</strong></span> Activity, provide <span style="color: #008000;"><strong>app</strong></span> name, select language to <span style="color: #008000;"><strong>kotlin</strong></span> and then finally click on <span style="color: #0000ff;"><strong>finish</strong></span>.</p> 
<p>2 . Open app-level build.gradle file and add the below changes:</p> 
<ul> 
<li>Add the below libraries under the <span style="color: #0000ff;"><strong>dependencies</strong></span> section<strong>:</strong></li> 
</ul> 
<pre>dependencies {<br /><strong><span style="color: #008000;"> //ViewModel and livedata</span></strong><br /> implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"<br /> <br /><strong><span style="color: #008000;"> //Retrofit</span></strong><br /> implementation 'com.squareup.retrofit2:retrofit:2.9.0'<br /> implementation 'com.squareup.retrofit2:converter-gson:2.9.0'<br /> implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'<br /><br /><strong><span style="color: #008000;"> //Glide</span></strong><br /> implementation 'com.github.bumptech.glide:glide:4.12.0'<br /> implementation 'com.github.bumptech.glide:compiler:4.12.0'<br /><br /><strong><span style="color: #008000;"> // RxJava3 </span></strong><br /> implementation 'io.reactivex.rxjava3:rxjava:3.1.3'<br /><br /><strong><span style="color: #008000;"> //RxAndroid</span></strong><br /> implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'<br />}</pre> 
<p><span style="color: #000080;"><b class="graf--bold">Note:</b> </span>While using RxAndroid in our project we still add the dependency of RxJava to work,the reason is, there might be a chance that RxAndroid doesn&#8217;t have the latest version of RxJava used in the project. So, using RxJava dependency we override the versioning of the internal RxJava version used in RxAndroid.</p> 
<ul> 
<li>Inside the <strong><span style="color: #0000ff;">android</span></strong> block, add <span style="color: #008000;"><strong>viewBinding</strong></span> block with property enabled to <strong><span style="color: #008000;">true</span></strong>.</li> 
</ul> 
<pre>viewBinding {<br /> enabled = true<br />}</pre> 
<ul> 
<li>Finally, click on <strong><span style="color: #0000ff;">Sync Now</span>.</strong></li> 
</ul> 
<p>3. Open the <span style="color: #008000;"><strong>AndroidManifest.xml</strong> </span>file and add the internet permission above the application element.</p> 
<pre><;uses-permission android:name="android.permission.INTERNET"/>;</pre> 
<h4><span style="color: #000080;"><strong>Setup the Data Layer</strong></span></h4> 
<p>In the data layer, we have to prepare the model for the data, and an API call needs to be implemented. </p> 
<h5><span style="color: #000080;"><strong>Creating Model class</strong></span></h5> 
<p>I will use <span style="color: #000080;"><strong>“https://fake-movie-database-api.herokuapp.com/api?s=batman”</strong></span> API to fetch the data.</p> 
<p>The API JSON response will be like this.</p> 
<pre>{<br /> "Search": [<br /> {<br /> "imdbID": "tt0096895",<br /> "Title": "Batman",<br /> "Year": "1989",<br /> "Poster": "https://images-na.ssl-images-amazon.com/images/M/MV5BMTYwNjAyODIyMF5BMl5BanBnXkFtZTYwNDMwMDk2._V1_.jpg"<br /> },<br /> {<br /> "imdbID": "tt0468569",<br /> "Title": "The Dark Knight",<br /> "Year": "2008",<br /> "Poster": "https://ia.media-imdb.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw@@._V1_UX182_CR0,0,182,268_AL_.jpg"<br /> },<br /> ....<br /> ]<br />}</pre> 
<p>For the response data, we need to create the below two model classes.</p> 
<p><span style="color: #0000ff;"><strong>MovieList.kt</strong></span></p> 
<pre>data class MovieList(@SerializedName("Search") val mList: List<;Movie>;)</pre> 
<p><span style="color: #0000ff;"><strong>Movie.kt</strong></span></p> 
<pre>data class Movie(<br /> @SerializedName("Title") val title: String,<br /> @SerializedName("Poster") val poster: String,<br /> val imdbID: String,<br /> @SerializedName("Year") val year: String<br />)</pre> 
<h5><span style="color: #000080;"><strong>Setting up Retrofit</strong></span></h5> 
<p>Create an interface <span style="color: #008000;"><strong>RetrofitService</strong></span> for the API call.</p> 
<p>In the below code,the <strong><span style="color: #008000;">getAllMovies()</span></strong> method returns an Observable object of Type MovieList.</p> 
<p><span style="color: #0000ff;"><strong>RetrofitService.kt</strong></span></p> 
<pre>interface RetrofitService {<br /> @GET("api?s=batman")<br /> fun getAllMovies(): <strong><span style="color: #008000;">Observable<;MovieList>;</span></strong><br /><br /> companion object {<br /><br /> var retrofitService: RetrofitService? = null<br /><br /><strong><span style="color: #008000;"> //Create the RetrofitService instance using the retrofit.</span></strong><br /> fun getInstance(): RetrofitService {<br /><br /> if (retrofitService == null) {<br /> val retrofit = Retrofit.Builder()<br /> .baseUrl("https://fake-movie-database-api.herokuapp.com/")<br /> .addConverterFactory(GsonConverterFactory.create())<br /><strong><span style="color: #008000;"> //You need to tell Retrofit that you want to use RxJava 3</span></strong><br /> .addCallAdapterFactory(RxJava3CallAdapterFactory.create())<br /> .build()<br /> retrofitService = retrofit.create(RetrofitService::class.java)<br /> }<br /> return retrofitService!!<br /> }<br /> }<br />}</pre> 
<h5><span style="color: #000080;"><strong>Setup Data Repository</strong></span></h5> 
<p>Inside the below repository class, we need to pass the retrofit service instance to perform the network call. The repository class will only interact with the network source, the response of the network call we will handle later in ViewModel.</p> 
<p><span style="color: #0000ff;"><strong>MainRepository.kt</strong></span></p> 
<pre>class MainRepository constructor(private val retrofitService: RetrofitService) {<br /> fun getAllMovies() = retrofitService.getAllMovies()<br />}</pre> 
<h4><span style="color: #000080;"><strong>Setup the ViewModel</strong></span></h4> 
<p>The MainViewModel class extends the <strong><span style="color: #008000;">ViewModel</span></strong>. </p> 
<p>In the ViewModel constructor, we need to pass the data repository to handle the response from the API call.</p> 
<p>It uses LiveData to update the data to UI. LiveData only updates app component observers that are in an active lifecycle state.</p> 
<p><span style="color: #0000ff;"><strong>MainViewModel.kt</strong></span></p> 
<pre>package com.c1ctech.movieapprxjavaretrofit.ui<br /><br />import androidx.lifecycle.MutableLiveData<br />import androidx.lifecycle.ViewModel<br />import com.c1ctech.movieapprxjavaretrofit.Movie<br />import com.c1ctech.movieapprxjavaretrofit.data.network.model.MovieList<br />import com.c1ctech.movieapprxjavaretrofit.data.repository.MainRepository<br />import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers<br />import io.reactivex.rxjava3.core.Observer<br />import io.reactivex.rxjava3.disposables.Disposable<br />import io.reactivex.rxjava3.schedulers.Schedulers<br /><br />class MainViewModel(private val repository: MainRepository) : ViewModel() {<br /><br /> val movieList = MutableLiveData<;List<;Movie>;>;()<br /> val errorMessage = MutableLiveData<;String>;()<br /> lateinit var disposable: Disposable<br /><br /> fun getAllMovies() {<br /><strong><span style="color: #008000;"> //observer subscribing to observable</span></strong><br /> val response = repository.getAllMovies()<br /> response.subscribeOn(Schedulers.io())<br /> .observeOn(AndroidSchedulers.mainThread())<br /> .subscribe(getMoviesListObserver())<br /> }<br /><br /> private fun getMoviesListObserver(): Observer<;MovieList>; {<br /> return object : Observer<;MovieList>; {<br /> override fun onComplete() {<br /><strong><span style="color: #008000;"> //hide progress indicator .</span></strong><br /> }<br /><br /> override fun onError(e: Throwable) {<br /> movieList.postValue(null)<br /> }<br /><br /> override fun onNext(t: MovieList) {<br /> movieList.postValue(t.mList)<br /> }<br /><br /> override fun onSubscribe(d: Disposable) {<br /> disposable = d<br /><strong><span style="color: #008000;"> //start showing progress indicator.</span></strong><br /> }<br /> }<br /> }<br />}</pre> 
<p>In the above code,</p>
<!-- WP QUADS Content Ad Plugin v. 2.0.98.1 -->
<div class="quads-location quads-ad2" id="quads-ad2" style="float:none;margin:0px;">

</div>
 
<p>Inside <strong><span style="color: #008000;">getAllMovies()</span></strong> method,we get observable object as response from the API call in which we will apply the below methods:</p> 
<ul> 
<li><strong><span style="color: #0000ff;">subscribeOn(Schedulers.io())</span></strong>: This tells the Observable to run the task on a background thread.</li> 
<li><strong><span style="color: #0000ff;">observeOn(AndroidSchedulers.mainThread())</span></strong>: This tells the Observer to receive the data on the android UI thread so that you can take any UI-related actions.</li> 
<li><strong><span style="color: #0000ff;">subscribe()</span></strong>: It takes observer as a parameter which receives the data emitted by Observable.</li> 
</ul> 
<p>The <span style="color: #008000;"><strong>getMoviesListObserver()</strong></span> method, returns Observer that listen to Observable. Observer provides the below interface methods to know the the state of Observable.</p> 
<ul> 
<li><strong><span style="color: #0000ff;">onSubscribe()</span></strong>: Method will be called when an Observer subscribes to Observable. It contains a <strong><span style="color: #008000;">Disposable</span></strong> instance as parameter whose <strong><span style="color: #008000;">Disposable.dispose()</span> </strong>can be called anytime to cancel the connection or dispose the subscription when an Observer no longer wants to listen to Observable. In android disposable are very useful in avoiding memory leaks.</li> 
<li><strong><span style="color: #0000ff;">onNext()</span></strong>: This method will be called when Observable starts emitting the data.</li> 
<li><strong><span style="color: #0000ff;">onError()</span></strong>: In case of any error, onError() method will be called.</li> 
<li><strong><span style="color: #0000ff;">onComplete()</span></strong>: When an Observable completes the emission of all the items, onComplete() will be called.</li> 
</ul> 
<h4><span style="color: #000080;"><strong>ViewModel Factory</strong></span></h4> 
<p>To create ViewModel we have <span style="color: #008000;"><strong>ViewModelProviders</strong></span> utility provided by Android. But ViewModelProviders can only instantiate ViewModels with the no-arg constructor.<br />So to create a ViewModel with multiple arguments, we need to use a Factory that we can pass to ViewModelProviders to use when an instance of MyViewModel is required.</p> 
<pre>class MyViewModelFactory constructor(private val repository: MainRepository) :<br /> ViewModelProvider.Factory {<br /> override fun <;T : ViewModel?>; create(modelClass: Class<;T>;): T {<br /> return if (modelClass.isAssignableFrom(MainViewModel::class.java)) {<br /> MainViewModel(this.repository) as T<br /> } else {<br /> throw IllegalArgumentException("ViewModel Not Found")<br /> }<br /> }<br />}</pre> 
<h4><span style="color: #000080;"><strong>Setting up the UI</strong></span></h4> 
<p>In the UI part, We need to create an instance of the ViewModel and observe the API response. Based on the API response we need to update the UI.</p> 
<h5><span style="color: #000080;"><strong>Creating Activity Layout file</strong></span></h5> 
<p>The below layout file contains a RecyclerView and a button (onClick of which we will fetch data from the API).</p> 
<p><span style="color: #0000ff;"><strong>activity_main.xml</strong></span></p> 
<pre><;?xml version="1.0" encoding="utf-8"?>;<br /><;androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"<br /> xmlns:app="http://schemas.android.com/apk/res-auto"<br /> xmlns:tools="http://schemas.android.com/tools"<br /> android:layout_width="match_parent"<br /> android:layout_height="match_parent"<br /> tools:context=".ui.MainActivity">;<br /><br /> <;androidx.recyclerview.widget.RecyclerView<br /> android:id="@+id/recyclerview"<br /> android:layout_width="match_parent"<br /> android:layout_height="wrap_content"<br /> android:visibility="gone"<br /> app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"<br /> app:layout_constraintEnd_toEndOf="parent"<br /> app:layout_constraintStart_toStartOf="parent"<br /> app:layout_constraintTop_toTopOf="parent"<br /> tools:itemCount="5"<br /> tools:listitem="@layout/layout_rv_item" />;<br /><br /> <;Button<br /> android:id="@+id/btnShowMovies"<br /> android:layout_width="match_parent"<br /> android:layout_height="wrap_content"<br /> android:layout_margin="30dp"<br /> android:text="SHOW MOVIES"<br /> app:layout_constraintBottom_toBottomOf="parent"<br /> app:layout_constraintEnd_toEndOf="parent"<br /> app:layout_constraintHorizontal_bias="0.5"<br /> app:layout_constraintStart_toStartOf="parent" />;<br /><br /><;/androidx.constraintlayout.widget.ConstraintLayout>;</pre> 
<h5><span style="color: #000080;"><strong>Creating Adapter Layout file</strong></span></h5> 
<p>The below layout file represents the UI of each item of recyclerView.</p> 
<p><span style="color: #0000ff;"><strong>layout_rv_item.xml</strong></span></p> 
<pre><;?xml version="1.0" encoding="utf-8"?>;<br /><;androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"<br /> xmlns:app="http://schemas.android.com/apk/res-auto"<br /> android:layout_width="match_parent"<br /> android:layout_height="wrap_content"<br /> android:layout_margin="8dp"<br /> android:elevation="8dp"<br /> app:cardCornerRadius="8dp">;<br /><br /> <;ImageView<br /> android:id="@+id/moviePoster"<br /> android:layout_width="match_parent"<br /> android:layout_height="200dp"<br /> android:scaleType="centerCrop"<br /> android:src="@drawable/placeholder"/>;<br /><br /> <;TextView<br /> android:id="@+id/movieTitle"<br /> android:layout_width="match_parent"<br /> android:layout_height="wrap_content"<br /> android:background="@color/purple_700"<br /> android:gravity="center_vertical"<br /> android:padding="3dp"<br /> android:textAppearance="@style/TextAppearance.AppCompat.Large"<br /> android:textColor="@android:color/white" />;<br /><br /> <;TextView<br /> android:id="@+id/movieYear"<br /> android:layout_width="match_parent"<br /> android:layout_height="200dp"<br /> android:text="Year: 1987"<br /> android:textStyle="bold"<br /> android:gravity="center"<br /> android:textSize="25sp"<br /> android:textColor="@android:color/holo_red_dark"/>;<br /><br /><;/androidx.cardview.widget.CardView>;</pre> 
<h5><span style="color: #000080;"><strong>Creating Adapter class</strong></span></h5> 
<p>The MainAdapter is an adapter class for the recycler view to set all the items into recycler view.</p> 
<p><span style="color: #0000ff;"><strong>MainAdapter.kt</strong></span></p> 
<pre>package com.c1ctech.movieapprxjavaretrofit<br /><br />import android.view.LayoutInflater<br />import android.view.ViewGroup<br />import androidx.recyclerview.widget.RecyclerView<br />import com.bumptech.glide.Glide<br />import com.c1ctech.movieapprxjavaretrofit.databinding.LayoutRvItemBinding<br /><br />class MainAdapter : RecyclerView.Adapter<;MainViewHolder>;() {<br /><br /> var movies = mutableListOf<;Movie>;()<br /><br /> fun setMovieList(movies: List<;Movie>;) {<br /> this.movies = movies.toMutableList()<br /> notifyDataSetChanged()<br /> }<br /><br /> override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {<br /> val inflater = LayoutInflater.from(parent.context)<br /><br /> val binding = LayoutRvItemBinding.inflate(inflater, parent, false)<br /> return MainViewHolder(binding)<br /> }<br /><br /> override fun onBindViewHolder(holder: MainViewHolder, position: Int) {<br /> val movie = movies[position]<br /> holder.binding.movieTitle.text = movie.title<br /> holder.binding.movieYear.text = "Year: " + movie.year<br /><br /> Glide.with(holder.itemView.context).load(movie.poster).placeholder(R.drawable.placeholder)<br /> .into(holder.binding.moviePoster)<br /><br /> }<br /><br /> override fun getItemCount(): Int {<br /> return movies.size<br /> }<br />}<br /><br />class MainViewHolder(val binding: LayoutRvItemBinding) : RecyclerView.ViewHolder(binding.root) {}</pre> 
<h5><span style="color: #000080;"><strong>Creating MainActivity File</strong></span></h5> 
<p>Inside MainActivity, we will observe the response from the API and update the UI.</p> 
<p><span style="color: #0000ff;"><strong>MainActivity.kt</strong></span></p> 
<pre>package com.c1ctech.movieapprxjavaretrofit.ui<br /><br />import androidx.appcompat.app.AppCompatActivity<br />import android.os.Bundle<br />import android.util.Log<br />import android.view.View<br />import android.widget.Toast<br />import androidx.lifecycle.Observer<br />import androidx.lifecycle.ViewModelProvider<br />import com.c1ctech.movieapprxjavaretrofit.MainAdapter<br />import com.c1ctech.movieapprxjavaretrofit.databinding.ActivityMainBinding<br />import com.c1ctech.movieapprxjavaretrofit.data.network.RetrofitService<br />import com.c1ctech.movieapprxjavaretrofit.data.repository.MainRepository<br /><br />class MainActivity : AppCompatActivity() {<br /> private val TAG = "MainActivity"<br /> private lateinit var binding: ActivityMainBinding<br /><br /> lateinit var viewModel: MainViewModel<br /><br /> private val retrofitService = RetrofitService.getInstance()<br /> val adapter = MainAdapter()<br /><br /> override fun onCreate(savedInstanceState: Bundle?) {<br /> super.onCreate(savedInstanceState)<br /> binding = ActivityMainBinding.inflate(layoutInflater)<br /> setContentView(binding.root)<br /><br /><strong><span style="color: #008000;"> //get viewmodel instance using ViewModelProvider.Factory</span></strong><br /> viewModel =<br /> ViewModelProvider(this, MyViewModelFactory(MainRepository(retrofitService))).get(<br /> MainViewModel::class.java<br /> )<br /><br /><strong><span style="color: #008000;"> //set adapter in recyclerview</span></strong><br /> binding.recyclerview.adapter = adapter<br /><br /> binding.btnShowMovies.setOnClickListener {<br /> viewModel.getAllMovies()<br /> binding.btnShowMovies.visibility = View.GONE<br /> binding.recyclerview.visibility = View.VISIBLE<br /><br /> }<br /> <strong><span style="color: #008000;">//the observer will only receive events if the owner(activity) is in active state</span></strong><br /><strong><span style="color: #008000;"> //invoked when movieList data changes</span></strong><br /> viewModel.movieList.observe(this, Observer {<br /> if (it != null) {<br /> Log.d(TAG, "movieList: $it")<br /> adapter.setMovieList(it)<br /> } else {<br /> Toast.makeText(this, "Error in fetching data", Toast.LENGTH_SHORT).show()<br /> }<br /> })<br /><br /><strong><span style="color: #008000;"> //invoked when a network exception occurred</span></strong><br /> viewModel.errorMessage.observe(this, Observer {<br /> Log.d(TAG, "errorMessage: $it")<br /> })<br /> }<br /><br /> override fun onDestroy() {<br /><span style="color: #008000;"><strong> //don't send events once the activity is destroyed</strong></span><br /> viewModel.disposable.dispose()<br /> super.onDestroy()<br /> }<br />}</pre> 
<p>When you run the app it will look like this:</p> 
<p><img class="alignnone wp-image-3144" src="https://c1ctech.com/wp-content/uploads/2022/03/Screenshot_20220306-175018_MovieAppRxJavaRetrofit-498x1024.jpg" alt="" width="284" height="584" /> <img class="alignnone wp-image-3145" src="https://c1ctech.com/wp-content/uploads/2022/03/Screenshot_20220306-175214_MovieAppRxJavaRetrofit-498x1024.jpg" alt="" width="281" height="578" />

