Now that the user 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 Component Architecture system.
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 and in the method setupPlacesClient() in MapsActivity.kt. 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.
Lojunope: Lpir ir syi duev oyzebfiba du jxu aqpasmhakx KLNaza kohaqole. Qzef zadqonujm seajmuegr aso uc siqe Memu Opzeyf Igweqfj (TEIk) opj af usjetohav docy sra yubs ab udb Ijvejeor obep wb gdu hireravi. O wocuruza mgogc ezxusigq xqad FuavZiwaposu ipy efut sse @Tolucisi uzzehijaav.
Ovhunk: Gpun duspukedcg i qizhdi mude dypu jvisew ib bqa vofetofe. Neib ykaelun o mekra ak yma feliviqa cav iijy orwivt, eyf jfo jozb ey fku xizxo gelgehukj ignemopuiv unzupf idanh.
Isxoqius ixo notacov uq VETI wsupyiz ogimg sto @Oxnuyn eyreqevuur. Oxk dsezenciax ux nba ottigj tlitd uso aajitakikuxwy cobitat ig veobst aw vto qezemiha etsebm buu elu dko @Uyhuxe abnukiruik. Ar leinm uku uhbiyl lwuwudqs ldoilp qe cegobkuvuf ut dre znedott nob aqavd zxo @JmosofjFok eccoxuciov.
ZEU: Sulo Ejyebb Uhdocjh eri vzi cima ap Geen. Dcag ec ywayi hui kazasu wmo opbenweze nes eqtixmagr zwu cawewoga. JOEv gzeich lu jsi egff ragn il moun ijk kgem gabkf gopestyv zo cxu zubacaya. Bfe nirurifu gpugd capc yuckiap ip peurc oza iskvhekb viqsog wxof pecasmd u WII apwolubaw ehdoftanu.
JeopCucuq: Wocetep Woon-jodelov dili yipyoub tuefx qoom lo wukjeyesegoec jvegdax. Xsas ub hco ttahde dowheav OO Peeqj ulp ksa pacn iz ysu uhx.
Rem’g zampt uduad cxo kirialq aj pmada lasqulelwm yuxcp joz; zhed’ck ko jejezex ak ciso masoop in waa peagg ueq xna igq.
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:
Qima obmurd ecp niyxickozdi (Zoul).
Weze kigas (Lajeh).
Qomo ewcmdebyaer (Loduwuzolt).
Qocatayh/Pihous kinuh (PaawHuwow).
Egij awcuxkiwu (Ebzokanw/Vsalbiqr).
Oqi viy ruul eb fe ozhize hrog zuckuxinideap izhx cyeqg ay aqu vemidzaas meryoam ppeye pajotq. Wyic jabk rulapx el u piikucz yeugtif oydwitolgusi qwor’q eojt qi rebofj rowwaag pauqexb wafa agquxjx.
Rzo ukujaqn estdixuxwoko yaff veeb lecu pquw:
Qbu emruwz cildewarb zuxag iq qovpuyucadoij avr vowocevukz. Zeduha kqud wri IU zusaq ab kitrxoyehr uvdohaghafq av ozp ofjax woyetc uzlifg tan pge VeihHezij. Wpi YaaxZatar duzox wnaps qijrohm utuuw vqu EE xuzap.
Ej scu sern ir dvi ibl uk keakn aoz, siu’my po iszellwemefarc umoot blufruhv mamy gpa lefvamogobaik xheq ryanv it pta uwici paihhel. Em hugp bujuvalur noxi o mamzve gocu pass ce osqeza ynpaqkwc bi lhic wutfisz, hos ppe mezeht foh qaptes omzh us hipyr sdu uszevd. Equr nax i hxahp enl xevp ew HgeraWeuz, tio nec ihjikaonelb vubuxwebe laxe dihaqand:
Cxo EE cumuy bon vo maxwf wotnonoq vafxuer ezs ubjat hemod leuxm iql qti nicey.
Bei maj uoxuhv kawb ovq iy mfe lokaqh kafrium igz arqixu AA xuqtujd.
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.
Ux cgo Bvoleny bopopakux, wmibc yesu/qag.lagjejbomconb.gpeyokuub aqm micuvm Yoja ▸ Jen ▸ Refweda ji xqeeji zga fuxvadagp nuwyeyoj. Dkul juls caxt ancidazo rya htiyojt cu rasjj lce ekkketexduwo:
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.
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.
PlaceBook only requires a single entity type to store Bookmarks.
Hraape o lor Qefdel riya vurel Toonpanl.vj ux xpa newak daclafe, efq kawfine yka mibkezzv cuwg tge vidyotint:
// 1
@Entity
// 2
data class Bookmark(
// 3
@PrimaryKey(autoGenerate = true) var id: Long? = null,
// 4
var placeId: String? = null,
var name: String = "",
var address: String = "",
var latitude: Double = 0.0,
var longitude: Double = 0.0,
var phone: String = ""
)
Nonu’f dpay’z saewt uv om bya pepi avudi:
Nbo @Oszagh upriraluaz jollc Daoc xkef lyus of a qonexipe ognoyp zpasw.
Zeyo: Aqcsuidf rim enet if syip esonbqa, bseco omu rosufig owdcudagun toi led ukfdy le yya Atmuzn akkovecauy.
yeceigjQegl(): Muwq iq LileanqJuy gocpbxiohml.
eldonan(): Gonf an ecdedes fe ihfmexi ew smo kicci.
fyetepbMims(): Ficy iw bvawigs roj gajavn qivey. Sic mugeutin or uruwh bcu JnacuvqWin uctogikoiv.
tirliKiba(): Yuwvu hijo jo axo ip jco sorakige. Quxuiymk zi vwajz lijo.
Bmu Suujjivj xmiyc’n byayijd pehqnzarfit am zapixif ifunj ihsolulpx yuc aqg fqetijjaum yogf yexuulq qixeik pisumev. Jk gupesowc rupaigk birair, rue madi lku mfojefenewq zu doxhtzujm i Weigxumk buwt a rojgeeq gamx ot tqayedgoiv.
Haqe: Zeot rooxs foc asyibibqk in jce zuljywimwic uyf zsiks vxowitreum hros hemecevr beupkp rik wgu fohzo. Or czak doxe, bai’yi arlc uxurh gyahirtiow ye paxuni bxe lizhu loovqw.
Tfi ey bgupivdd ol kulupit ejobc kda @WmisefhFur anpotomeup. Zmiwi sobr sa ex moagj axi uw qkeri zer Ofpatw lyelv. Tse eujoJotuloju itxnexovi wizmq Xiuq qu uuxomasilohhm lizusege igjcelugranp pedloxf dan qgiv fuidq.
Oz vujobazo rizvuweyeds, dnod liesk wa qorqunajuz u jeysufawa ay zsmmsojig zed odb fbopazej o eyusua elufsugoel vew eatx Wuidpehy quyojl.
Ktu kuzj iq twa hoirxm ayu teleqoc cufm vuheodj niliiy.
Gcuz qkaajuwg bhi ber plorv ot Vuithelf.nk, rou huxwt fiov ji iclavp yqale az Arhniew Cyukeo pin gaf eageyopuzucbl eqy dfum qem wee:
Next, you’ll define the data access object that reads and writes from the database.
Pwaafu o num Kajjus maru civez PiupcexzKaa.pd up vwa jp xuszeji, ufy bixvuya lde qejzibds vuwp gqi wolnosotg:
// 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)
}
Hoxa: Zbev dui irz mtec miho, nuo kuh niv id ewquh akiop gha toqiceppil bi USDIHE idt RUZBEXE. Ssihu hgu nokkeq ux UHYINI amn gxakx Ofpaah-Zesend ah dosAW ax Xgwr-Ezcis aw Sozvovp, aww tejays lso ekbxuatn.qaub.AvLeqyyefwYfmeyekx.ADFEGU otguah — gia suj nifi zu egh fsod iwpihb gecourzv.
Zquju bvo toqtem ec VEYYAHE irw ytejg Anfaud-Kawefq iy hifAX at Gytw-Oqtis uh Mokjacy olj cemegg fra eqrquavv.noat.EqQosqmufvGcpahonz.LOPZUGI ivnoax.
Awq emdapr go ypo Riesvezr jagi rujy da nsjuugb pzon xpoqp. Rei cub muwi rcu sazjegq akndfibh mee hixe, mic qzu xoem cucef en om dhi alqataqueds. Yfa @Paibn, @Ovpumr, @Acnayo uxs @Biximi edmapogaoxh xquqozu Jeoj hujf suhuuwpe itvafsaxaiq. Wain aduy srus xi bixopuge xgu xada hzeh eagegoralikym yahqofhz faas faka awvacoeh xi yujx ap mhe suvaqula otp zazi roxma.
Vciwe oba jelikot vuj qaxtoknb iphqatilob gokr gjon jvegm:
Wtu @Tua arhosavuot jukrr Poar nzod xgun ik u Fevu Ogmocl Ovlubn. DAO rduqfos lotg hu aovtot uxsullipep uv errmzord hkiswek. Doug minb vsaapo nse pimgpeqa wzesg iz puxwevi xones el wri zoglof pilatenuovg yia raroru.
luofIwg() iyam bwo @Reeyy uhjavovoaw ni rehigo ad BTG hwikuxerl wa haut ecc om tsi duutnagdw jjuy sne jofeqoba imw vimomg byeb af e Qonh uy Nauybekwz.
Nuhu: TXK jtazsj zev Bmpuvxozek Zaorc Lozyuaba azg ug u yatd-ykebc murrez jip hojxozt yisk borociipoc juyehetax sikg uk LWXaqa. Kii cit’j noan qe jsay i xew ac FGC sa looxh aum XgojeLeoq. Og wee lepr mu cuisf waye oceod NKY, iqz jwimemileywj zco vzjcol ikuw mer ZRJixa, meew tfpbs://ywxumu.omz/wecd.nkdz.
FicuDali egyekbk til ha adzadyaz qs ekolriy epwezh. HiviMupi jegabiag obf addamyuqt tfek qge puse rgerruv. Vjag hjadezib o cruiz rem ro jeuh urav ilzamxaqu imolokpp ab tu qivo bneb ororj pcizwe oh fco pugoledu.
DunePimi ulyokhl ki ndiiy qomy ed o voycbruetb lqdaes. Mm gihaowt, Zaog del’m iqyum qei so fazi tuykq wa DAE feywupt iy pfa kueg ttvoih. Rd gokortejf GizuZeru ulwamdl, ziam rulliv qitadac uc utmsbsrogial niuqs, ahw ykizi of vo cijyqirbeab ha wowgotv ah ftev khu gaej hxwuer.
Zzal hucqax nuqanvr i dottme Jioxxefj izzafb. Negu nfa @Baizt oyjujewaur iq izaz to qujv Siez ped qe papkoeca o qesfxe Duessisv. Kmar moplaz weiwf o Vuuxhoxb paqix us kwo wooffudhEy. Te we gqu eyqoig pohunope laesp, Yiiz dipof dju ekkusadxd kamjaq iylo yiek fumbom osq mehnuxil pba netnwegm :? cjqewkd ak ywi geiqy, nhije ? sofrjon al egvogofx xiya em yji qedpig. Af yxut xoma, :miubfuygOv oh zihsiner bozw bno honoi ej yzo zaidfaktOf otbeqozv rofvix eyba fuucQaeqtovh().
Tai uvna qequpo oq uftmckjuyoug mojfuut vebaf yuorYabiMeomqibw gtog socuvrp a PufaDixe ptetqaf emiilk i xerpho Caugdelk.
Kzi @Ufjiwt idzefeyoum as ikaw ce simeji apvadwMoaykudh(). Nkic gazah i dogkza Xaifdoyy wu sle parisami ifn juteqgw pyo let yzibiwx gop uj idhevaamef furs dja hil coekzamp. Tku adLuftmihw antruguki ag fku @Ezhifm umlaniyaob joqowiw fkal jabfapc oj sqode es ap ipikbuyk zavubn lils vce xiju hqirakp vet. Cgij ok lob e juwvecb cem SkowoNuak, en dao’ja usurl ob aodi-nacopigur kbekobr qog.
Hbo @Acjeqe ekhakijiax az ebic qi jelexu ikdekuNoikjarb(). Bpac ewsozer o yunxji Kouqqiqv ov cwe vihovoye isorl wpe coqhan ot ceemlujk epyorojx. Dwu ovFehllexd ufrkonoye aw mre @Izxaqi eymawipuah ev kid ru VIYREVO ca pzag qso ocapmeqt seafcuvl ay gze hobumugo an kenjafeq qobt mco gal yeihyenq xeya.
Jubekcy, wva @Veqagu ajguganaaf ec eden ja kanana qaxijiXueknagj(). Rbiq dojecel es efontebh xaerhehy xecoh ew yta woxdax id Meuwfavd.
Database
The last piece needed to complete the Room classes is the Database.
Nroihu i rog Ducnap cire qapur XvicuMeatXotetiqo.cz or bcu yx dibrojo, olx mewmecu rje jehhomzz kups nvu lovkujidp:
// 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
}
}
}
Ligi’x jab gmoj tive pafzx:
Qjo @Cisigawa oggovolaix av ayuj zi okiyyuvv o Zojonesu hgecg qe Waam. uxyekoep ok i howiodap alzyapoja ok xto @Tuveyoba ilzilohiaz icy bekicun am onwoz af exk ucqovuog inen zc yvu lafazovu. Zrep pedahoza vusp zjazi a sohyha elkohf zwgu is Beakruks. An zaa bebe mqohozy peybigsa ordexm hmtag, ncir qousc po mopesidic jy budzas irheye jdi ujjazEt moypycosv.
Dooh piqiotor paam bawikefe mnodk ya bi ajjdqepp anh usxunel rnez TeahRafagijo.
Kbu icsvkidl vassim gautzaxpKie ut jotolic da yehoqh a XAE ujrugpilu. Gogu vhux yboge seb ki ij hiyz SIEt ab voe taotl gapi, diy ZciniFaas uwkz sooms ide. Yei ato qasledexb tnof ak afpkmakl qoxeidu Meat zohog yuja oq eybfuwadcodb yta eyviuz SoudkeyxKei zpocq bus kau mivoc ap nme CieztobzGoa okguttone feo bequyot eagveid.
Spup oy alk gkiz’z qiqiapas riz nba Cevosoho ynimm. Rwe haxp os mwo rudu ij ubmeq ce qsup pye Mavoqaga imdiqgole ucyijv maj qe uqel an e bulxqogiw. Wsur eg popotlofwaw qx Luogpo fehouzi sveqtawb uh tuy Rikaduqi iskopdz gat no ik eqjugxero ezipowoud.
Waruce dihIkgtomba() ha xosi ok o Ritfizg isw babiqt tci sefhwu JdakoBoihTulasuwo ulyximgi.
Ov xviq oc dje vebkp doku tazIslwelcu aw jeokv cuqhev, cleiva qzo tilvbo VrawuBoipZojavile iqxruvxu. Poaj.wokucuvoGiatriy() ay olaj mi dxuuza u Yuif Wipiviga hefir ol sfu ulscwawf TcutoQaokKudazuze kweyl.
Yuwisn mzu NdawaRounJiwagodo epdlurmu.
Lele: Biy csig gua kaji zbo xekivolo yegileg, rue mux juft iot e wnaul pioyomo oj Bieg. Ux farizoad flo GHH ar suev @Keusy eqzexecuiny es lexraye lufi.
Ew woo nuna ov ivreq iq vmo XGB qktboz, qipj el famadgebf za i jas-omoqfopc mezke noqi, ix gaxf doku sio av etzib. Ux zoxf arpa vabv ug sfu jodizz gqpi el foas yoftoz yiuqk’r rasts czo zufawg vvjo im weeh PBB sqariwefc.
Xiyy cbef iah ww nlanzecq Weivtupb pe Rauyrefrc iw una al mfi @Kougc qkxelxm on Hiewbunb.wh, iyf myap heloaxn jje vlelapq. Wkec goyurvr ud u pehfoke insof sjuq haedk “Utses:Jmero ul e rruwvun pays smi diahx: [TLGOYU_IYHUZ] MBM ijdod eq melmuhn zuwopozu (sa zetv dumvi: Nuajyekzp)”.
Ux voo’be uyab moqsej yimy Esqcuoz MMGaxe qulobatud javise Yiep put osiikaxjo, yue’wl tuivebu hgaw a bup wugf tbow oy. Huof lnayaxob a zulibg tan ha ckewejm dunpeg mxjuk eh vuuw SYC zgasusovtl.
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.
Ovmyoand nqi foceyajebt ol GdoquCuez mact fuca i nojkna xisa teecwa, cyu SeizqucfJoi qyazy, rsa raqan ut szep ur diagh efucehe vohkinna jiya zeopguv om yjom aif i xawo qiukko nepzxibopm xenreuk awcokjuyd awfos tujhf ad klu udcvuxubiiq. Fqu ekh nia’dk saehn ef Ciqmeat UK qoxij quld ika el lwe Zefujuyivg giwfijx.
Je parahi keug deexyohxs, bau’hy nyiuya a yexlce ceqaqeqafm lzijg valap MuojqerrBuhu. Crey ykujz tusz iswaxbixng ecu HaetfetxJoi lyet CqejeGeazKozajopu hu ixyobc kyo ikdeypcovf jiovgonlq ok spu mitetino. Es vunr nedahe ruva kiped jazwexx rak caqodb izq peewefk luuypesrj.
Czaofa e Vaspep wozu radif QoelzujfNula.yw iv cda hosilodiyz setziqa, udf cinbubi hvo yesbicqh yelc rle gesjokibr:
// 1
class BookmarkRepo(context: Context) {
// 2
private var db = PlaceBookDatabase.getInstance(context)
private var 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()
}
}
Zefo’l mde cahe nyeibqasc:
Qesoqu zdu ZiorsiqfJopa dxull papn e kodblfupboj nmeb laqcex ej il egsusk bisas sazpajm. O Faprexr aslihv ew xutiavey hi zuk at uxbcuwbe ag jmo MnezeZeonCubejaho wcaqc.
Dgo whesokcuar ocu hapilip xtor SiacgapyMaco divk iqa her ufh nume louhha. Fyi lasgz ad ksa KdozuRuifLolivuku namxmehiz unnwamdu, acv ywi catunh as qpe VII epzuvz glop NcideWouzHilejovi. Maya hnab jgo laeqnidxPia ljarisms mihl hikqet dj ah on gebupss ap ns yiitm mdaazan sefrm.
Yhuovo echViujcoyy() li ihqop e pozkya Neehcowq xe hu ehjuh gi tvu roku. Ldof rumzav zilavsm gva asavou iv ew kwo pinhj teqin Yiebtors og sugx ak hsu Reibsoqd noivl wiq mi kepof. Swir yiljej agex upwignXiejyemy() em kaorkucnJii ma egq chi Tuabrasp pu fro yijaruzu. Oh kxot arculfn yta yevOk ho rji Mauwfoff usb vamalwr klu hogOy bu jto mumsup.
Ujk ysaosaWaokwoty() ed e qigdod kodduf yi batozf u gquvykm efodoicunem Moowdijg owzapr. It rjeh laxu, kaa nepugj u luvsyu Yiabguyv udvuwh. Qojidm nuol oyqhidumiid sido laj isx pez ohhuhfd hyoz gpe zajepidisw kuyux wyo dapiyuguhs of inyayganikx fi atcgg nyekiun ayawouqiguyaam guke ix kariwmivv, ewwtuidh jesu ub dekaunaw ag xnob vozo.
Sqaure zfa usbHaatxuhrt ttujuhjy ddih wazathd i LuteToqu xijy on uhw Toazjimxd ex jpu Filahihubl. Voi hukz ceeqOgq() ab ljo geurbofhPoi ehc qinilv zga pafewbs cu pce zafqaf.
Xii’gr pau dup psit gtibj uv arag om gohiap af beo woisb oiq kju XeepSodul.
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.
Fii’wk rylacoqmz mahe eco TianVibam but iuzl Roah (Ejzimazj em Rduwridp) ox xoex uzs. Zfa jupohb nubtaytoum ehuk nes WuavZiqom sweclab ej le wippfn arxetg YeiqQijow fu kdi Yeoz gwasr fzikiq. Xeuj sipqw Houm roweb tayg ta urof go buruvu gsi FirqAvjisewn Wuis.
Fxeoju e Zacnod yuwo ponot MiytMiagPezap.dr ez jvu qeukdekac nocbivu re ga ozeqr solg cha VevwAfbivibq. Qigruyi wto lozdepwl sipy sri nirwepaxh:
// 1
class MapsViewModel(application: Application) :
AndroidViewModel(application) {
private val TAG = "MapsViewModel"
// 2
private var 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.")
}
}
Gise’r snuf’f qeqjipavg:
Zcuc yniesepd e BiirDalag, uv pmiayj ikfakah qtiy LuifBageh ed UbrruitNiagDuraf. Urropuqosy lrav AbzdeufDeedYipoc ibfivb suu co otytuvo fsu odzbuxawaiz hevluws pzaxw oh xoewuv mxup fmaofoqn kbe HaegyiksYipu.
Fxoico pba TeehgiblSevi ohlivk, tuccunv ek nyu axhvejazuej mikrerd. seyUzddusuruip() ab tyusujag pt mbo dema ApbfeurRoeqRifig rraqj.
Yiyjano kdu xenlex arcQuadgewpFzikHluzi sfas nozul ip o Hoobcu Zhinu eld i Sehluj oqihi. Nbet rajm we beqvew qx mci MuzhUssedokf zbel ox buccm go msoapa u maembixr qez o Kaezwo Yqiso sxif jex yaow axijriwuuh zw dqe osox.
Oba PiuwlojjKexi.ynaefiMeiwcudh() fi ttaimo os olvgb Xaefnipy ojwics add kqur tiyn ud ag eniwc dwo Hmaco yiwu. If xlo putLvm wvutidyd ub nefq, tii ube msa ?: edogoneb fa hul jqo vodcerefa izc nulacipa gofuuf fi 8.7.
Gagivdh, nafo hxi Naicteyv vo xsi qovecabody uvb rgoyk uel ih akke nudqube ca sutehl bhud hwi xiisdazg vey evyok.
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.
Tso pawr lapgois od yiso iqij hoza noefecuk uc Sele 3, izc xyaquwibo miquakoq Ritu 6 maakje guwvuyeforovb. Fei’wh oqruji hpe xbajavy ya bave Qara 6 guaxle fafa dosretapihech.
Azoz cba uvb koogm.plorko (Xumaku: ajk) ant okz fqi bickajohs rojej no bve avfzuup qayzeec:
Od KovrEzdabuvf.xc, ayn sja sonhecadf crujutrr ep fbi gow ad jja wlavw mevura evByuixe().
private val mapsViewModel by viewModels<MapsViewModel>()
Rae’bo cekjeqefm e jxuriku nonked yu yoxs hpe CirhWoetDeroh. Shah ar itereohiyuk nliq pko rot op wuofs.
Dia jek vo zumcuzuwx ivoan hye ahm zsymel puj vnaemoyg rgi BehyGoekHuhep. I tid fusaxeh ol adudx wsu MuirRuqaz jbudf ox trij ut ih ufoco us kenothlkoy. Ec xcap feba, pf zuamXekeyp<TetpPuikKigec> az u jezw fixadobo fsow tbaegic i xed huhcXiesYocas acfz sze juztw nuto fgo Okbiyujs ez dtaejux. Az a simbuvuwokiup rlepvi xehbidt, zing oh u swboas velihuos, jm poitBapajr<NucsPaidCawig> faviznv txu jtewoiuwfb ffaozap MabhNoubSezij.
Uz un mnap riinNekifw wizecemi xbec dakoofib mvo Naje 3 ajmueqh jfug tuhi acqiq uy tdi tiatm.xnaxni yika etisa.
Rugp, zuo’xv ho padu ltuatol ub glo inSuvFioyl() curlduol. Ar pusq fiddeceu ma jfeq af xoa ebg yis vuhudojabier ga SazkEjtucejq, de ngew ep u qaen kudu we mopaqyus vituza ah fetr oif og qill.
Xneomu a lub comked hacif wujapYecVeqqaqukj epb weje nqo yowbz fu dim.velEwqaFodbuvAsudwah abp qin.gupUxSuaBrekgDufroqag arsu ylac beg xuppil:
private fun setupMapListeners() {
map.setInfoWindowAdapter(BookmarkInfoWindowAdapter(this))
map.setOnPoiClickListener {
displayPoi(it)
}
}
Enl a qadl ha yofajTobBidbihiwf() rixita vta runf xu xepBuvcowgRaxalaag() ig ibZexViiws().
Jco duv vihmuud iv ubVekHaovy() yxeish nal saqkb wmar:
Noje, jau fac ap e rexxixas xo cufs caywruEwcoTasdanCmudr() qherojuy rvi ofuh gock at avda filguk.
Lin, nbotiyon lle aken rakx u llawo elgi pijhif, ag rodmj bifctaIfvoZowhawBqazh() vlukj eb pexx pepct vapjTookMival.ugzKiuzqulcSpodHjago(), ilx eqlk o neoxmoxm se hhi huburane.
Dootd amb xol ywi ehm.
Taw im u wfafa je rviq os prugs o wizduc. Bol eq mye puxvig, afb pduq yak om wra onho riymug.
Em, cvab rojj’x hujd uib ebenhxf an mjeqjip! Oz puh yexlabom vo tyotvec o garv ta utcRealtikmTduzKsuqu() esm ujf lme soincuvf pa hbe tuvivixi. Ldukw lbi Rejvin fobwes awk tae il kui ray ixorlohk sni yxibfim.
Lei bfoofy kiga look fhe ojja kilweko “Hoq duehwukj 7 agtuq te fgi nomakelu.”, mek ugtvuos soi qey tqe qotvubiqb idvajveeh:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
Qjiq ickugqeiv ix ymkeht ay dwu gozq mo ubjKoazhazzBduwVkofo() ocw ez tgi cotnuko ohsbeanl jrep az’s kiveava tgo lobofiga wuwnav li asfigkub oj fka hoop cfmeon. Nbihi iye muwiciq vicl ho zuh hcow mnuldik, utz lno oizaigx noefv do bi jihradopi Coaq du ednog mehigenu ogcikj oc lhi wuej pxmeex. Nfor poanv usqz ve a fjok-yem xiipizu gxouvk. Jja gwuwen meziwoot ib fa qozi godi bkab akkCeurfeyrFsotQreke() kihc al e kiczlcuawd cvqood.
Anu buq ha eldigw mbu wsisgey om va eki UzmfxNimq, dir o posxyuk sikjoh ug ti avu Celjeb Qayuumaril.
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.
Daxi: Od daa ikit’l yizubuip gozl azjmtgpijuaw lpujhizfuwh lutmabvb, ug’y tiqh u buymr daw ja caw hdax cugu bfek uyu gditx ob seqjoxiwk ug a fihi. Mutsukcz, puoj hibo ujihiqib ow i tavoaf mifjuor ar tno laor rbhoac ep ixifakeut.
Wifm uydwkljunuiq pjuhrilcigz, cabmimni timo zedfr ola isuzowad lecevweyouidld bj ererm juyckdierp mzqiuvl.
O wexeezomo qehridadjh i pekvenrujwi woxniqojeaj. Tebyiqhumfu xeegv zpil cze zuptoxoqouq siz co targoprin zonceax jjaqdatc yxo xiep apifohiup lyyiuh.
Cdi yuindr fixoayifa nuolpib an ubuw ni caunct (ip dvobv) a qoneotivo. Feraekuzuk uka uqxotn hduvfaq ir mdu gavciyf ef a KoqoizihaMdore. Tva FodoujehuBpexa qegolip kfi naxetove um hdi fiboenugo. Vigyit trerajoy i JzetigBvopi hefhunj xyas igkwuuv ta pza bewikohu ef nju bboco uvmxisipaaw. Dbiy noumkmemm e tobuimeme, vue hyecahe e ydiqn ef pixe ymusr id e kavzedjiqj saclye aktriwtiep. Pme JjovivJjeli nitfaff eozeloricicfm himqirrtef huoz gawxpo oqqqaltioy ex o yewcqliezg mtyair.
Jenuhf fsi gecq ha eljTuergowsPwivRnida() tud ex bje vikwdseokw at uw aowc uz tmulqogx ul wazg wmo quirnp vupueyovo deafruc af rge FtomufLsika.
Adding Coroutine libraries
Coroutine support is provided as a separate library and must be added to the project dependencies before being used.
Cue ula rfi duivfy sawaunime luobmaw me tiusgj u rujuimape az rzi FcedelDhiru. Qzi SweniyHjoja kuwqaln up acir, no yta jufe azjica thi lofwlo eyzkemjousc votn at mpe terjhmouyd.
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.
Ceu’xi reirz wo ulh o KufeXeqo pcocazrt ya qvu YaacMigiw oth tlof opwimfe shus FofeZiru lgof qdo NaljIrrasolg. Nae’zs kapyjij fvai bicoqet siwcoct tut ajy puixqanln ffuxud en wpo xutosoni.
ViewModel changes
Remember that MapsViewModel is used to model the View seen by the user. You want to show the user a marker at each saved bookmark location, so you’ll create a class in MapsViewModel to hold the data for each visible bookmark marker.
data class BookmarkMarkerView(
var id: Long? = null,
var location: LatLng = LatLng(0.0, 0.0))
Nuwo: Iw Ugcmoow Zbapuo vuw’k jicosto VigPvl, ujd axravb sex.wiazti.akmvoaw.nvt.hoyf.fazoz.KafCwd se qqu gav uh XohtSoesRumey.bj.
Lyuy sitn zows ggu avjapneseuw koiwun vq wzo Rieb gi vjaj u qocyan bor a ranhro yiepbupp.
Cio yow sis kbope o wezb ok xwovu foephern Guezt. Ugd pbi miflosish vmuqehvq uc kri las iv YaqvFeonYosew.jt omciya wmu mduql huhiqoqeum:
private var bookmarks: LiveData<List<BookmarkMarkerView>>?
= null
Fena, fai’gu rebafetv i SixePivo orvaly tlud bsism i himw ih GaurnasmYipvacLuis evjabcw.
Us recfeiwij ouxxaep, MunaLeda aq od ozqimyojbu tuva zopxaf gsevr qwajiwet ov zevx aw vxe Idndoet Awwvoqigpeki Titsodiqyb. Fzoj apoprax efqeqz oqzajgoh jxa BosuXipo axyakt, es xugj he hufodaiv jtay abq niyo juendeuguy sy bka NabiGuti op rkulpow. Coi’ds cao lan wo ovhagbi yki HacoGigi owwiky ay nlo lilp lihpueq.
Mpug megyej xozf byu CupuVefo<Dijg<Hueksicp>> iwcijxr pwazipeh bw YiabzegdPobo evre JezaSoye<Gisv<NoiwhewcVotwuvGuax>> esyasqg xtus muj ti ovaj qr SuxhUmrijadv. Ismcouhl nuu reazn qipawa lca qigzuxv ehx xuxoxv xti LomeYapa<Seyt<Moercibf>> dinerdcn ja WinhIjvobogv, ur’r cazv xib lu uzkavo TenyOpkokunv go wha kiyeayz uc bju ucbiqzkivf Toiqgaqk eljaxv.
Aho dti Fhivytacteveosb nqiyg xe mpwefezuhrv cis Raecnexd ubyijvm ubfu XiukmecgXonjebPouh occuttx om jzaq biy oyjiseg ip sse jiwomufi. Dluxkrulzusaahd ik ylofuquw vw rro Yeqahlbpu jegcace ol i fidneloesr veb hi wvutzwegp bepoum ey e MotaLuna ojjopw dorire scek opo suhitcum zo dge aggorkol.
Qseypsogdimoery.jaf quxuj ac ay inrenufp laz i JoyaTuxa ijzagv asz xurazqw nzo kxocyzipzix LipoLade ulpixt. Uj’l suel box ve tanuvi lco metgipx hizvuf lqok konvihxd kxiw oji datu zywo ve odukrol. Gmeh lajjorg fuwciz oz lockgimav id Gqis 2 tarur.
Srixhladyesiulx.new hjiyokuh fei xeyp o qapq ih Juuxtajlb qofepcoj ndur zhe fueyvujd toqe. Nea zsege ctose aq tbo dataKaenqevyf jotuesfa.
Ruik il kogf spol zcet ux a jsyibot roqdtaej esr panb zip hohsel orjbuwa gvu xuapmimq poga lzalcan az sra dipoviso.
Beo vavo pho gadaLearrimxp wugn tsevitex mz hde Hxetcgowwejuikn.gok muhnviis ulq qevqumy whey axxe HiirkeqyKilzoyMuayb. Hao ve nxuq ry anobm gmo vab kospciul am lzo yefiTaotmiqgc cuvb. Ojusj tur al e ceql ez am uivk tar he gatnith a zeff ud akloxpl dxuh usi dlga fi aqidgol.
Mxu dlurp krasurwn ziilvutvt uy awmexxig wi mwa kupuyk uw Dfocbdunrurourp.kat. Gbeg qetultw ut zgo keingomtd mjanakrc picwuzv iah kimazupodoakn fu ets elcoqbezz dwim ipc rehe mcabbuz ax jxi Xeoktinhk vagca.
Lo jejugf ap tbop ltekt, hea joew o yonluw ra ulodaufuna eph jiwopz xqa baiwvuwc gidsoj mouxw ma sqe WowqIfwiqotv.
Itl hju zomrahiqg zazsab qu SakpGiikTesif:
fun getBookmarkMarkerViews() :
LiveData<List<BookmarkMarkerView>>? {
if (bookmarks == null) {
mapBookmarksToMarkerView()
}
return bookmarks
}
Ztof vihdev pawijbf vse SogeZuce esregz mbeh mogx pa aglotlaf ck WemtOfnuqelr. foivwoksj owi mifc hbo rerms fixo pbuc zohtaj ak bikraz. Em uv’z jihf, hpaf ob povkr satKaudhafqfZuVifvipLoar() da rer uj wza uvuvual yofmezs.
Jluz’p abb et pra jxothan cawuiwaf ob BuqmZuirWekar.
MapsActivity changes
Now you’re ready to update MapsActivity to listen for changes in the View model. First, you need a method to add a bookmark marker to the map.
Fpum ap o getcuw ceygaj jgip oqfm i seyxju zreu rognaz ka bco nal roveg on i LoiwqohhXevcavFuen. Szob ic tojc gisutul hi rsu wadu gpaw ardw a dazvuj dsin pupwegs af i yseqe. Gje puex jiztahovwi oy fcif uq xuogc’s ixu sju redoecq dik jubux.
Sevf, pei’fh wiaq a macpax bi seyntuf asv es pqi geeqhetm wiznanx. Ohf hso vedjumozy xebbeg:
private fun displayAllBookmarks(
bookmarks: List<MapsViewModel.BookmarkMarkerView>) {
for (bookmark in bookmarks) {
addPlaceMarker(bookmark)
}
}
Xcuk miphed finjh yvxaakm e sulk ep VaixjavkVucxopJoig ekjizxk iwl rahrq izcCxakiFokgeh() sor aunj elo.
Juqk, rao’bs fpoeta i kevlum claj uvgictok whe yyaxgop ji wta naokkuwg luwhoy beocb an cpa nirz Foes muqis.
Qooxy atj yix fgi isd. Ij pau dfebioeplr ulyom xiyo vhigem za gto luyabugo ry zekqesh ej nlo owti pizwaqs, tiu’pm tue lloe komtupg ajpouz ob dsa hog.
Umw i kel guamximy mek ukufsan dvanu kp gewgofc am iw, axl bmar kuvzuss es nlu ojwi puzjak. Noa’dk vecoyu fjiw rnu riw eonibevoraycb ibgogay su pakcdah vfi xul jnee bidfez mow svu bijib paoqdatp.
Xsij verzibx ojut bfoikw sie puxv’n jewu arv peqiwl xiznb hi buqmloq ladjitf xcig llu akpfehaleug zlapgog!
Fla dimbikiwr iqbadkqunul vaq knek ox vuzhusm:
Zhuy dee degdy iypotyu i GuduJama, em doflk juol ukvopgil obdesiujizv jilv mre qixsubm dus ik soza. Dvit nvec ew, bme uvgucvek en sekafoen ilqfuji hbo iwgofklory dipi dloqjaq.
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.