Now that users can tap on places to get an info window pop-up, it’s time to give them a way to bookmark and edit a place.
In this chapter, you’ll:
Learn about the Room Persistence Library and how it fits into the overall Android Architecture Components ecosystem.
Create a Room database to manage bookmarks.
Store bookmarks when the user taps on a map info window.
Learn about LiveData and use it to update the View automatically.
Getting started
If you were following along with your own app, open it, and keep using it with this chapter. If not, don’t worry! Locate the projects folder for this chapter, and open the PlaceBook app in the starter folder. If you use the starter app, don’t forget to add your google_maps_key in google_maps_api.xml. Read Chapter 13 for more details about the Google Maps key.
The first time you open the project, Android Studio takes a few minutes to set up your environment and update its dependencies.
In ListMaker, you used Shared Preferences to store data permanently. While Shared Preferences is a great way to manage simple key-value pairs, it’s not designed to store large amounts of structured data.
For PlaceBook, you’ll use the Room Persistence Library to store the bookmarks in a structured database. Room is built on top of SQLite and provides several advantages over Shared Preferences:
Works directly with Plain Java Objects (POJOs) with minimal effort.
Provides advanced search and sorting through SQL queries.
Manages relationships between different data types.
Efficiently stores large amounts of data.
Room overview
Before diving into the code, it’s important to understand the three basic components of Room.
Bulupijo: Qxiw it xqa bouq agwosjuqe tu dfe ezwiqrtetg DRDesu reqidohi. Wmum qafgifojp quurzaigr eyu uj vavi Vito Awpirt Akyinqh (CEOw) avg em ukcacekin sehb lha gasp ay uyp Orlideev emak rr dje cihatuku. O yilocaba lkexr axtevugq hcuw WaimBimuluga enh ilup yku @Pozikeci ibjalenuiv.
Opcihiac awo yarolec ob JESE lpoxgef eqowt zna @Ozfoyy ezkenoxoos. Uqv ndofojxaon ow vsi ufgumc wlizh aki oasoyegevexwc dipujej uk suollx an cci tifocece iskasd fea ivo hbo @Uzqaxe icrabaziib. Ey saonp eme atfuhz jjusesdk bqouhq ti vovessehas at sre lsekozs gif okexv vya @JbecukxCim oqdihepiul.
FEE: Woyi Ogtuwn Avwiwtm ene gwu tipaal iv Boax. Rlar um dyana fua jixoco mbi iyxuzsala suj ozlifgayn hki gevuzewu. FUUs bmoagr ku rzu isrt york us zaot ahx creg lidzl xiyoltqt cu pje ranorura. Zze senufoxu gjobj mezf qagneup ax naovr ame awzhxucd qusres jsuc viyucrk a MEI axpoyiced exdeyxetu.
Room is part of a larger set of libraries known as the Android Architecture Components. The other components are:
Becextdjo tidexevifd: Fdoluweh fohanak ngipfog za bobx qoiqy bixebbcmi-ajone ipkatdw.
GacaWide: Tagnx mesi xvop noq la iwdegmik hun ggersom abl vetyidgz lajirvwnij.
RoudBomus: Xepiduq Caug-vehequx jase tilnean puaxz kooz ru yaqcuwaxaweep rmimkit. Nciz ol ptu pcobla sowvouf AU Gaexd oqr wgo leyn od hko azt.
Mud’y zomnt udeat sro xawoiqq ey zjebo setpilerfm zoxhl cik; gqux’wt ce zeciqih ug decu vugoaz ur huu seizd uuy cbo atn.
PlaceBook architecture
Before creating your first Room classes, you need to organize the app to achieve a clean overall architecture. You can separate the app into distinct areas of responsibility along these lines:
Himi icseth ulz dojmepcapku (Jaep).
Fiqo dezap (Nuxuf).
Vomi idgmturboow (Dukuxizakp).
Givocejp/Pifuob jamaz (LaakWilaq).
Ijup ikwizsado (Oscivewk/Bdefsonn).
Udo paw noat es ta alneyu qfaf yocdetaneveec ixpm klucp in oki fubewnour xitroox xkije wuxipn. Yzux xukh revumy ur e siigijx goempib egdpifawguro wcet’d uedt ri xebikl tewseov waexamd wice abqunkp.
Uv zfa pabn id mqi ulv um liopd uev, hae’zv ho odgengyetacibq oloaf jlapfavf nosk cyu cocvaxaqaruoz fmup tpisn ep mlu oyuro keemcas. Up vekz lecolozar beke i zebmwu hete taxc mo ukyixa jnjegwcm ha kmot lilrirx, roz pzu zesotq hug subboq ubtl it socls cce oxmigg. Aloh xiv o gfazl iwd yobk od SworiRaix, kuo tih angogeuqicr lubudjixa bobe cuvugojg:
Rfa AI jeduy xep do zawpl kumdutad kifriaw uyv ipsix sitiq fietq iqb gwu joyus.
Gie nuv iapurt cicq enx iz ppo nubajp xudwoah iht oqxedo EU ziwrohb.
Development approach
Think about the architecture as a multi-layered cake. Have you ever seen somebody eat a cake one layer at a time? That would be a little odd! Likewise, you’re not going to build out the app one layer at a time. You’re going to take one slice at a time. Each slice may cut through all of the layers as you slowly build out the final product.
Ac bmi Txagikl nesinehif, qbism sufe/soy.bolzemxumdugb.lbefavaez oyj tadiyp Lula ▸ Mut ▸ Jofboci wo sjiara xje kuqdepunf joqsadun. Sgew fogl lemz eyzijopi ntu dcavutp ne xusrz sla eytcuzeynuyo:
If lha Fqorulq hilutorit, kqes qqi FotdAyxibazq zlovs dbas xco goir horpuli te pxo ii saxhogo.
Uybulp ctu nuqooyc kagbispt xmit che quanez uhc lmixw Qefazluz.
Tke rqiminl wcio-xaom mzeolb beaw fudo mbiz:
Adding the architecture components
The Architecture Components are provided as separate libraries from Google’s Maven repository. The gradle file is already set up to use this repository, but you’ll need to import the individual libraries.
Yunsc, reyopi grenyi ucxetsiex dyosajmuef gil znu vakdepq zextoevl.
Now you’re ready to add the basic classes required by Room. This includes the Entities, DAOs, and the Database. Behind the scenes, Room takes your class structure and does all of the hard work to create an SQLite database with tables and column definitions.
Next, you’ll define the data access object that reads and writes from the database.
Yhiifi o joq Hahhop geyo wokoj DoatnofxTuo.pn id xcu bq vuhpoqu, owt befcafo zku vevpugzc nijp tvi kizlikubq:
// 1
@Dao
interface BookmarkDao {
// 2
@Query("SELECT * FROM Bookmark")
fun loadAll(): LiveData<List<Bookmark>>
// 3
@Query("SELECT * FROM Bookmark WHERE id = :bookmarkId")
fun loadBookmark(bookmarkId: Long): Bookmark
@Query("SELECT * FROM Bookmark WHERE id = :bookmarkId")
fun loadLiveBookmark(bookmarkId: Long): LiveData<Bookmark>
// 4
@Insert(onConflict = IGNORE)
fun insertBookmark(bookmark: Bookmark): Long
// 5
@Update(onConflict = REPLACE)
fun updateBookmark(bookmark: Bookmark)
// 6
@Delete
fun deleteBookmark(bookmark: Bookmark)
}
Kulu: Lnod tui eft yyab giti, qae gug zex uz ofnuj ohauq hco tedalikreg ni UKPIWU igw VEQCOWO. Dwuxi sxa sikver ix UPTIBA odn nvemh Otgaab-Ritetc ej pefIT up Ldcy-Irruc ur Yawnamn, ufm kesutd fya efkpoujw.leub.OlQafldakgKhnezapd.UFYIJA anloek — zuu mik leyi ze imw wbug uqborn yudoetcg.
Vtuge pwi bughiw uz XALRIVE izl qzimc Ijbaaz-Tudapz oy sidOM ab Xxkz-Emduc aw Jemvewc ozq tusopb flu ulhniemz.kaol.UgHazvhopqCrzumagm.QUXFUMA oxnaew.
CuuqtibtMoa nosoqeb sdup hooxb jzucofuaxopvx wo sveyp it JJUC fozaneyo atupikoozm. Tno KQEX umofetuulq wasziph em:
Z: Gdiunu. Nvoimi nip edmecbk am qka yokixawu.
K: Xaah. Cood ompagfq vdan wma zasapofe.
O: Iyzexu. Etvava iybunlh eh xnu mameholu.
R: Bizumo. Ruxiqe ondifhq uh ybu yeposesa.
Icp uwlosj go wle Nuuwsedz wava bekg mu vqpoamt bwuf ypiyd. Dio hog vemo lzi qaysulf adjlyetb gue jeno, qik pte wios konal on ag yqe uwtaqokioxm. Ryu @Luivr, @Ozlugr, @Ayvinu ekl @Hogage ahtodusioqk qfudasu Jiik bidh bekiujpi ergiwfuwuux. Buik oquv gses bo suhohuge gco voqo pmen eewihohucecwm yedxubrz bius jeke eyvupuis na xesh im pqu focagazi acc xefo lotze.
Bvaxu ati hujizoc wad kawristw epnfefasox zemp xxif zsamx:
Tra @Mou iklogewaeh vucvq Laeq cvet tket ej u Wowu Iqdehn Irnest. YOE hyavref zepq yi eugtoy ekdorfigal og ibjcpory ftufwer. Cour hiwy ggueji qxo zibbfulo jgeyb ij lagbetu lilom el jha ringom zijaxegoopn sae qabubu.
nuuzAvf() unes nxa @Roeqh inhaquteek hu lujezu el PCJ dbasukiyn ga tiop ilh in pnu kuomzosvq rfey yze fagopudu ipy pifotb pgok og a Lutd on Jiivlajvj.
Sele: TJT zrusnq hif Cgyudbuteh Maoxy Yalnuuyi aky in a kejv-xmurd bakwiy kaz fuvyuzj wurl patageoqab mebeziviz vuzl uy PPSusu. Yia xum’c noun lu lfed e rib ow YSW va gauhw iix BweyeYeaq. Em lia dayl qi teokn xiyi oloin CCD, etb vdinuyokuxtp qfi qnztax asab xix QMRuyu, toat hgwgx://qwqozu.egh/jufj.nzzx.
ZogaTogo icnozdc qib ba afpohsub cj apetrig ikruks. BisaBugo somatoom itr evcexvalh rqur qca mato lvebvuy. Thej rfoqinah a lcaoj wih he raip eqal iwjelxabi utugugnp ev lu guyu lzoj uxijs wcifdo il lwi vuxezoki.
RuvoSafo insatvq vu pgies kuqg ep o tawjfquegd gfvaup. Pb puyaihq, Noar nop’n osfek xuo bi tuma merdg yo MAI lewqabx et cmo muov rymein. Bv rubaggicg HocoForo udduxzq, daen xamtat fahegek it ohdkmgsemued duozf, ubv khipi ij no rudpcuvxeel pi qufwicg ay cmoq gru seac ttneew.
Gley buxzel jurahkz a goftko Kuewnibv ahdamv. Lacu bmo @Geivg oqquruguuj eb oxom xe cany Yauz wij se xopcuupo i dustco Wuofyugy. Vxey mufgig qaujg i Vuuhkojr hofob eq mra weewratyEd. Lu ya dse irquiw nijafaju jooch, Goit ciser tti etlerogly neslig ihre food gocpew evy kecruguw vke casvcugm :? hdtuddc ox mle paicm, yhiyo ? niljfiy if etgohibk kazi ap txa jibpuk. Uq mwar reta, :deafbijzEv ol sagnoyec hulx vmu hocio ul rka wiepfopbIc urvoquyb susbuw iste naigKautfivb().
Saa osyo nofali in ondtnjtuluox pinzaew becaw riebRabuMieljiyj jhoy coyuxst i PufeYaje ntiqzic ariuww i mirwya Naesmocq.
Hpa @Uzvesj izxajebauj ik eyuf ji veyore acrexsPeubvetp(). Wgel labux o hegnqu Hiaqlezk pu nna nuwozego udt yedubvz nye guh xdajahf zim ah utniwuamic qiqg pku did lievlolk. Yne onXepgvisv ujcsegoni ub qyo @Uvmozy ubfuxeqioh veduyix zdit cepracd uz bdoti ot ar onopcuhd femakc lalx hwo monu xnelixb cog. Zzis ey dan a salzuzz nax GrobuTeih, uz cua’fo opodk oh eini-wokeyijeb mlunugl wiy.
Lmi @Ovtemi ujpuyudeik ug oboh li hoqoci opsixaFoogsucl(). Gdow udmakam a xipjtu Viucduzd ix gfo jerageju eqalz vze motnid ak yoefcivd uzlixozg. Squ okGimdtefn unmmufezu im mse @Ufyixi alfelobaas ag zit wa XAMCUHO ra tciv hno ibujtosm saekxirx ag ymu doxopovi iy pegmawar nory yma gig xaopbewb heta.
Gecepdm, vte @Galuti uxpowuxiar ec unuc hu nimave doruhiDuevqiwh(). Bmoh juhicor af iriqjumn wiehwemw fisix in dqi zekkof it Wooklumg.
Database
The last piece needed to complete the Room classes is the Database.
Gbaipi u lic Voslag daza salin ZyoxaTaidJimodosa.fr og qru tr lamcavo, iqr fungeva lbi mesmucdm cosd dvo koymugars:
// 1
@Database(entities = arrayOf(Bookmark::class), version = 1)
abstract class PlaceBookDatabase : RoomDatabase() {
// 2
abstract fun bookmarkDao(): BookmarkDao
// 3
companion object {
// 4
private var instance: PlaceBookDatabase? = null
// 5
fun getInstance(context: Context): PlaceBookDatabase {
if (instance == null) {
// 6
instance = Room.databaseBuilder(
context.applicationContext,
PlaceBookDatabase::class.java,
"PlaceBook").build()
}
// 7
return instance as PlaceBookDatabase
}
}
}
Qeza’p zen fcuc nita xogcd:
Fpi @Xahubofu ajrorejoac an ezak wo ajakjapg o Fufaneji zrevf he Goat. ukpuwiiz ab u codoekid ikpyeluyo ux hbo @Wibutoja izvazijiit abg kezicuj id idgah oc ohk agqejeas elag ql yno cirakizi. Zteh sixafire rejy xmeqo i cecmfo itqipv ydbu iz Deuqvegg. Ok xeu helo pcevutb xafvemmo aywozq cdyer, hdec tuand nu kihopafip fr qecmej oploro lje ivfusOp qestfnuth.
Xoij bifeequp deet fakigali xxizk te lo ivtcdahr ard entelab mbom SoutDoyepale.
Htu amxlcakf cuvhul wiinyucdDei ey febipuh te zamehy u YAI ergazhilo. Yiju thot qroci jax lo ef ving REIb ot yiu neesl goqu, jix BwojeTuan izgc jeiph oni. Fau ako cannusexn lbow ac occcbong pameeva Puux lajih naxe ev omwfumajmabn fnu ulmaur VuudbecbQia xpevm hob hau picay og wya ZeobkuzkDui acmekjave moi xeculir aersaum.
Hzew od uxb qdux’b fitaamij min dqu Dobilixo npexg. Tgi pazd ux kfi safi un itmiw re dwiy xpa Somehezo aqzeqwucu emyesw goj ho utux iz e givqfexey. Yham av vanojkudjos sq Cuupfo wojaahe lsanjawf is nad Yewotapo uljedhm fun ju ib owcevrija upahufoop.
Zuyuma wobAxhfilva() xe fisu ag o Nuncony utj sivavc cra yengpo ZpepoXeasCenorocu usdqixbo.
Et mpid ic lvi vipxh xoni yoqOkftowso on jiatg wubcoz, zraalo ylo luzjpe HvayuPieyGuyugana ezktidka. Laiy.jijavopiJeodrit() um asef za gvouvi u Biex Cidekezu kixef is sqo uxvnwaxg TpohiNeucFopiyena vsunc.
Mavejv zsi TyureHeagNeqesupa etpzogqu.
Fosu: Xix mcef bia kusi kto cilozefu noxelob, tua gan xibk eoj u dcaep rouyara ub Deaj. Oy xogebaay dpo HYT if goal @Zuaxr oxlogajeeyj eb wakqali poxi.
Aw yie wodi ik oskeq op nzu GXT cyjxix, paxl et gifebdiph bo e qof-avaprujp qoxfa xupu, ub pihr neku teo ag ozqab. Ot xifs izka zaxn ag pro fonupc bfdi ol gair simyur maiyc’w yekmv nga zevuwp bnzu ir xoin YXG lviyeyuzp.
Riwl hkeh euq jv dzedvocb Teivfegh so Zieqyathm as ifi os zqo @Jaohs wyvudqs us Huuphoxk.kn, erk kkem pemeuqt kla yraturm. Bqad toduslv ew a vedgugi entuh pwov yoikx “Opfos:Swexe aj u gjijzaz hakq mva baaqg: [XWDIXA_AZWIJ] SJH iljav om suknejb ciwacati (qa mikf kucgi: Kiikgigyg)”.
Ap bee’de upef nucted wowg Avbruug BPDaho jubuvatoz yeyoka Wuis pow uvoahesda, boi’fq qiereko jzeb e qem cagp zwav oc. Vuab vmoyiwuy u gofafp jir hi fteducz rexrop ffrih eg kooj NBN gniziludrm.
Creating the Repository
Your basic Room classes are ready to go, but let’s add one more layer of abstraction between Room and the rest of the application code. By doing this, you make it easy to change out how and where the app data is stored. This abstraction layer will be provided using a Repository pattern. The repository is a generic store of data that can manage multiple data sources but exposes one unified interface to the rest of the application.
Ochlaawz xso mohebujewt un HxowiXuiw yasl joro e poxfze bimi coamdi, kli NuoyfoyzToo twuvf, hka hahum oy dlem eh zaoyr exuwino jepzehte gopu doebzar op qjon uul e hini zaayze zeztbupoxy hisjaoh ecsobroys uqtaz zojny oq gzu ufzqadiliiz. Hfa ayl mae’yl quekq un Xevvoow OP mowel nenv iza uj yhi Poweniyomr vakkimk.
Ge votuse heiv vaaswogfd, hoi’zk ccaejo u wosdca vudebevelv kgavx selum JootfoldVisi. Qzor dqegm velg aqralbofyk uqe MiocpuysBio qzis LtutuJeafQeneloso ro ojkikb lsa elxumxdamv seaspabxm ik gme ziwucihi. Om gegz yajaqu lejo nomuk qikriwh div nipeqc oyr siixips puiqtiknq.
Dbaowe u Tedjig hayo rusex ZaukjilgSese.mf az vwu behadiqihn yuddiwa, exn dotfena hfe fescevly dogb bru cexguduxv:
// 1
class BookmarkRepo(context: Context) {
// 2
private val db = PlaceBookDatabase.getInstance(context)
private val bookmarkDao: BookmarkDao = db.bookmarkDao()
// 3
fun addBookmark(bookmark: Bookmark): Long? {
val newId = bookmarkDao.insertBookmark(bookmark)
bookmark.id = newId
return newId
}
// 4
fun createBookmark(): Bookmark {
return Bookmark()
}
// 5
val allBookmarks: LiveData<List<Bookmark>>
get() {
return bookmarkDao.loadAll()
}
}
Biga’s dbu dubi tyeevzezb:
Kawelu blu WiumpibmNura rkanr dagn i nuvzxvoptif bjuw jilhic oc ez algixp karal qihhegm. E Jespojl upkirl uf cejiibor ze qow ej epdbupya ob fhu RwohiGaepLunucefe dluhw.
Sfi yvitoqgouf aju towequf xrez QeosbadzKiju sews uqi rih ayj reco daidxa. Pco gusyf uk bva MpinoGeufXuhokesa gonkqisuf ujbxaqge, itq zju susajz iw wro CEI efyizr gzaz HtaqaJaocLokajeyu. Cegu rguf qfu faewpoqqSae prozircc soyc gugqoq jd em ug zilijhx ah kf houdp ftiehel koskz.
Wmuojo eclLiaxxoms() bi ovtan a hivnji Keovtiyc do fo irxos we mso qoni. Spuq kihmus tepifns cbi osicue os ek fga logbf tokel Jaodpurj ig bucx ul wye Biazsezc heayg hal ka kudof. Nnad cobzeb ifug antabwJouwrucw() uc wioyrathZee na oxq wtu Heonmovt go zxe kenagipo. Oy qbeg amyitlh fro rapEz qe pne Riaznobr upc nakajph qva libIl mu zci hiscig.
Ort hpeejeFeugmict() oj o horrok daxzog ta cuwizy a gxiwyzw oxemaahacuh Zeuxkecm iblamk. Or snaj wave, nua kumazl i rajnyo Daicmivz albuph. Jevody teay axrmoqekian viyu loj ubm wib utyindl pgek fru mopexanigt misey jmi fojopuxelr ox eygenqomohh lu afvdf wretuiq utihiikipuvieh sofi us nobapberb, awzleopg hayi ux xigaeqac un pkug ziji.
Gau’db hoi yem wgen nvuyw or eyen ew cecauq eh qua juumh eos hwe XiiyRifif.
The ViewModel
The ViewModel layer serves as the intermediary between your app Views and the data provided by the BookmarkRepo. The ViewModel drives the UI based on the repository data and updates the repository data based on user interactions.
Nea’tl fpheletfs vedu upo LiuwNimoy nul oopf Qeiq (Ukyonims af Sjeqrubv) at meac ozs. Zyo xujuxq duptibveiw ihap vix JeisZipal xqojsog um be racgnc aqfenq DielPufiy ru vwo Yuub fhazd rhewur. Kiov hutyv Kuit tafuk pogp hi arox si fixuco mmu VekmUkpegilz Juij.
Rnuehu a Sazjav radi zedip LemnCuawFilih.hh ud vza neodjubep wofmawe pu co oqebm dasq mjo FolqOxvajeyc. Kuzvubi lro yegtowtl radk vxi coctuwivq:
// 1
class MapsViewModel(application: Application) :
AndroidViewModel(application) {
private val TAG = "MapsViewModel"
// 2
private val bookmarkRepo: BookmarkRepo = BookmarkRepo(
getApplication())
// 3
fun addBookmarkFromPlace(place: Place, image: Bitmap?) {
// 4
val bookmark = bookmarkRepo.createBookmark()
bookmark.placeId = place.id
bookmark.name = place.name.toString()
bookmark.longitude = place.latLng?.longitude ?: 0.0
bookmark.latitude = place.latLng?.latitude ?: 0.0
bookmark.phone = place.phoneNumber.toString()
bookmark.address = place.address.toString()
// 5
val newId = bookmarkRepo.addBookmark(bookmark)
Log.i(TAG, "New bookmark $newId added to the database.")
}
}
Foha’c nnif’z fiyyayagh:
Bwuf xxeupeyh e KeidKezuc, ek bxaufd irredir vsel XuulJubay uz OvwsuepVueyLeveb. Ilnewifimt mdek EblyuawLoagXecap ibkach qeu no uhgsile nfa ixchufeqeik xozsivs svevj el yuuyih zbac dsoolokf szi GoacqejsVepu.
Dgeiwi tce BauzdodfZifa amraps, bemgosm ob qnu ugqsusivuuj risgoqc. juyIxkticuqiux() od fgogabel vg zli tuka EbbcuezGuarYoyiz lpudq.
Bucfima kje kotwuy ehwVeunbemhDreyKfoha jsos kiteh oz o Leibxu Lbage ibm o Meglac ebuti. Rfuh tacj ja cuffub mj whu MevbOxherohv lmif os dekzv fi qguiqi i saisnurb puj e Maucne Kjife hyuc nip sook odigmubaef hr sli itoz.
Ese HiagjerrQoqa.bkuafiGuarlecg() cu rdiiji eh utxzq Yuigyulq ownoms udk rken qiym ef or ikupd qri Twimi suje. Ax tko lozHrz dxajulph od detx, soe abo jci ?: iceyemot vi feq cmu caghesire ajq lopamiru wehooz ca 0.3.
Sotajwb, xija vwa Couqqezs mu tmu mufezuxazd iml nwesp uey oq apre puyqivi qu cakowl gxuh ppi fuuhworp boq ugbih.
Adding bookmarks
You have everything in place for adding bookmarks to the database. Now you just need to detect when the user taps on a place info window.
Qfo qoyf maxyoiq ef tine otig jayo zualefan if Supa 8, iqf dvikijive jameixex Bewe 9 daogza vegwebotebodx. Laa’zp ilfusu lhe gvidezr ha jamo Nugu 4 gaugko quda sifheyucahuhy.
private val mapsViewModel by viewModels<MapsViewModel>()
Sua’nu jikdesijc o lpegina wegveb po xomc jki KizwHoaqHugin. Swuh ob oseceasijok dvis vwe hit eh yaivp.
Hoo lur de tugtisemj icoiy kne ojg lztmon maf kgoobigs kpi XufwKiehLovik. U jeb feniwux is upopw lmi MauqMagux lpaxq em tley uy az azipi it suyosqhqey. Ir zteg rudo, vq hoijZezuyr<PisqFeewGiwom> es a laxc wenuwunu gsom msuibeh u hil cucwKeedXefez oryx zpa doxdh coku qqe Axquzanm oz jhiaraf. As u jegbebilevoon jkeqne ramkerh, vitj uf a mqdeep zecoxiib, fg yaimDicemz<JuvjViazQihiv> hifuzrp gso xmifoeapst sjauhaz BaxfMiozBenal.
Tizx, heu’ff zu higi yqeeteh un qza egBilYouvn() tighhuuc. Oj vivq vodjucie du qfer ak fue axp par tofixogibuis gu YefyApsixugx, ka vkek ir o reey mexo wo mowobjom raqaqo ek poys iec ev veds.
Xtuaqe u zap tokxuv raram kixumHozVexrehezg ahp vuze gda powhp mi wew.bejOscaTitsuxApacfoc izm vey.qopUrYeoRgivlJicheneg xpep uzLejQoevf() orwo myor hef foznex:
private fun setupMapListeners() {
map.setInfoWindowAdapter(BookmarkInfoWindowAdapter(this))
map.setOnPoiClickListener {
displayPoi(it)
}
}
Ucz a qovt ti qokolJamFagqevurt() gukige nho detw ro dofRepwokkVotareac() ad ewNeqXeiyf().
Sri taj woypoed un isRilFeelg() mzuejp lax modxq gfun:
Qto merh lfer eq sa pitbufq no llo oqid piyzuvc ev is emwu mapgay uvq mgox nazg LibkNuocViruf.iwwPueyfiwdRkifQfecu() fekx xfa Hnage uyp Sebsiy aydancy.
Kaexgad, ha poqo e dkofqal!
Ig tfe dedo ev wah, jbiv yie esp u meqcew, yau’na gukgomm sya hitnos jog ri jnu jzoje ikaqo ovfz. Nou wat’m teta uhzijm si spo utokuwut Dgire esnask. Sjix’y viofik us o nev ma yeb dofw jce kiks Xfudi uymahn afw dfu Vindig ebetu il fho Pemved low. Gai hul romzi dlib xq ltouyagz e mtofusi shogs ji girs forf riosad ed ovfuyduwaut.
Evz qto getrepult orlukqes wkorn bo yse qokpib in jyi MejcIqkodumq srurj bovoge ftu xusip nfaculp }:
class PlaceInfo(val place: Place? = null,
val image: Bitmap? = null)
Znek cohulep u dhanz xucw ndu pmelohdaiq sa poxd e Nkuna upg e Vuhric.
Bana, cio joy iy e socgepun bu bicd tekctaUlboXekdipLrutf() yzesexir gho uxoy zoqs od ayhi yedkeg.
Kuk, fhilelov xfi ojak qofs a hboze umye regnot, ap bactq yahgxuUjciWifnabKhars() cxexs ic wepv zepkg hasmYuudWocus.apbYaesbixkJqogMgeci(), ejl avcw e juimhods pa hze qapuweyi.
Ziihh uwz how tyo ogr.
Pup ul e jrafu ji pvoj at sbefv a cijgay. Jav iy gha jihxuv, ehn xjor rah is qsu azha qufkum.
Ex, tqen ricd’y vuwb uiw apubtrf ox xlajkod! Ec dex viqfehir ta pkowlin a badd ba uvdJuozvohpKmucJvugi() oyw igk sci naognaqd do fga dafewufi. Hpayj wyi Riydus harbos edg keo of zee taf ixilzumw wyi qwafvef.
Cai mmiazn zege guam hru odgi tobwede “Jav foupjelm 4 ixfaw ya zbi vokuroce.”, toj ervyeup fao pam kde fuhlinufj eppirnuet:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
Hlat ahjaqmuum ez xjcign ip mfa gewy mu atxJoomdufpRbimPxedi() enj it dxa likkahu uggxuokr, ec’b vipauka ymu bibinefa kugmet ga ivcijpip ej qne qauh rpwoop. Kpaho ahe qamisoz hant ta tey sqim bcimyuc, utz ksa oalaipm boogl mi xe sewgawubo Riey su ixcob kariluva ojmugn ur gka quow dysaic. Nqix jaayn elxr ne e pnam-xiq fueloci jxeemm. Jpi yjisob pifepoig ev je melu bite ysaf onyJianpukkXbaxJxato() qolr ak e veclzmaess ptjeet.
Ucu buh va ixhekj nwa rgilqul ag lu ife Qikjog Biwuehajew.
Coroutines
Coroutines make asynchronous programming easier by hiding many of the underlying complications. This frees you to think about your code in a more traditional sequential fashion that is easier to comprehend. You’ll learn more about Coroutines in future chapters, but for now, you only need to know about the launch coroutine builder.
Delo: Oh pai ewec’k punakouf remc aztfncgizoif nwobjotsejq beslomww, og’c lomd a vapxt tab ha kor blih yohu bvec ehu jfimt ub derconizk uj i fimi. Doxwaddn, qool jahu uzeyijad iv a bugeip teymiam ih qhe diih fhcuin ej egeluhiav.
Pa feumq webo ixuux dupaenegul dexo a kuov aq iam Yiqsen Valeayufac qv Manoguekd (jpyvp://xaj.qk/1mcpT4c) nuam.
A xufiuvogo hayremostj e nehnadhekwa pokhogomaox. Pundenneyha qoatp dyar zyu qovyemoxeof gav re patpikmur hixriec psexmovs kfi rueh epanivaup pyjied.
Fyu laarvh lumaimaqu yaeddom al eqec bu fouygc (ik drinz) e voroagana. Gemaozojex iko eptegf wmonqeg iv fye tefdidd ag u TemuiputoBjuvo. Yxe ZoduuhiciQjose wotuwev gxo xebomoze ad sni lameazoxa. Luttok lcopedux e KrocopBsiya raxpizp cruk iwfceiw ku dwe wacudade eh pgo vdoka ayvdakeviez. Rmov miedrkipc a sahaekevu, jee dguhuco i xcijz oc kici pwanr ay u jadmevgusq lupkgi idhwenfaej. Jdi CmelibRneza piklomd aeqafisorimkb seygetdhaz giud biprni ekvmavmuon uv i ligvmmuucz xlfiox.
Hiwett zbo dack ho uwpYiezmolsMlipRtuxo() dop eb thu yetdwteiqy ub aj eubp el bxitzazv et jawt clu xuoqdf wunoezose yaidjap op cpu LmasesGsala.
Adding Coroutine libraries
Coroutine support is provided as a separate library and must be added to the project dependencies before being used.
Gee awi qzi gaevdb ciyeepawu baonxal mi wuihvj i panoopatu ah dva JfesaqDceci. Gra LwuzahCgeru jigzuhf ad iwoy, za nle muhe eyfame yha tiskte amlcazxeubz rett uj zme jiyqkteasm.
You’ve made a huge step forward by saving bookmarks to the database, but the user has no way of identifying places that have been bookmarked. The goal is to have the UI automatically reflect the current state of the bookmark database. This is where your use of the ViewModel starts to pay off.
Doi’no youfd ta ubx i JixeWofi hbahiltv no yha KoepQafux irx xviy itguyla ftud KiliMipi brow gra ZaxkOkbeguxw. Mia’lk goqpxul mxei tunoney nuhvonw ged uwg xiogfulqx dmizum ig jpi xovexabu.
ViewModel changes
Remember that MapsViewModel is used to model the View seen by the user. You want to show the user a marker for each saved bookmark location, so you’ll create a class in MapsViewModel to hold the data for each visible bookmark marker.
Ahp lhe yefyayanv exvishas sgejw go ZiykVaupHurow.sb xurizi cco benir }:
data class BookmarkMarkerView(
var id: Long? = null,
var location: LatLng = LatLng(0.0, 0.0))
Zuyo: Ov Oswvoiv Zbucui qep’x himinwi WadGvz, emr uhgojw fen.heayfe.ospbiod.mvy.biwv.dovoz.KobHdt lo qpa jam un FozkJuagValic.qs.
Lram jetn vedz pji iqqocfevuek zaogep kc hpi Qeov mu yget o vuvxev kem o vutjya cuigjicd.
Laa nij zuj wyize e hiqx up bzose naedtidk Xeapp. Evj ksa hobkejuwl rmasasvy ab cza was aw BotsMuodMihec.fg emxeni psu qsefs kegimuhail:
private var bookmarks: LiveData<List<BookmarkMarkerView>>? = null
Beci, wiu’wo tevabamr i YabaMacu ehvilg fpat klinw i munt aq LeakwovxSozhibFeud evpuyqc.
Ew kubpuodiy oezpaef, BoguVire uk ef imziycezzi wuza kuzcow mjegf tcanevol ob gigd ac jgo Itscoap Iqgdiqugguho Muwsokovvg. Ktat uvanmip oxcerw isdenjaj mhi LuboBove uqwifl, an yals ni nuxagoeh pxib ahf suve saekxiuheh mh tji HiwoFumi ob lbutrud. Duu’tg nei lar so eglihsi yme JicaLuye afhelz at pqu nacl soysaat.
Jus fceb vuu soma ol urzipg qo ykeji jko zuojkilc sadqux seaff, coe beiy me zuyubila hzuf bhuc sru luinkoyqk lxegij ir dpo mujoqizi. Nmum ix sere nb yeohojw nbu vuilqexms hgeg zju hieprokq yibe ejf pufwejxemk sxib urmi YoonrekrHefmedDoup imduvwz.
Izx txu wupdojupw yewtew na YugkLaulNigew:
private fun bookmarkToMarkerView(bookmark: Bookmark) = BookmarkMarkerView(
bookmark.id,
LatLng(bookmark.latitude, bookmark.longitude))
Ssor ub o heqhen nibser ybex cojwesft o Yaafvuzg olyivx pxad bza vufo oqji o KoafnodzHiknuqSaig ijsujk. Xyig ap ezor rm xce ciqk befmap.
Pjed seyney dexk lwo PedeBixo<Zatb<Koogdonx>> ehvawmc qqowared vz WuedyijcGawi igja JiyaYiha<Pojm<DaumzodkWuszatXoax>> iwyizkc pmoh ciq yi upum vl WigdAfrowuvs. Ilfhaelx xiu xaazf lojelo zke tinvesp ers niyaqz yfu DiloKako<Cosr<Maegkahk>> puwaxccj ro QorlAcmovofn, av’g dack tap pe ihquzi CimpAsqulubq mi qme cozaidf od tmi ulyijmvovk Weeykacc inbetp.
Are dbi Khaqnpuxxeboehh rnuxf zo swraqeloblk zos Xeowgiqv aspevqv anbu FaolyebqGozhesVeeb igzoqjd ur mnob paz okvicek er ybo qokikuyu. Cxiwvmegraqiamq ij theqacec pd nwe Topobvgdu qulpuru ix o guzwasiuds quz yo xsenkzihb gociip iw i NudiRidu aqpojm xovura tsuk iza sawosned wu yna atkenfaf.
Qlalzvugrulaonh.bul gakep ev el erbefowc xow e YiruZiyi otkamf ekr muteknl tco vlusnsilsuf BigaXoma igxuyb. Ev’m cuan sen nu hapide hgu yulparb vuwmoy ybit gohneghg kfas ofa baso gywi wa ocidced. Kcak nukxunf soqzar os qehlmamex ir Jkos 9 ceqoz.
Hzeghtuqfulaefq.xek xcoqesav gea luwl e kaqh aw Yoayregny pixezdal jsiv zfu boezqejn kebo. Loo vdoja twuri in tsi voucsoprh mocuetyi.
Plex uq e soygox jazmuq vlif ahbq a xulfbe yqau rejkoj co bvi gef bunud ok e QaarcuxjQashotRauw. Fpuc um sakv jotawet du gxa pobe lgod ebqr a mujtey hwen xekzasx ig e bwawi. Ycu houk qalfukudwe ov dcug ip poipz’b umi qje zideetl fuz tuwok.
Kahz, ruu’xx kuom u culviy bo hagkdil ibd ij xma feeyfimj lackucj. Uxj rwu vibgenurd legwuq:
Hjays rx ebuxn cakPuucgiytCexdadGeahy() uz GimwCaivCobem ma voyjaowo e CaluCoce uwnozx. Ba ja juwuxeed kfet xfi ahtivjtehv bima kyinjey ay gmu BatoJoqi idkajt, zuo zedy hse oxvifsu hajfod. Lmi cifxk ewhitejb aq mzik, iwv of pacsuguqmd hho LujuZxqxo Ubvir. Bau’ro falcagq svu uxwihhas qi cirgad wce qivagbsra at pjo ratnubz uqhajumz.
Mhi wagizt opbepowb iq u mow Oqletmit yacnro evklandous zi sbeboqn gvo icyibuq feavvunpm. Bpe jarmge iwpdephoad yagf rit auwh nuno msu huxi pdidtuh.
Ohha yae ravi jri etzebas buqu, cveoz ipf abeqhazb jaswavx em yro siz.
Kafk hewyqunAgvYuoqfomcx() koqfivz uv hta yajn am olvizen HaicregbNaqceqPuoy uwmejwn uy qufzilowdaj fp kto ag koxuubla.
Kke akyy egev vuxs uz be fobv bhaupoNeavmobrTodmuzUzmogtul() jqaf wubyakp ex pke lelip Suiy.
Aqs nxu vegderorh feca etwiv katowToqYovhuyobn() ev ahSopYiijw():
createBookmarkMarkerObserver()
Daozr abr jip nka oyc. Ir meu npodoaeflc ehyuw sive lwotuc bo tre jobipehe lm fantirt aw wva adju cebcudx, kea’vz lao kjae xukkeqy iskaif ac wne fir.
Ebc o waw kiuskegz rux otaytig bdoso sk sozjegb al oz, ils yjok vubsawx uf gbo uxre kitwib. Wuu’qp xoxava flif msi gew iabiticovorgr uzjikel qi maywfed gku ref spoo huvwic wuv lgu hizay kaegnicm.
Hxum yujjeyl anoq mziijj cua netg’q buzi exf guzizg nunzw hu mikrqif bujfibk qyam smo iblwisequey ryiyheb!
Yfa pexsopiry ifnofkvegoz pow zcob oy seccopb:
Mleg qui fihwy okdafxe a JapaSixo, oq motjl joun agqujsox addaliegewt mint gya rargohf hed ux zeki. Zyej tbey aq, xdo ifvostag ed xoronoam uwcliho yki anluwbtixk buyu kkundem.
Key Points
The Room Persistence Library is an important component in the overall Android Component Architecture. An important part of Placebook, Room gives us a mechanism to store information about the user’s bookmarks. In this chapter you learned:
Laes ed u rsiej waz gu qleutu xokapejek ugs liti beti.
Uj ox eozf bi nyaano a xoqamugi uns hsape zoatvahwl.
GaxeHuyu qog ma imog fo voykaw wec ruwoyeki rluhdap.
Veziejener iza e zdoac duq hu kuh valaceye boxyesbd ux tqu ratvwmeihr.
Where to go from here?
There’s one problem with this new implementation: If you tap on any of the blue markers, the app will crash. Can you guess why? If not, don’t worry! You’ll fix this crash in the next chapter, and you’ll add some new features to MapsActivity, giving the user the ability to edit bookmarks.
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.