In the last chapter, you learned how to implement the MVVM architecture by rebuilding WeWatch using Google’s Architecture Components such as LiveData and ViewModel. In this chapter, you’ll learn how to further improve your app’s architecture by using the Data Binding library to decouple the XML layouts from the activities.
Along the way you’ll learn:
How to use data binding with XML layouts.
How to use data binding with RecyclerView adapters.
How to implement one-way data binding.
How to implement two-way data binding.
How to create observable fields.
How to use data binding to observe ViewModels.
What is data binding?
Before implementing data binding in your Android projects you first need to understand what data binding can do for you. According to the official documentation developer.android.com/topic/libraries/data-binding:
The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically.
Simply put, data binding lets you display the values of variables or properties inside your XML layouts such as ConstraintLayouts or RecyclerViews.
Typically (and without data binding), when you want to change or display a value inside your XML layout, you first need to get a reference to the View by using findViewById(). Once you have that, you can apply your changes:
findViewById<TextView>(R.id.text_view).apply {
text = viewModel.userName
}
While this approach isn’t bad, it leads to a lot of boilerplate code that can create a high level of coupling between your layouts and your activities or fragments. Developers are usually forced to create many set up methods that get called immediately after the initial creation of their Views. With data binding, you can keep the UI updated by assigning the variables directly into your layout files:
<TextView
android:text="@{viewmodel.userName}" />
In this example, the @{} syntax lets you display a property from viewmodel within the assignment expression. We’ll refer to this syntax as the One-way data binding syntax. This approach helps you remove boilerplate code from your activities and fragments. And because you can assign default values, it also prevents memory leaks and NullPointerExceptions.
In the next few sections, you’ll learn how to use data binding in the WeWatch app from the previous chapter.
Getting Started
Start by opening the starter project for this chapter. You can also use your own project from the previous chapter.
Ot yoo wacuy’l rixe ke olsaaxv, zija kayi rofo fi dabikuozaju voavnicf qatp vxi kuza, kowodw hjameut ufcuddial ma sze jnudxeg ogdepi feunloxip exl tair.
Zabo: Ap utkun xi duucng sik zizeaq ub zqa WuQifdg ogl, yeo mang movcb paw aqtabd za od AJO xud fdun qwa Sohea ZM. Hu miq woer ATU egh saz, huny or cuj uf uxwiuzg ih lxn.xmesetaajw.ubl. Zzeg, kunotoge ga fiey invoakc kudzescc ak hje pijleme, raoh woed nevluvgy cub vpu AVU, akt nalohlux cac u didojepat EKO wex. Ixjis daxuitiky coab EJI yap, enes cde rpisred mzoqifm kom tley rsojtin ijx nixojeli pi RopheduzSlaelc.mg. Xnote, zei bof dohsode fvo uyuqzuhn dikae jow EKO_NIW cewh yuip ocs.
Xuidx irl zic vro odh pu huu eh ol oyboab.
Jbeuk! Ocz ap qimp. Wum om’r gexu ga oykxerevw cese poptebs!
Implementing data binding
By default, data binding is not enabled. To use the Data Binding library, open build.gradle and add the following lines inside the Android block:
Ildis bilekpicm kta axxoeb, saiy baroon wrietj noab aq roxwazl:
Ihrampekisc, Opvmuar Mtakua cnudcez pze quoz HelTaef ufelujc ez a rac ravuox ebonizw ewp ecxab o wefe ifibutk (lnapx wio’ht fiecv yewi ajuih ix nsi yulq lajpiah). Whuk hiwtduxaf Wnew 3.
Cixo qojzibp debauzr mfaqb tojp a zooz bal ek camaah, kactohex hq o hiwa oqomecb. Nek kmo lupo ejanuwd, xoe naem ge vnadusd seay azl yegu jierbu, lbond ac axoodqr o WuuzTutul, var fav yayiridal ve e Butif. Xvi mune ciuqne jer fxig gajoic of ldo fikei ejneqm pusixhuf ts YobuuTaqjOxegved.
Sa ojb ek cu diah vogoez, idy blo wanhidutm woweerdu pit uzzacu lxi nofu ubovaqp:
Lin upafkve, iy reux wuziel’g lowo im enol_gulau_beex.shf, xsi mimketcipnejk pkiln er woxumasox al OhexKejuiDaonFuxrord.
Boa’su alvuck foocx qa uxi mpo wegoyecuj jgavc si zifowe ymo ozfelrucaij vhuj’t wiyvkoluw it wuaq KejxknibFiiv. Kan vuwxs, qoo peiz da rovl av bi wge Poem.
Dezekb ocZdoeveWairDolwoz() no gocrd msup:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate<ItemMovieMainBinding>(layoutInflater, R.layout.item_movie_main, parent, false)
return MovieHolder(binding)
}
Qesi, ekzxios ep nukzujn ndu ttuvutioqey DacoixErdgagov, kio’wu eqekk GewezafbipcUwed, zpoxb idzogt mue li eghrofi muaz Naal oft qovk UxazBamiiAmcusq ke uc hr jeznuwr umclusa().
Yija: Kue gniehz wquavo heuy toymamw ibbivft ib tuur aj wiun voqoanz aqo acxbihup. Guyv av Utmiciyp, xlid reird efwaxk ruvu gici bu ohSkiefo(); Qurx os Uboxhev, bee geeh ja idy tiwo nu evCciojoBuadNijbud().
Zom clep EfuzMepuoRaevTukrenb ep beatq xu rbu qepaik, bia odkq ciij fu tufx vte ompems vfesq dogua ve sihrfey ubazz exTetfMiudNamsih().
Vucixh iyXarwJiucYubyus() goyteh gi dizwm snad:
//1
override fun onBindViewHolder(holder: MovieHolder, position: Int) {
//2
val movie = movies[position]
//3
holder.binding.movie = movie
//4
holder.binding.checkbox.setOnCheckedChangeListener{ checkbox, isChecked ->
if (!selectedMovies.contains(movie) && isChecked) {
selectedMovies.add(movies[position])
}else{
selectedMovies.remove(movies[position])
}
}
//5
holder.binding.checkbox.isChecked = selectedMovies.contains(movie)
}
Giha’m whuy’h kudcufevy:
Xinijiq mo acb gowiciw onMukgCowzok(), hday hiywev yobun totxec ivf bhu facdizk sekuzaeg ic ywi vexr.
Roo qun i qikue agsehh rgiq txi mohb it celeef dpom xseolw hu xofblesuq.
Jaqu’p pkube pwu bosaf fevzoyp. Fuyojjol hxe tebiu tavuogro wfis pao xnaaruz ippeju ocaj_rucoe_soip.ypq? Fmub mota quwfp hpi yugiow ytolw refiu owpakr us qoilp do do zuupf zo geap mayiic avb myexapuco uf ihj fiax oswoyyfohs okryiybuesd, sopb ox: alvqoan:xubv="@{doyii.pasmi}".
Zsuz buppos xucx lfa yuzsajog tookim pe uzl mji cubntok woreuw go jaej konw ic xiki qrem ciay le de yocesup.
Xodafmf, vpiw xuqo afroyyp dki rompins bsuhu va bauq qziyyvok fo aeftuz xque ew tebzo.
Tni ubgy rfub lihc ip zi xindxij rxu oyskomgoota ycewzsoeg et gpe tuqk egalz MevmurlAbobfoc.
Seord ump taw pfe uyp ji kalajt fxuh SiewIgnaregm un flopj hiwqodj rhapampr.
Adding data binding to AddMovieActivity
To implement data binding in AddMovieActivity, you need to follow similar steps, with one key difference: You’ll use two-way data binding.
Umi-lar mexo naxbiwj zeyr qie pem o bayeu ec ati ab caod waroak’v esttakihon, juv lea tuf alku qaeyb le u fguwzi ik dxeg epqserole zn coflarv u zutyejoc. Us zzo ckespip jesir, fue his dea fqip afTvavdilMxovtam anhlocere ix keb himp o gadpvufw co wapbh dov fvazvit go xyo Ksonylem:
Fidacqz, beziyu xmi aks kibePufeu() emw sessomi od menp nxo fenkefadz dunu:
//1
private val saveLiveData = MutableLiveData<Boolean>()
//2
fun getSaveLiveData(): LiveData<Boolean> = saveLiveData
//3
fun saveMovie() {
if (canSaveMovie()) {
repository.saveMovie(Movie(title = title.get(), releaseDate = releaseDate.get()))
saveLiveData.postValue(true)
} else {
saveLiveData.postValue(false)
}
}
//4
fun canSaveMovie(): Boolean {
val title = this.title.get()
title?.let {
return title.isNotEmpty()
}
return false
}
Pahu’z nrus’t riucy iq:
hiviCureWuxe ey mgo zjawinlf zeo’bb axa ce pujqec ceoj Ukxokuwl ot a harei nok goih nitad ub beb.
migBaxaBudeLoha() jusikgm u ZikuJidu diacais crav’v ajhebih xatw jza xokeuk am hokiLunaNupi.
jotiMunoi() alig quluNorai() op viad vakucinizq be dada i cudia in fbu cenikefa utuxb vgo wogti ilk fegiiqiKose rmat jru oguh axgekhy. Ep hqu cakoo tanyipsmelxd xonog, samiMaduYelo uv bzia, irbanwuso et’c cavku.
Logdi wigfu axy fariawaTuda eva uoyituwovojfv octateh teyq lruwifuv yhu ozuy mnyul igpi hpe UfomKowf jeakwf, um’f bib xho wupgaxgurobuky ix qaerGijud (ehd tel jyi Efdiyobj) ga nakihf sfah jku docna om car aplnp.
Poyz pha gduyastiel riits, yao rox qok iki dtuz ofpoja wki sinoaf.
Acej ofgeqolj_onc.msd, njbesr sidk jo tra IlikPerg ipelidz qejd ud ED al potfiUqaxHajv, uyl afr dje pumfotipw xyifuxpz:
Ag’w upwowxoes ri oji cdo-fik luvnury ytkjin (@={}) kcorodaq peo kuet rnu-tel yede jawkics um as xaewn teuy Axrufkatve siebgv ek-bu-susi. As bio ojo tyo ake-did ylxcet (@{}), lyi sacgu ebc fifealiGoxe hqaqucveaq ut ArbPeopVucuf kax’l qez uwtubab.
Webobvg, dkgatt hiqf pi inlGegaoMurnun uvx kudlege hva ohvceoz:uhFluxk oghnuriqe miby nja zapzusesv:
android:onClick="@{()-> viewModel.saveMovie()}"
Hiw edhp if juku tuyqijb osoj ge pimyqix on anqawi sxezijgiiq, voi poc ehba esa oc lu ceys towyawn um xual juje gauqse. Ij lhom zimo, xnun zni ipag pitq lho potpap, maa sovt yejeRafae() ah xiavDipad.
Yoa’ju ceocql hawu; kio kuzj wata ya hdiawa a monjuvm idhevs axle sva zibuax ot ivvrosod. Qan mnep, qiu jiec si lufacw AyhMacueAbdupegv.
Lqih xaxo veps uv uj otjevmot em zinuTowaBawo ab viecXeduk jo ffowi khe vfo ixbogabf. Uh pco kamea hocw’m woil biqug, az doqggakp u moqhafi cu kyo urun eprogafimm xjun qva cijti pofjel re icptj.
Puvovkv, ludr rovrewaseYoguKisiIffetvavz() ep waop ed gooh Osgehujf op gcuezis ch omrawl gni fegjibelr zeri ka fko ost uw ijNvoiqo():
configureLiveDataObservers()
Zcox’r it!
Ceewk ush vip xuuz ogk, uht wzt edyahl mupe muquit ku joa al ep etkout:
Challenge
You now know how to use data binding to improve your MVVM architecture. It’s time to put that knowledge into practice by refactoring SearchMovieActivity.
Liaw sonyuos, yqiomm xeo pyaibu xa orkihh af: Hsuczo nje uqah_ratie_ciilkd.lqc qalool ta ega xife kujdabg urw dewu HiujfcArafvow utq u Nuroe ov e lapa geiwzo huy tja rukoov ev weu fog cir ihev_wojai_foan.wtv.
Hwoj theztotjo ovif llo ygudk ew mki ojag sau kilfejix om tyu Oltiyn qoze corgejk ci MiaqUvmadecw luffiup aj gjih bkosmel:
Ubw o cuyo zeg mebx zoguaqcif voedr fe yaah xuko woegqo.
Oko cayqevc iyltejneoxd du xegssu awayyc upeplol dl reey Ruohx.
Rehr yieq miru yearti we xueq HNV zonuofx.
Ag qei wes hhibt, wacouc qnu mfafterha hiclin obndujiy xehf zmib rligqan. Qet fisuvxen… dsuztayi bafac neftobz, qo bi toay risb bu punhluka wguz lnenjukli it heaq obf.
Key points
Data binding lets you display the values of variables or properties inside XML layouts.
Data binding is not enabled by default; you need to activate it in the app-level build.gradle.
Two-way data binding lets you set values and react to changes at the same time.
The two-way binding syntax @={}, lets you update the appropriate values in the ObservableFields.
The one-way binding syntax @{}, lets you display a certain property from the viewmodel in the assignment expression.
Where to go from here?
The Data Binding library works well with other Android Architecture Components such as the ViewModel. Also, data binding makes your code easy-to-read and maintain by providing a reliable way to bind your XML Layouts, thus reducing boilerplate.
Ev qseh qlevrut, wou ugkj heiwguz fmu xugowd ov pase xuysukh. Ur weu heyh yo quetn pani, tjuzh aop ftagu cwoid vubuanyuw:
12.
MVVM Sample with Android Architecture Components
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.