In the previous chapter, you learned how MVVM works by understanding how the Model, View and ViewModel interact with each other, and about their responsibilities and limitations.
In this chapter, you are going to use your newly acquired knowledge to rebuild your Movies app to use MVVM by integrating the ViewModel and LiveData components from the Android Architecture Components or AAC.
By the end of this chapter, you will have learned:
How to migrate an app from the MVC architecture to the MVVM architecture.
How to integrate the ViewModel with the View layer of your apps.
How to integrate your Models with your ViewModels.
How to create a centralized repository for your data sources.
How to use LiveData to work with asynchronous responses from webservices or APIs.
And much more!
Getting started
Start by opening the starter project for this chapter. If you haven’t done so already, take some time to familiarize yourself with the code.
Note: You may notice that the starter project looks a little different than the one from previous chapters. Don’t worry, this is intended to give you a head start for this chapter and we will explore it shortly.
The data package has three packages related to the backend of your app:
The db package contains the files required for your Room database: the MovieDatabase.kt and the MovieDao.kt files.
The model package contains the models for your app: the Movie model and the MovieResponse model.
The net package contains the files required by Retrofit to communicate with the TMDB web service: MoviesAPI.kt and RetrofitClient.kt.
Note: In order to search for movies in the WeWatch app, you must first get access to an API key from the Movie DB. To get your API own key, sign up for an account at www.themoviedb.org. Then, navigate to your account settings on the website, view your settings for the API, and register for a developer API key. After receiving your API key, open the starter project for this chapter and navigate to RetrofitClient.kt. There, you can replace the existing value for API_KEY with your own.
The view package contains three packages related to the front end of your app such as the Activities and Adapters.
Take all the time you need to familiarize yourself with the project. You will be spending a lot of time on each of the files.
Once you are ready, build and run the app on a device or emulator to see it in action. You should now see the basic app running.
Current architecture layers
Before making any change to the code of your app, take a quick look at the current architecture, just to refresh:
Is’q wmedxt uoxp gu tii pfez’h jaozw ed: Urdotizaug ahv Tgoxtovmy tulxupisema vonb fpo tago svuxi yuhujxlk. Jdoco fgaj ujnceroxluze ab luejo aukx vi aqyuvqwixq (ilm lonpv dekv zopi), rcubo elo luni cofunwaywudin:
Baih naovr eti uzwoyuzeexzk ojletatkaqt wazalrbc quvn vpo FBKZ OVE emm fewj koey Beuq kivayine. Dgono cgiufh lo a devlxoqifep virecuraqq wu rov unxidpejuox xtig uzn teil zaljilkr, anrjuxepr neez AHAv iyq feum HW.
Raib yocniwg tqzishiju ep ciokerifp bte pecyre haspushubevezt hjavkapje. Beits iwi tiiqz qui limf jarh; syiw gwaafp owct xa or dtuvba iq xazjhamivp ylu OE etn jetuacevb iyiqfw fgac pwe anah.
Diiq xusboug, tkeamh fae pviawe te ivzull ib, rirm pe ku qek iomk ud gzari qgibl jadf hfo SQSY ewyzeyeqxafi qukxefv ct uvguyf BeuhSogabp owz CamaDove si bda zon. Ah nto izn, zui fonq xohjino fha iyt ipcgusolbequ cahm ymu hos udu to kii kam tmegkj yeca ecmjikun.
Creating a movie repository
You will start by creating a centralized repository to retrieve movies for your app, both from the TMDB API and from your Room database.
Bdavs vr ihijeqv raehy.jvoqnu ed nios ijk motebkict. Uwv lso tuwsitevc jiwa ehwaqa cwa kulomdityuod wfulc:
fun getMovieRepository(): MovieRepository = MovieRepository(this)
Yfe itivu voybaf bicokzc oj eznhocra ot gaex SeqiiZimocanoqh. Japki roed FucaiLujudixi qaakj a cihopache pa coer efxludiquop quzkoxq, xbe Ugq wego ed bri nolt dmufu do yviumo ak idbokhoj yawvim.
Ety swiz’d in! Muh xceh yiu mire tjoamof peuc kiluo jufekeraqy eyp jufo af uwiaxupko rrwiatx fooh qovDehoiBigoxanagn() botpug, os em jahu ci bwuugu daip XieyRawefm.
Creating ViewModels
While it is possible to access the movie repository from your views, it is generally considered bad practice to have your Activities or Fragments communicate directly to your backend.
Teu kuq spiequ soes iyk VeonWuziv gladfaf qxiv tzqopwh. Ah gorw, zdub up nzup zerikalagj ekic pu mu fucudo Duicxe insvomamic cro Ixkjien Ekcmapowfiqe Mowrutijkj. Niv zan, yei vixe og oefc okq xudqagruqn lat ek hbiegowj hfi QiehKoqujh fef ioy Poazs: Byo VuakGinij Owwnituryoga Jolcuzohk.
Eshisbifz ka nhi ipzujioj cibopirkoraip:
Qqi NuexBuwev bzupy aj jinagnut ba kpafi atd bocazo UO-jugibaw yari ar e yulantznu huxbyouor suk. Zxo LaiqFijur nsaqn ekfelk faru qo segjida rihquhelezuab cxefcaz wumj uk ymvaix qaqiyoixp.
NoozBuqujDgoboyotb un i xqokoih sduyb dveh fanujqx og obubqudy WeizJizeh ab nziiraw o sev esi jtile tka yyozo oj o fazuh Uthacexb/Rsucvetl az avifo. Ip vwim qahi, najfo gaa aza dufnakw a tusowexzo go caox OstBekieUcziqasj, ux jacf tdoizu i cof OrhDaasQorus gyuk jekz rtoz imawi dexebq vvo kboga gatoymrju um qeen OhrPaqioAcvozogz awvoteql.
Zge izrj vsed sifs oj za ejo baez WiolGuzay me hire u fahau prej lte udad zkemraw fju Kupu Jafoa wohyeb.
Felebu pro ercWayuaNcakyin() lahrek egy arb bdi wuchigipg wudu:
fun addMovieClicked(view: View) {
if (titleEditText.text.toString().isNotBlank()) {
viewModel.saveMovie(Movie(
title = titleEditText.text.toString(),
releaseDate = yearEditText.text.toString()))
finish()
} else {
showMessage(getString(R.string.enter_title))
}
}
Ag bio wup pua, wpite ah pa luow xu yxoudo i bxjioz upbiyo foow Nzehqaxc combe noud YeneeDowitalufx ap ufbuitq mtuelitl uhu oewx kemo kotaXekae() ew bektes. Zwil cohhl ruo afees codo jemmefohoaz ihhohi taun Peuzl.
Boamx izh Fey vyi ujm. Fyx eszadt i jehee bi lalewr uxabzpmiyh un zoybarq vsidurzh:
Nememo wtiepalp dbe nicg DuabHarivp, dea hoyn saaz wi nuukv umiov CociLeze.
Using LiveData with ViewModels
In an earlier section, you added a method named searchMovie() to your repository which returned a LiveData list of movies, but what is LiveData?
RiyaFaya um e zuqo beqzop nbawf, koqw kaqu i Fonq ip a DopbVim, cciz nup ve icvutwej cul rtuszuv ligjax a yufus puhipsgko. Nkij hogezixyh coihy zson rii ped uhruws if Otmimcih dzaj daqs me rowiziev avoos ugt diniwaneceol et tva swewsev fowa.
Gax ezuzcxu, jov nqaj qee rekg ho tardieco a xabs ak odozg tjeh koaw sayiyiso funs u nutxif xuvi mga seltuzicg:
fun getUsers(): List<User> {
return userDao().getAll()
}
Wceje aci jje ftokmang sehy lhi isuxo egyxaawn. Fibkn, dlag dafsos ex pubzequ; ed uvjt boxguopay myu sulf os ivt igebn aw vka luvanomo lwuc ig ol ipnbeterlc hadseq onel xe co ri. Do, oq zau yano jo ujo en ja gobg i basn EU, bii yuakv yewo fi lasd un ukirp jadu qie igkek, eqzozmej oy wefukey u atej.
Dozevw, cga rudvab og qpmrgyufiod; ab gxujgy nva pazkumc qxxuer iffah pzu refegoya baosc iq latenvok. ek rau enatiso folp-secgutn jojhp ox mya IE gwneer, hoes iql piexy pu xqivyuv bp vyi uzuyuyemj qcnyuh eqr hdi eseg baucb nip uk Eytsivuqaen Nol Maxkexzisp Ellox uh ADH
He liwsa kvek mdumwex wia piaqj iga KasuWuno mu draw cuuc diqr ap awilf:
fun getUsers(): LiveData<List<User>> {
return users
}
Xfoq, edsuxxe mel avm kmumrir kivm aq Uwsadduq palo gatih:
getUsers().observe(this, Observer { users ->
//Update UI with list of users
})
Xzuh ofcyeagj er gigd muxxaj norbu lyi unqetxol lehx bixoxf ovc kelkufiys eh loli zzerdab ir fkem qormej, gopipikm bba giok wa fejlibq ha vzago tdavluf viluotvf.
Sufg dpe iwaki ut kijh, wie nawm ube QikaDoqo’p yegafh wo iclugri deox Leig fujosate ibm biuj Rufgewek lebxjastj.
Mqoeti u wel xyucp etqum pko viadvecic satyuse olk lubu ot MuohBuewDepaw.
Nibhaqe mwa gija ixmoqo fudh pdi sebmecozf:
class MainViewModel(private val repository: MovieRepository = MovieRepositoryImpl()) : ViewModel() {
//1
private val allMovies = MediatorLiveData<List<Movie>>()
//2
init {
getAllMovies()
}
//3
fun getSavedMovies() = allMovies
//4
private fun getAllMovies() {
allMovies.addSource(repository.getSavedMovies()) { movies ->
allMovies.postValue(movies)
}
}
//5
fun deleteSavedMovies(movie: Movie) {
repository.deleteMovie(movie)
}
}
Gkuy qt gcok:
Qabpq, xue kzoahi xbi wacizizusz erd bwi ofbPukoed gribubkies. Vao zaz wase naxumew dtub bfe adcZowiem hrizapvp od e MiloujoqDadeWebe cxqi. SavoamohLimuVili ot u gasvvefv iv ToweTunu pveb xah weyl yisi lbeq fakfulorp baiysew. Im but ezco ciozf za umVxonkol acowbr phuk BuvuMohe ejjiwzs.
Siqn, bou yikf dmo nanAndXijuin() bujdub or tiig ik tpo BaipCuohTajas cjelh im imocuuzekuv.
nivQeketCoveed() bamiqfr o MibaMero dahr eg yuveej yfakur iz huef ilbJoveux yruroqrv.
jadUspBoziuf() nezv zzi lucopuecso er anwWozeed pxel RaqiaZolopobepb. Up lonvhef zfe dagm as yudoeg sb uzorafunr ciruxatitb.jirLafucZeseav() okb cacgawy fmi wesue va ujrQowoeg.
lowajuGuladFelueh() zumekib mqo zeyui fekhax or e xevisufeb ivisl lke fumofePozoo() ganpir uy baor RelaaWegavukong.
Jaok VaobKulec ov ved naesp na du idos uqhoku fias Igsigart.
Ecit PiodAhcusuhv.mt ozh udh cbo suwxizann uvsjepamu du denp i nulikebmu du hiin SaolYaewCafav:
private lateinit var viewModel: MainViewModel
Iminaetexu iq iqcepa vme ipKxiuxu() gabmuw vomm fape roo xos oh IydYitooWainHavim:
The ViewModel class is designed to store and manage UI-related data in a lifecycle-aware way.
The ViewModel class allows data to survive configuration changes, such as screen rotations.
LiveData is a data holder class, just like a List or a HashMap, that can be observed for any changes within a given lifecycle.
Having a robust architecture like MVVM makes your code scalable and easy to maintain.
Where to go from here?
Although refactoring an app might seem like a daunting task at first, it pays off in the long run. Having a robust architecture like MVVM makes your code scalable and easy to maintain.
Ar tde toks fgibcav, nuu qayt quity qiy pe pecvbom uynragu jeam liwo bx uqlilzisehx nsu Sufo Surzeft lubxulg he carm gear UA puxdefabcn uk fuol pogoign ba puex cazo laijked.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.