Site icon C1CTech

Android App using RxJava, Rerofit with MVVM Architecture

&NewLine;<p>This post is about how to build an Android app using RxJava&comma; RxAndroid&comma; Retrofit with MVVM pattern in Kotlin&period;<&sol;p> &NewLine; &NewLine; &NewLine; &NewLine;<div class&equals;"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex"> &NewLine;<div class&equals;"wp-block-button aligncenter"><a class&equals;"wp-block-button&lowbar;&lowbar;link has-background" style&equals;"background-color&colon; &num;20057a&semi;" href&equals;"https&colon;&sol;&sol;github&period;com&sol;arunk7839&sol;MovieAppRxJavaRetrofit"><strong>DOWNLOAD CODE<&sol;strong><&sol;a><&sol;div> &NewLine;<&sol;div> &NewLine; &NewLine; &NewLine; &NewLine;<h4> <&sol;h4> &NewLine;<h4><strong><span style&equals;"color&colon; &num;000080&semi;">RxJava<&sol;span><&sol;strong><&sol;h4> &NewLine;<p>RxJava is a Java implementation of <strong><span style&equals;"color&colon; &num;000080&semi;"><a style&equals;"color&colon; &num;000080&semi;" href&equals;"https&colon;&sol;&sol;reactivex&period;io&sol;">Reactive Extension or ReactiveX<&sol;a><&sol;span><&sol;strong>&period; Basically&comma; it’s a library that composes asynchronous events by following Observer Pattern&period;<&sol;p> &NewLine;<p>The library offers a wide range of amazing operators like map&comma; combine&comma; merge&comma; filter&comma; and a lot more that can be applied to the data&period;<&sol;p> &NewLine;<p>RxJava is all about two key components&colon; Observable and Observer&period; In addition to these&comma; there are other things like Schedulers&comma; Operators&comma; and Subscription&period;<&sol;p> &NewLine;<ul> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">Observable<&sol;span><&sol;strong>&colon; Observable is a data stream that does some work and emits data&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">Observer<&sol;span><&sol;strong>&colon; Observer receives the data emitted by Observable&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">Subscription<&sol;span><&sol;strong>&colon; The bonding between Observable and Observer is called a Subscription&period; There can be multiple Observers subscribed to a single Observable&period;<&sol;li> &NewLine;<li><span style&equals;"color&colon; &num;0000ff&semi;"><strong>Operator<&sol;strong><&sol;span>&colon; Operators modify the data emitted by Observable before an observer receives them&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">Schedulers<&sol;span><&sol;strong>&colon; Schedulers decides the thread on which Observable should emit the data and on which Observer should receive the data i&period;e background thread&comma; main thread&comma; etc&period;&comma;<&sol;li> &NewLine;<&sol;ul> &NewLine;<h4><strong><span style&equals;"color&colon; &num;000080&semi;">RxAndroid<&sol;span><&sol;strong><&sol;h4> &NewLine;<p>RxAndroid is an extension of RxJava for Android which is used only in Android applications&period;<&sol;p> &NewLine;<p><strong><span style&equals;"color&colon; &num;008000&semi;">Schedulers<&sol;span><&sol;strong> are introduced in RxAndroid which plays a major role in supporting the multithreading concepts in android applications&period; Schedulers basically decide the thread on which a particular code runs whether on a background thread or main thread&period; <&sol;p> &NewLine;<p>Even though there are a lot of Schedulers available&comma; The below two Schedulers are extensively used in android programming&period; <&sol;p> &NewLine;<ul> &NewLine;<li><span style&equals;"color&colon; &num;0000ff&semi;"><strong>Schedulers&period;io&lpar;&rpar;<&sol;strong><&sol;span>&colon; This is used to perform operations like making network calls&comma; reading disc&sol;files&comma; database operations&comma; etc&period;&comma; This maintains a pool of threads&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">AndroidSchedulers&period;mainThread&lpar;&rpar;<&sol;span><&sol;strong>&colon; this provides us access to the main thread of the application to perform actions like updating the UI&period; We shouldn’t perform any intensive operations on this thread as ANR dialog can be thrown&period;<&sol;li> &NewLine;<&sol;ul> &NewLine; &NewLine; &NewLine; &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>Creating new project<&sol;strong><&sol;span><&sol;h4> &NewLine;<p>1 &period; Create a new project by going to <span style&equals;"color&colon; &num;008000&semi;"><strong>File &Implies; New Android Project<&sol;strong>&comma;<&sol;span> select <span style&equals;"color&colon; &num;008000&semi;"><strong>Empty<&sol;strong><&sol;span> Activity&comma; provide <span style&equals;"color&colon; &num;008000&semi;"><strong>app<&sol;strong><&sol;span> name&comma; select language to <span style&equals;"color&colon; &num;008000&semi;"><strong>kotlin<&sol;strong><&sol;span> and then finally click on <span style&equals;"color&colon; &num;0000ff&semi;"><strong>finish<&sol;strong><&sol;span>&period;<&sol;p> &NewLine;<p>2 &period; Open app-level build&period;gradle file and add the below changes&colon;<&sol;p> &NewLine;<ul> &NewLine;<li>Add the below libraries under the <span style&equals;"color&colon; &num;0000ff&semi;"><strong>dependencies<&sol;strong><&sol;span> section<strong>&colon;<&sol;strong><&sol;li> &NewLine;<&sol;ul> &NewLine;<pre>dependencies &lbrace;<br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;ViewModel and livedata<&sol;span><&sol;strong><br &sol;> implementation "androidx&period;lifecycle&colon;lifecycle-extensions&colon;2&period;2&period;0"<br &sol;> <br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;Retrofit<&sol;span><&sol;strong><br &sol;> implementation 'com&period;squareup&period;retrofit2&colon;retrofit&colon;2&period;9&period;0'<br &sol;> implementation 'com&period;squareup&period;retrofit2&colon;converter-gson&colon;2&period;9&period;0'<br &sol;> implementation 'com&period;squareup&period;retrofit2&colon;adapter-rxjava3&colon;2&period;9&period;0'<br &sol;><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;Glide<&sol;span><&sol;strong><br &sol;> implementation 'com&period;github&period;bumptech&period;glide&colon;glide&colon;4&period;12&period;0'<br &sol;> implementation 'com&period;github&period;bumptech&period;glide&colon;compiler&colon;4&period;12&period;0'<br &sol;><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; RxJava3 <&sol;span><&sol;strong><br &sol;> implementation 'io&period;reactivex&period;rxjava3&colon;rxjava&colon;3&period;1&period;3'<br &sol;><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;RxAndroid<&sol;span><&sol;strong><br &sol;> implementation 'io&period;reactivex&period;rxjava3&colon;rxandroid&colon;3&period;0&period;0'<br &sol;>&rcub;<&sol;pre> &NewLine;<p><span style&equals;"color&colon; &num;000080&semi;"><b class&equals;"graf--bold">Note&colon;<&sol;b> <&sol;span>While using RxAndroid in our project we still add the dependency of RxJava to work&comma;the reason is&comma; there might be a chance that RxAndroid doesn&&num;8217&semi;t have the latest version of RxJava used in the project&period; So&comma; using RxJava dependency we override the versioning of the internal RxJava version used in RxAndroid&period;<&sol;p> &NewLine;<ul> &NewLine;<li>Inside the <strong><span style&equals;"color&colon; &num;0000ff&semi;">android<&sol;span><&sol;strong> block&comma; add <span style&equals;"color&colon; &num;008000&semi;"><strong>viewBinding<&sol;strong><&sol;span> block with property enabled to <strong><span style&equals;"color&colon; &num;008000&semi;">true<&sol;span><&sol;strong>&period;<&sol;li> &NewLine;<&sol;ul> &NewLine;<pre>viewBinding &lbrace;<br &sol;> enabled &equals; true<br &sol;>&rcub;<&sol;pre> &NewLine;<ul> &NewLine;<li>Finally&comma; click on <strong><span style&equals;"color&colon; &num;0000ff&semi;">Sync Now<&sol;span>&period;<&sol;strong><&sol;li> &NewLine;<&sol;ul> &NewLine;<p>3&period; Open the <span style&equals;"color&colon; &num;008000&semi;"><strong>AndroidManifest&period;xml<&sol;strong> <&sol;span>file and add the internet permission above the application element&period;<&sol;p> &NewLine;<pre>&lt&semi;uses-permission android&colon;name&equals;"android&period;permission&period;INTERNET"&sol;&gt&semi;<&sol;pre> &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>Setup the Data Layer<&sol;strong><&sol;span><&sol;h4> &NewLine;<p>In the data layer&comma; we have to prepare the model for the data&comma; and an API call needs to be implemented&period; <&sol;p> &NewLine;<h5><span style&equals;"color&colon; &num;000080&semi;"><strong>Creating Model class<&sol;strong><&sol;span><&sol;h5> &NewLine;<p>I will use <span style&equals;"color&colon; &num;000080&semi;"><strong>&OpenCurlyDoubleQuote;https&colon;&sol;&sol;fake-movie-database-api&period;herokuapp&period;com&sol;api&quest;s&equals;batman”<&sol;strong><&sol;span> API to fetch the data&period;<&sol;p> &NewLine;<p>The API JSON response will be like this&period;<&sol;p> &NewLine;<pre>&lbrace;<br &sol;> "Search"&colon; &lbrack;<br &sol;> &lbrace;<br &sol;> "imdbID"&colon; "tt0096895"&comma;<br &sol;> "Title"&colon; "Batman"&comma;<br &sol;> "Year"&colon; "1989"&comma;<br &sol;> "Poster"&colon; "https&colon;&sol;&sol;images-na&period;ssl-images-amazon&period;com&sol;images&sol;M&sol;MV5BMTYwNjAyODIyMF5BMl5BanBnXkFtZTYwNDMwMDk2&period;&lowbar;V1&lowbar;&period;jpg"<br &sol;> &rcub;&comma;<br &sol;> &lbrace;<br &sol;> "imdbID"&colon; "tt0468569"&comma;<br &sol;> "Title"&colon; "The Dark Knight"&comma;<br &sol;> "Year"&colon; "2008"&comma;<br &sol;> "Poster"&colon; "https&colon;&sol;&sol;ia&period;media-imdb&period;com&sol;images&sol;M&sol;MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw&commat;&commat;&period;&lowbar;V1&lowbar;UX182&lowbar;CR0&comma;0&comma;182&comma;268&lowbar;AL&lowbar;&period;jpg"<br &sol;> &rcub;&comma;<br &sol;> &period;&period;&period;&period;<br &sol;> &rsqb;<br &sol;>&rcub;<&sol;pre> &NewLine;<p>For the response data&comma; we need to create the below two model classes&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>MovieList&period;kt<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>data class MovieList&lpar;&commat;SerializedName&lpar;"Search"&rpar; val mList&colon; List&lt&semi;Movie&gt&semi;&rpar;<&sol;pre> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>Movie&period;kt<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>data class Movie&lpar;<br &sol;> &commat;SerializedName&lpar;"Title"&rpar; val title&colon; String&comma;<br &sol;> &commat;SerializedName&lpar;"Poster"&rpar; val poster&colon; String&comma;<br &sol;> val imdbID&colon; String&comma;<br &sol;> &commat;SerializedName&lpar;"Year"&rpar; val year&colon; String<br &sol;>&rpar;<&sol;pre> &NewLine;<h5><span style&equals;"color&colon; &num;000080&semi;"><strong>Setting up Retrofit<&sol;strong><&sol;span><&sol;h5> &NewLine;<p>Create an interface <span style&equals;"color&colon; &num;008000&semi;"><strong>RetrofitService<&sol;strong><&sol;span> for the API call&period;<&sol;p> &NewLine;<p>In the below code&comma;the <strong><span style&equals;"color&colon; &num;008000&semi;">getAllMovies&lpar;&rpar;<&sol;span><&sol;strong> method returns an Observable object of Type MovieList&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>RetrofitService&period;kt<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>interface RetrofitService &lbrace;<br &sol;> &commat;GET&lpar;"api&quest;s&equals;batman"&rpar;<br &sol;> fun getAllMovies&lpar;&rpar;&colon; <strong><span style&equals;"color&colon; &num;008000&semi;">Observable&lt&semi;MovieList&gt&semi;<&sol;span><&sol;strong><br &sol;><br &sol;> companion object &lbrace;<br &sol;><br &sol;> var retrofitService&colon; RetrofitService&quest; &equals; null<br &sol;><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;Create the RetrofitService instance using the retrofit&period;<&sol;span><&sol;strong><br &sol;> fun getInstance&lpar;&rpar;&colon; RetrofitService &lbrace;<br &sol;><br &sol;> if &lpar;retrofitService &equals;&equals; null&rpar; &lbrace;<br &sol;> val retrofit &equals; Retrofit&period;Builder&lpar;&rpar;<br &sol;> &period;baseUrl&lpar;"https&colon;&sol;&sol;fake-movie-database-api&period;herokuapp&period;com&sol;"&rpar;<br &sol;> &period;addConverterFactory&lpar;GsonConverterFactory&period;create&lpar;&rpar;&rpar;<br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;You need to tell Retrofit that you want to use RxJava 3<&sol;span><&sol;strong><br &sol;> &period;addCallAdapterFactory&lpar;RxJava3CallAdapterFactory&period;create&lpar;&rpar;&rpar;<br &sol;> &period;build&lpar;&rpar;<br &sol;> retrofitService &equals; retrofit&period;create&lpar;RetrofitService&colon;&colon;class&period;java&rpar;<br &sol;> &rcub;<br &sol;> return retrofitService&excl;&excl;<br &sol;> &rcub;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<h5><span style&equals;"color&colon; &num;000080&semi;"><strong>Setup Data Repository<&sol;strong><&sol;span><&sol;h5> &NewLine;<p>Inside the below repository class&comma; we need to pass the retrofit service instance to perform the network call&period; The repository class will only interact with the network source&comma; the response of the network call we will handle later in ViewModel&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>MainRepository&period;kt<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>class MainRepository constructor&lpar;private val retrofitService&colon; RetrofitService&rpar; &lbrace;<br &sol;> fun getAllMovies&lpar;&rpar; &equals; retrofitService&period;getAllMovies&lpar;&rpar;<br &sol;>&rcub;<&sol;pre> &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>Setup the ViewModel<&sol;strong><&sol;span><&sol;h4> &NewLine;<p>The MainViewModel class extends the <strong><span style&equals;"color&colon; &num;008000&semi;">ViewModel<&sol;span><&sol;strong>&period; <&sol;p> &NewLine;<p>In the ViewModel constructor&comma; we need to pass the data repository to handle the response from the API call&period;<&sol;p> &NewLine;<p>It uses LiveData to update the data to UI&period; LiveData only updates app component observers that are in an active lifecycle state&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>MainViewModel&period;kt<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>package com&period;c1ctech&period;movieapprxjavaretrofit&period;ui<br &sol;><br &sol;>import androidx&period;lifecycle&period;MutableLiveData<br &sol;>import androidx&period;lifecycle&period;ViewModel<br &sol;>import com&period;c1ctech&period;movieapprxjavaretrofit&period;Movie<br &sol;>import com&period;c1ctech&period;movieapprxjavaretrofit&period;data&period;network&period;model&period;MovieList<br &sol;>import com&period;c1ctech&period;movieapprxjavaretrofit&period;data&period;repository&period;MainRepository<br &sol;>import io&period;reactivex&period;rxjava3&period;android&period;schedulers&period;AndroidSchedulers<br &sol;>import io&period;reactivex&period;rxjava3&period;core&period;Observer<br &sol;>import io&period;reactivex&period;rxjava3&period;disposables&period;Disposable<br &sol;>import io&period;reactivex&period;rxjava3&period;schedulers&period;Schedulers<br &sol;><br &sol;>class MainViewModel&lpar;private val repository&colon; MainRepository&rpar; &colon; ViewModel&lpar;&rpar; &lbrace;<br &sol;><br &sol;> val movieList &equals; MutableLiveData&lt&semi;List&lt&semi;Movie&gt&semi;&gt&semi;&lpar;&rpar;<br &sol;> val errorMessage &equals; MutableLiveData&lt&semi;String&gt&semi;&lpar;&rpar;<br &sol;> lateinit var disposable&colon; Disposable<br &sol;><br &sol;> fun getAllMovies&lpar;&rpar; &lbrace;<br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;observer subscribing to observable<&sol;span><&sol;strong><br &sol;> val response &equals; repository&period;getAllMovies&lpar;&rpar;<br &sol;> response&period;subscribeOn&lpar;Schedulers&period;io&lpar;&rpar;&rpar;<br &sol;> &period;observeOn&lpar;AndroidSchedulers&period;mainThread&lpar;&rpar;&rpar;<br &sol;> &period;subscribe&lpar;getMoviesListObserver&lpar;&rpar;&rpar;<br &sol;> &rcub;<br &sol;><br &sol;> private fun getMoviesListObserver&lpar;&rpar;&colon; Observer&lt&semi;MovieList&gt&semi; &lbrace;<br &sol;> return object &colon; Observer&lt&semi;MovieList&gt&semi; &lbrace;<br &sol;> override fun onComplete&lpar;&rpar; &lbrace;<br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;hide progress indicator &period;<&sol;span><&sol;strong><br &sol;> &rcub;<br &sol;><br &sol;> override fun onError&lpar;e&colon; Throwable&rpar; &lbrace;<br &sol;> movieList&period;postValue&lpar;null&rpar;<br &sol;> &rcub;<br &sol;><br &sol;> override fun onNext&lpar;t&colon; MovieList&rpar; &lbrace;<br &sol;> movieList&period;postValue&lpar;t&period;mList&rpar;<br &sol;> &rcub;<br &sol;><br &sol;> override fun onSubscribe&lpar;d&colon; Disposable&rpar; &lbrace;<br &sol;> disposable &equals; d<br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;start showing progress indicator&period;<&sol;span><&sol;strong><br &sol;> &rcub;<br &sol;> &rcub;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<p>In the above code&comma;<&sol;p>&NewLine;<&excl;-- WP QUADS Content Ad Plugin v&period; 2&period;0&period;98&period;1 -->&NewLine;<div class&equals;"quads-location quads-ad2" id&equals;"quads-ad2" style&equals;"float&colon;none&semi;margin&colon;0px&semi;">&NewLine;&NewLine;<&sol;div>&NewLine; &NewLine;<p>Inside <strong><span style&equals;"color&colon; &num;008000&semi;">getAllMovies&lpar;&rpar;<&sol;span><&sol;strong> method&comma;we get observable object as response from the API call in which we will apply the below methods&colon;<&sol;p> &NewLine;<ul> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">subscribeOn&lpar;Schedulers&period;io&lpar;&rpar;&rpar;<&sol;span><&sol;strong>&colon; This tells the Observable to run the task on a background thread&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">observeOn&lpar;AndroidSchedulers&period;mainThread&lpar;&rpar;&rpar;<&sol;span><&sol;strong>&colon; This tells the Observer to receive the data on the android UI thread so that you can take any UI-related actions&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">subscribe&lpar;&rpar;<&sol;span><&sol;strong>&colon; It takes observer as a parameter which receives the data emitted by Observable&period;<&sol;li> &NewLine;<&sol;ul> &NewLine;<p>The <span style&equals;"color&colon; &num;008000&semi;"><strong>getMoviesListObserver&lpar;&rpar;<&sol;strong><&sol;span> method&comma; returns Observer that listen to Observable&period; Observer provides the below interface methods to know the the state of Observable&period;<&sol;p> &NewLine;<ul> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">onSubscribe&lpar;&rpar;<&sol;span><&sol;strong>&colon; Method will be called when an Observer subscribes to Observable&period; It contains a <strong><span style&equals;"color&colon; &num;008000&semi;">Disposable<&sol;span><&sol;strong> instance as parameter whose <strong><span style&equals;"color&colon; &num;008000&semi;">Disposable&period;dispose&lpar;&rpar;<&sol;span> <&sol;strong>can be called anytime to cancel the connection or dispose the subscription when an Observer no longer wants to listen to Observable&period; In android disposable are very useful in avoiding memory leaks&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">onNext&lpar;&rpar;<&sol;span><&sol;strong>&colon; This method will be called when Observable starts emitting the data&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">onError&lpar;&rpar;<&sol;span><&sol;strong>&colon; In case of any error&comma; onError&lpar;&rpar; method will be called&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">onComplete&lpar;&rpar;<&sol;span><&sol;strong>&colon; When an Observable completes the emission of all the items&comma; onComplete&lpar;&rpar; will be called&period;<&sol;li> &NewLine;<&sol;ul> &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>ViewModel Factory<&sol;strong><&sol;span><&sol;h4> &NewLine;<p>To create ViewModel we have <span style&equals;"color&colon; &num;008000&semi;"><strong>ViewModelProviders<&sol;strong><&sol;span> utility provided by Android&period; But ViewModelProviders can only instantiate ViewModels with the no-arg constructor&period;<br &sol;>So to create a ViewModel with multiple arguments&comma; we need to use a Factory that we can pass to ViewModelProviders to use when an instance of MyViewModel is required&period;<&sol;p> &NewLine;<pre>class MyViewModelFactory constructor&lpar;private val repository&colon; MainRepository&rpar; &colon;<br &sol;> ViewModelProvider&period;Factory &lbrace;<br &sol;> override fun &lt&semi;T &colon; ViewModel&quest;&gt&semi; create&lpar;modelClass&colon; Class&lt&semi;T&gt&semi;&rpar;&colon; T &lbrace;<br &sol;> return if &lpar;modelClass&period;isAssignableFrom&lpar;MainViewModel&colon;&colon;class&period;java&rpar;&rpar; &lbrace;<br &sol;> MainViewModel&lpar;this&period;repository&rpar; as T<br &sol;> &rcub; else &lbrace;<br &sol;> throw IllegalArgumentException&lpar;"ViewModel Not Found"&rpar;<br &sol;> &rcub;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>Setting up the UI<&sol;strong><&sol;span><&sol;h4> &NewLine;<p>In the UI part&comma; We need to create an instance of the ViewModel and observe the API response&period; Based on the API response we need to update the UI&period;<&sol;p> &NewLine;<h5><span style&equals;"color&colon; &num;000080&semi;"><strong>Creating Activity Layout file<&sol;strong><&sol;span><&sol;h5> &NewLine;<p>The below layout file contains a RecyclerView and a button &lpar;onClick of which we will fetch data from the API&rpar;&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>activity&lowbar;main&period;xml<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>&lt&semi;&quest;xml version&equals;"1&period;0" encoding&equals;"utf-8"&quest;&gt&semi;<br &sol;>&lt&semi;androidx&period;constraintlayout&period;widget&period;ConstraintLayout xmlns&colon;android&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;apk&sol;res&sol;android"<br &sol;> xmlns&colon;app&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;apk&sol;res-auto"<br &sol;> xmlns&colon;tools&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;tools"<br &sol;> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br &sol;> android&colon;layout&lowbar;height&equals;"match&lowbar;parent"<br &sol;> tools&colon;context&equals;"&period;ui&period;MainActivity"&gt&semi;<br &sol;><br &sol;> &lt&semi;androidx&period;recyclerview&period;widget&period;RecyclerView<br &sol;> android&colon;id&equals;"&commat;&plus;id&sol;recyclerview"<br &sol;> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br &sol;> android&colon;layout&lowbar;height&equals;"wrap&lowbar;content"<br &sol;> android&colon;visibility&equals;"gone"<br &sol;> app&colon;layoutManager&equals;"androidx&period;recyclerview&period;widget&period;LinearLayoutManager"<br &sol;> app&colon;layout&lowbar;constraintEnd&lowbar;toEndOf&equals;"parent"<br &sol;> app&colon;layout&lowbar;constraintStart&lowbar;toStartOf&equals;"parent"<br &sol;> app&colon;layout&lowbar;constraintTop&lowbar;toTopOf&equals;"parent"<br &sol;> tools&colon;itemCount&equals;"5"<br &sol;> tools&colon;listitem&equals;"&commat;layout&sol;layout&lowbar;rv&lowbar;item" &sol;&gt&semi;<br &sol;><br &sol;> &lt&semi;Button<br &sol;> android&colon;id&equals;"&commat;&plus;id&sol;btnShowMovies"<br &sol;> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br &sol;> android&colon;layout&lowbar;height&equals;"wrap&lowbar;content"<br &sol;> android&colon;layout&lowbar;margin&equals;"30dp"<br &sol;> android&colon;text&equals;"SHOW MOVIES"<br &sol;> app&colon;layout&lowbar;constraintBottom&lowbar;toBottomOf&equals;"parent"<br &sol;> app&colon;layout&lowbar;constraintEnd&lowbar;toEndOf&equals;"parent"<br &sol;> app&colon;layout&lowbar;constraintHorizontal&lowbar;bias&equals;"0&period;5"<br &sol;> app&colon;layout&lowbar;constraintStart&lowbar;toStartOf&equals;"parent" &sol;&gt&semi;<br &sol;><br &sol;>&lt&semi;&sol;androidx&period;constraintlayout&period;widget&period;ConstraintLayout&gt&semi;<&sol;pre> &NewLine;<h5><span style&equals;"color&colon; &num;000080&semi;"><strong>Creating Adapter Layout file<&sol;strong><&sol;span><&sol;h5> &NewLine;<p>The below layout file represents the UI of each item of recyclerView&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>layout&lowbar;rv&lowbar;item&period;xml<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>&lt&semi;&quest;xml version&equals;"1&period;0" encoding&equals;"utf-8"&quest;&gt&semi;<br &sol;>&lt&semi;androidx&period;cardview&period;widget&period;CardView xmlns&colon;android&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;apk&sol;res&sol;android"<br &sol;> xmlns&colon;app&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;apk&sol;res-auto"<br &sol;> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br &sol;> android&colon;layout&lowbar;height&equals;"wrap&lowbar;content"<br &sol;> android&colon;layout&lowbar;margin&equals;"8dp"<br &sol;> android&colon;elevation&equals;"8dp"<br &sol;> app&colon;cardCornerRadius&equals;"8dp"&gt&semi;<br &sol;><br &sol;> &lt&semi;ImageView<br &sol;> android&colon;id&equals;"&commat;&plus;id&sol;moviePoster"<br &sol;> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br &sol;> android&colon;layout&lowbar;height&equals;"200dp"<br &sol;> android&colon;scaleType&equals;"centerCrop"<br &sol;> android&colon;src&equals;"&commat;drawable&sol;placeholder"&sol;&gt&semi;<br &sol;><br &sol;> &lt&semi;TextView<br &sol;> android&colon;id&equals;"&commat;&plus;id&sol;movieTitle"<br &sol;> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br &sol;> android&colon;layout&lowbar;height&equals;"wrap&lowbar;content"<br &sol;> android&colon;background&equals;"&commat;color&sol;purple&lowbar;700"<br &sol;> android&colon;gravity&equals;"center&lowbar;vertical"<br &sol;> android&colon;padding&equals;"3dp"<br &sol;> android&colon;textAppearance&equals;"&commat;style&sol;TextAppearance&period;AppCompat&period;Large"<br &sol;> android&colon;textColor&equals;"&commat;android&colon;color&sol;white" &sol;&gt&semi;<br &sol;><br &sol;> &lt&semi;TextView<br &sol;> android&colon;id&equals;"&commat;&plus;id&sol;movieYear"<br &sol;> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br &sol;> android&colon;layout&lowbar;height&equals;"200dp"<br &sol;> android&colon;text&equals;"Year&colon; 1987"<br &sol;> android&colon;textStyle&equals;"bold"<br &sol;> android&colon;gravity&equals;"center"<br &sol;> android&colon;textSize&equals;"25sp"<br &sol;> android&colon;textColor&equals;"&commat;android&colon;color&sol;holo&lowbar;red&lowbar;dark"&sol;&gt&semi;<br &sol;><br &sol;>&lt&semi;&sol;androidx&period;cardview&period;widget&period;CardView&gt&semi;<&sol;pre> &NewLine;<h5><span style&equals;"color&colon; &num;000080&semi;"><strong>Creating Adapter class<&sol;strong><&sol;span><&sol;h5> &NewLine;<p>The MainAdapter is an adapter class for the recycler view to set all the items into recycler view&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>MainAdapter&period;kt<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>package com&period;c1ctech&period;movieapprxjavaretrofit<br &sol;><br &sol;>import android&period;view&period;LayoutInflater<br &sol;>import android&period;view&period;ViewGroup<br &sol;>import androidx&period;recyclerview&period;widget&period;RecyclerView<br &sol;>import com&period;bumptech&period;glide&period;Glide<br &sol;>import com&period;c1ctech&period;movieapprxjavaretrofit&period;databinding&period;LayoutRvItemBinding<br &sol;><br &sol;>class MainAdapter &colon; RecyclerView&period;Adapter&lt&semi;MainViewHolder&gt&semi;&lpar;&rpar; &lbrace;<br &sol;><br &sol;> var movies &equals; mutableListOf&lt&semi;Movie&gt&semi;&lpar;&rpar;<br &sol;><br &sol;> fun setMovieList&lpar;movies&colon; List&lt&semi;Movie&gt&semi;&rpar; &lbrace;<br &sol;> this&period;movies &equals; movies&period;toMutableList&lpar;&rpar;<br &sol;> notifyDataSetChanged&lpar;&rpar;<br &sol;> &rcub;<br &sol;><br &sol;> override fun onCreateViewHolder&lpar;parent&colon; ViewGroup&comma; viewType&colon; Int&rpar;&colon; MainViewHolder &lbrace;<br &sol;> val inflater &equals; LayoutInflater&period;from&lpar;parent&period;context&rpar;<br &sol;><br &sol;> val binding &equals; LayoutRvItemBinding&period;inflate&lpar;inflater&comma; parent&comma; false&rpar;<br &sol;> return MainViewHolder&lpar;binding&rpar;<br &sol;> &rcub;<br &sol;><br &sol;> override fun onBindViewHolder&lpar;holder&colon; MainViewHolder&comma; position&colon; Int&rpar; &lbrace;<br &sol;> val movie &equals; movies&lbrack;position&rsqb;<br &sol;> holder&period;binding&period;movieTitle&period;text &equals; movie&period;title<br &sol;> holder&period;binding&period;movieYear&period;text &equals; "Year&colon; " &plus; movie&period;year<br &sol;><br &sol;> Glide&period;with&lpar;holder&period;itemView&period;context&rpar;&period;load&lpar;movie&period;poster&rpar;&period;placeholder&lpar;R&period;drawable&period;placeholder&rpar;<br &sol;> &period;into&lpar;holder&period;binding&period;moviePoster&rpar;<br &sol;><br &sol;> &rcub;<br &sol;><br &sol;> override fun getItemCount&lpar;&rpar;&colon; Int &lbrace;<br &sol;> return movies&period;size<br &sol;> &rcub;<br &sol;>&rcub;<br &sol;><br &sol;>class MainViewHolder&lpar;val binding&colon; LayoutRvItemBinding&rpar; &colon; RecyclerView&period;ViewHolder&lpar;binding&period;root&rpar; &lbrace;&rcub;<&sol;pre> &NewLine;<h5><span style&equals;"color&colon; &num;000080&semi;"><strong>Creating MainActivity File<&sol;strong><&sol;span><&sol;h5> &NewLine;<p>Inside MainActivity&comma; we will observe the response from the API and update the UI&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>MainActivity&period;kt<&sol;strong><&sol;span><&sol;p> &NewLine;<pre>package com&period;c1ctech&period;movieapprxjavaretrofit&period;ui<br &sol;><br &sol;>import androidx&period;appcompat&period;app&period;AppCompatActivity<br &sol;>import android&period;os&period;Bundle<br &sol;>import android&period;util&period;Log<br &sol;>import android&period;view&period;View<br &sol;>import android&period;widget&period;Toast<br &sol;>import androidx&period;lifecycle&period;Observer<br &sol;>import androidx&period;lifecycle&period;ViewModelProvider<br &sol;>import com&period;c1ctech&period;movieapprxjavaretrofit&period;MainAdapter<br &sol;>import com&period;c1ctech&period;movieapprxjavaretrofit&period;databinding&period;ActivityMainBinding<br &sol;>import com&period;c1ctech&period;movieapprxjavaretrofit&period;data&period;network&period;RetrofitService<br &sol;>import com&period;c1ctech&period;movieapprxjavaretrofit&period;data&period;repository&period;MainRepository<br &sol;><br &sol;>class MainActivity &colon; AppCompatActivity&lpar;&rpar; &lbrace;<br &sol;> private val TAG &equals; "MainActivity"<br &sol;> private lateinit var binding&colon; ActivityMainBinding<br &sol;><br &sol;> lateinit var viewModel&colon; MainViewModel<br &sol;><br &sol;> private val retrofitService &equals; RetrofitService&period;getInstance&lpar;&rpar;<br &sol;> val adapter &equals; MainAdapter&lpar;&rpar;<br &sol;><br &sol;> override fun onCreate&lpar;savedInstanceState&colon; Bundle&quest;&rpar; &lbrace;<br &sol;> super&period;onCreate&lpar;savedInstanceState&rpar;<br &sol;> binding &equals; ActivityMainBinding&period;inflate&lpar;layoutInflater&rpar;<br &sol;> setContentView&lpar;binding&period;root&rpar;<br &sol;><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;get viewmodel instance using ViewModelProvider&period;Factory<&sol;span><&sol;strong><br &sol;> viewModel &equals;<br &sol;> ViewModelProvider&lpar;this&comma; MyViewModelFactory&lpar;MainRepository&lpar;retrofitService&rpar;&rpar;&rpar;&period;get&lpar;<br &sol;> MainViewModel&colon;&colon;class&period;java<br &sol;> &rpar;<br &sol;><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;set adapter in recyclerview<&sol;span><&sol;strong><br &sol;> binding&period;recyclerview&period;adapter &equals; adapter<br &sol;><br &sol;> binding&period;btnShowMovies&period;setOnClickListener &lbrace;<br &sol;> viewModel&period;getAllMovies&lpar;&rpar;<br &sol;> binding&period;btnShowMovies&period;visibility &equals; View&period;GONE<br &sol;> binding&period;recyclerview&period;visibility &equals; View&period;VISIBLE<br &sol;><br &sol;> &rcub;<br &sol;> <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol;the observer will only receive events if the owner&lpar;activity&rpar; is in active state<&sol;span><&sol;strong><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;invoked when movieList data changes<&sol;span><&sol;strong><br &sol;> viewModel&period;movieList&period;observe&lpar;this&comma; Observer &lbrace;<br &sol;> if &lpar;it &excl;&equals; null&rpar; &lbrace;<br &sol;> Log&period;d&lpar;TAG&comma; "movieList&colon; &dollar;it"&rpar;<br &sol;> adapter&period;setMovieList&lpar;it&rpar;<br &sol;> &rcub; else &lbrace;<br &sol;> Toast&period;makeText&lpar;this&comma; "Error in fetching data"&comma; Toast&period;LENGTH&lowbar;SHORT&rpar;&period;show&lpar;&rpar;<br &sol;> &rcub;<br &sol;> &rcub;&rpar;<br &sol;><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol;invoked when a network exception occurred<&sol;span><&sol;strong><br &sol;> viewModel&period;errorMessage&period;observe&lpar;this&comma; Observer &lbrace;<br &sol;> Log&period;d&lpar;TAG&comma; "errorMessage&colon; &dollar;it"&rpar;<br &sol;> &rcub;&rpar;<br &sol;> &rcub;<br &sol;><br &sol;> override fun onDestroy&lpar;&rpar; &lbrace;<br &sol;><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol;don't send events once the activity is destroyed<&sol;strong><&sol;span><br &sol;> viewModel&period;disposable&period;dispose&lpar;&rpar;<br &sol;> super&period;onDestroy&lpar;&rpar;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<p>When you run the app it will look like this&colon;<&sol;p> &NewLine;<p><img class&equals;"alignnone wp-image-3144" src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2022&sol;03&sol;Screenshot&lowbar;20220306-175018&lowbar;MovieAppRxJavaRetrofit-498x1024&period;jpg" alt&equals;"" width&equals;"284" height&equals;"584" &sol;>        <img class&equals;"alignnone wp-image-3145" src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2022&sol;03&sol;Screenshot&lowbar;20220306-175214&lowbar;MovieAppRxJavaRetrofit-498x1024&period;jpg" alt&equals;"" width&equals;"281" height&equals;"578" &sol;>&NewLine;

Exit mobile version