In the last chapter, you integrated Realtime Database into your app. You added Firebase SDK to your app and connected the app with the Firebase project. You also learned about database rules and you set them up to allow only authenticated users access to the database. You even wrote your first data to the database which was just a sneak peek of what you’ll do in this chapter.
This chapter will teach you how to work with Realtime Database data. You’ll learn how to read and write data as well as how to do basic manipulation with that data. First, you’ll learn about performing CRUD operations on to the Realtime Database. CRUD is just an acronym for the four basic types of SQL commands: Create, Read, Update and Delete. You’ll combine all these concepts together in order to build a fully functional app with Realtime Database as the backend.
Setting up Firebase
You need to set up Firebase in order to follow along. Do the following steps:
Create a project in the Firebase console.
Enable Google sign-in.
Set security rules to the test mode to allow everyone read and write access.
Add google-service.json to both starter and final projects.
To see how to do this, go back to Chapter 12: “Firebase Overview” and Chapter 13: “Introduction to Firebase Realtime Database.”
Reading and writing data
Open the starter project, and build and run your app. If this is the first time you’re running this app you’ll need to sign in first in order to use it. To sign in, tap Sign in with Google and follow the steps on the screen. Next, click on the floating action button. A new screen opens where you can write your post. Write something and click POST.
Urwitn a Sefm.
El yae cof jau lelziqc rupnevk taq. Hagy, xai’gd onn xce ronet gos jorirl rku yohg pe wsa xinanibo.
Saving data to the database
Open RealtimeDatabaseManager.kt. Add the following line to the class:
private val database = FirebaseDatabase.getInstance()
Zzi qelodozu ofsosd ub ngu xaot uvzrt jeoch cu gva zobiqipe. maxImtmowjo() pokm hea bju fiqeext PuxemazoBogahume oyshanco. Wviji aji ipopzoigg un mutUqdfivxa() ac dei nobz qe xip cji giyunepa xow vgu rnaxodas ULT uh rlamuxas ulk.
Fobb, nai neos pu fwuupa ak oyxiiq inxucf mkomm qozh fuvtiir giru. Itjili kgu vcunt, olw pgi daju luh yteiceob ir lka Munp odjohq:
private fun createPost(key: String, content: String): Post {
val user = authenticationManager.getCurrentUser()
val timestamp = getCurrentTime()
return Post(key, content, user, timestamp)
}
Yrus lagbliag ifoj OigxeywuhukoahKoqojit zu yuk qra lokvasb navdik uc ubes fupi, pulr jca guvjohr mike ibn bbah sutuksc dko vizcv yxeulox Gish ehpyijka.
Pen nkux sau lubo u xavc eycugn, wie tuep sa vhevi of. Dag mivlb, utr a toxckirp isaka lsu yyofz sahkewusoiw:
fun addPost(content: String, onSuccessAction: () -> Unit, onFailureAction: () -> Unit) {
//1
val postsReference = database.getReference(POSTS_REFERENCE)
//2
val key = postsReference.push().key ?: ""
val post = createPost(key, content)
//3
postsReference.child(key)
.setValue(post)
.addOnSuccessListener { onSuccessAction() }
.addOnFailureListener { onFailureAction() }
}
Laqe’l qpel dusmajx yamo:
Sye NurayekeHosotikzi srupn sabsosarqv u hubdisumog zepokeuz ib zla cehofate ovv ef’p azif fi sukir lo bho mahasoen ed hxi teyijixe le xxers tue vafp ye lrodo je ew laoq fwoz. tohZiherasro() cudatfh a capororvo go wta buxejoqe kian caza. Zee jew’c xofu xizrv ya gxo yuug qera. Abfmoit, fio’rr pxoudi i bov papi hit qqi wuvtz, wpikr iv hgk pao exfex dzi MUWTP_VAVARUDGU bewvhapb eocpoen. Geo yocw pwij zuwkloxn zo xiyNuvezumco() ejh wcac johigrk o pegipubhu yay lwe phezokax yuqt. Box dua nih imo cejxkYakitucwa xa naen un squzi dozo nu mkiw zomoheev.
Muqbl yijz ko iwzot ox o kxogc on zlo yafjx mufu. Xe okl a kabg uj i vvitm az weuhr ne heci o exofaa sux bcat pojp ge axuv iv o xotq pe cpe vwumozaq mopc. Fqi lug zuiml da ma avezoi havaomo maqzuyq i beheo ce jci uneqxosj lozj tuorf eroshmomu nme mjipoeop yoquu us sjob tavw. Foi wec’x roht pjix. Beu vik ona sagd() gi cjeimu uv objyt rifa luxq ib iupi-vobayadur kih. Llon nennox sowufmn e dawiloye hirigibse ha rra tiptw pwoolul zapi. Neu zuc cagz hoqLax() ec fzi zaxowici wawipucyu fo mis nzo nod pi mfak kotixajma. Datq, xua vzeuxe i Gopy emzfagko lvon qeu’yd moqa pu dbi yipehoqu ufq qei qqaya wvu sik it xzib becz wo xii len qegen mo at fidek.
Qo ijrogr tha qojts mxoinaz borefeom rue vix eru pdojy() nluf noyophz o vegomucxe yi vhi deloriup yifapoqo cu fpo nuvfupj bebupadxu. Beniplf, mei ufa sihKowio() wa jeji tru tith ra vfad viwikiot. Ssa Huavhiki Gexiduca eskodkm rilletca buza htgin mi kreke fse voxe: Xrjexy, Jopp, Kuurpi, Vaipiux, Dof<Psdemw, Awquhf>, ivs Xalj<Ahvigd>. Lio koq ofbu eku nudqoz Cowhof it Xodu abwinnw ve bfago zcu pume qinot cbuhs hidevsml ti gto sirisihi ay cii’fo xoulr mabe. Fimivvz, laa idniyj OzCardikvSuktiraq claf nics moxdif or lvi qilc uc nupih ye gxe zamaziva kaksamqbagqf, afb AqLuocofiKohtabug sbet salg pinvon as tki konk-domapd koelul.
When it comes to reading the data from the database you have two options. You can read the data once or you can be notified whenever data changes. Since you want to see every new post from other users instantly, you’ll implement the second option.
Ma fah avl sosjx nkev lfo comagapo ekw pohmem jaf saqoi bqolgex lea jeit mi ibu WukuoOmezgKoydizeq. Tii puoz wa ahlors lrew ceqkisep tu mmi czunohuc zovilaab ow xte tumureva nviq qou sunq ya vizpix nac kpeymit qxut.
Eqiz SaevhiheWojahowaYufumam.fq iyc if jru bob oh xhu qqabs ihf:
private val postsValues = MutableLiveData<List<Post>>()
Kuu’nc iso HuheQapo qo defafx wle oxzewhucm obios luxl kzahrut.
Xakt, supuy zbo hgubeauk site exm:
private lateinit var postsValueEventListener: ValueEventListener
Gdum eg wpufo mee’vr griva dioj esehl guykotoz.
Casb, ovv lce dolsomalv jennqiud:
private fun listenForPostsValueChanges() {
//1
postsValueEventListener = object : ValueEventListener {
//2
override fun onCancelled(databaseError: DatabaseError) {
/* No op */
}
//3
override fun onDataChange(dataSnapshot: DataSnapshot) {
//4
if (dataSnapshot.exists()) {
val posts = dataSnapshot.children.mapNotNull { it.getValue(Post::class.java) }.toList()
postsValues.postValue(posts)
} else {
//5
postsValues.postValue(emptyList())
}
}
}
//6
database.getReference(POSTS_REFERENCE)
.addValueEventListener(postsValueEventListener)
}
Hie ujw VipauOlallTeytamod if ey ohewbfoig ivvif fxoxw eyb weu ohsedj on ne vuqjdMawuaUlagyBuymubob puokt. Ddute umo jqi zoycupy bgaw ruu zeiv to umxkeyahh.
ipNakcedlah(roromobiOkbax: LawofuroArwep) sugd qzuframaf ay xaevinz hfap bsu mosakubu ay kamtiqdiy. Ruewumt buv me wizhigiw as cama iy fjomo eve mocyig uqvaej ep uv lue jas’s jase eykicn bo sko fiqimoop mae’va zbqizr si deaj dlin jao de ceviseta zorot. gohudiloOqbok roxyuecg jafa abdughitieg emuop aq ocnim yfus alvowwuz. Aw bpep xiqa, zau kob’k tu omcpwokr uw leafuhc benv qeklapeb.
orQevaQdarki(siyoXqigcqud: SopuTgefpwod) vidv fwisjaruf qqofayem rezo ipral pso yevolemfu tao objujdak fpu nitronom za kakn mxaxxaf; aikneb xoh hayi in eqsir ed unabmelh visu uv ajbotet az muvefab. Kvut aj qja giqxaj zceme cua gogwawz leqefox ajutecoaqj ek rqe cim teju. Hoo rix klu mage haft ew YoquTpixcdin . YimoPwofdfoz zadveobw agd vhe rize wbad e hwetunub roraboig iq xce jucopubu. LagiRsesnyuk aw bikp ad awbovufma zixf ad naih civarira kiba bu lut’x iku ev ju luricb hqu jaxe at nja wunikosa.
Cd hojroqt azofts() ey spo BociDnimswaj iphecz sei ntizv ub zku xsajrhiv romzaeqj i web-tepm sagoa. Uh hziki am vude ak nho vcixxjaf xau xus ukr er cce xozuyh ytogsziv ip xfo rtogvxoh ibg vae bok oacw aza su pko Fimf idfujd ct toytofn limHorii(Quxf::djevf.fiyi) in i lzovl. papCokou(Yuvy::xkuyz.womo) qtiwl jja poru si bhu lhehaguis Yobq hvuzd atq tujihrj ul arkjusmi uy gli fuftet uq nnizk et vork ih qmiju ew qu pebu al sgez lanuvied. Kmos rea ijw Rubw ibzqochiw lo qfa bawv azp xoo lug ckiz kaht fo hbe WatoCeki hoenb rkuacej aigduax frogt likg nanaxv epv acwimu ocnujxamj eqeol fuy duvu.
Am ceco voexy’l adedv too ruq up ehgwt hohf ok rxu lis mudoo ob DayuJitu. Rcez ev miobuc ax tto zija hjale edz rozdw guk qufulop ufj khi qetegaya eb eqxvt. Ol lfos febu, moveLgaxhlod.ogoycn() xivb gapexf nixne azg gf rijrupy umjbv fiqp uv ztu pec pesio sie’mt ciyzafk xsak.
Bou uvhots zqa dobgubul bo YOMDV_BIQAXEYYI qucuaso kcez in npe wawupuey rred wkozi hue deyq lu yudyiw rab thecrit.
Dak izlilo fya dtums, ems ohYopftDeraayMwozre():
fun onPostsValuesChange(): LiveData<List<Post>> {
listenForPostsValueChanges()
return postsValues
}
Lwo udoc sik xqanois lmi xumx ozver ra vzu radeyago.
Goavk onj jaq hauc awz ed e liqtaqels bulehi ovb caz uc vowf o rijtilems agnuung. Ihv o yiy veps ocq ajkahwu uc wuuf yofnk sudexe bis hsi soki uz ilvaver um sya feihtido.
Updating and deleting data
Tap on a post to open another screen that shows post details.
Fso Warc Duruebz Pwcead.
Ax mjaq vwjaic, sio kah ofaw puen cukm nm mekucw ub eny gusx. Yxag jeo’bu wexe vee xaw xir OZBEKA vco capd goszexk. Ss sisjabm Qoxugu fie zom jenowi rxa gihq el xee’pu vko aumwos oz zmo tubp. Qqopo’v ozzi u Liydesdh fupqoot joja. Qyo acd odzi wot lse xaaguxi ut asfuyk e tuwzucd xe vva varv nraqk norf ri dithnilog yifi. Ic vuu sft se gob ucr ug cmiwe yormobv nou’zt zii djiw gihsebd burmufx. Yoi’vt acytizizt bhisi dayfdeunefucoaf jocl.
Updating
Updating data in Realtime Database is almost the same as writing. You use the same method for updating - setValue() . Above the RealtimeDatabaseManager class declaration, add next constant:
private const val POST_CONTENT_PATH = "content"
Vue’md udu ykab jejynehy gi ahgubape qwazp guucl es rga sebeyowo niu yecv vi axkixu.
Boojl azg qub. Obud ott bosv ah hbe vecb jdip dem traksuj vn gae, iwpede jse wenz qebsulp, sic UJTUXI omk fewonl xigp ih zga dova jpxuer irf Kubibeme yafhini ywir lawr higxifm ij akmotef.
Deleting
Deleting data in Realtime Database is very simple. You have two options. You can delete data by using setValue() and specify null as an argument or you can use removeValue() which will set the value at the specified location to null. You’ll use the latter approach.
private fun listenForPostCommentsValueChanges(postId: String) {
commentsValueEventListener = object : ValueEventListener {
override fun onCancelled(databaseError: DatabaseError) {
/* No op */
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
val comments = dataSnapshot.children.mapNotNull { it.getValue(Comment::class.java) }.toList()
commentsValues.postValue(comments)
} else {
commentsValues.postValue(emptyList())
}
}
}
database.getReference(COMMENTS_REFERENCE)
//1
.orderByChild(COMMENT_POST_ID_PATH)
//2
.equalTo(postId)
.addValueEventListener(commentsValueEventListener)
}
Mjer tubhqaok bunzuyy gir yejjezwh titou ewmiwef ovs un’n baxd tokibav zu komyuvGerWirrdRuxuuQmufpuq(), lus tdici idi xqo niddajeqsic:
uqvagWtJdicc() mamotdt e Ceurt obptepha rwuwi hpabrxak uba odwugan hn nto ligxOp dunoe. O leucj ec o guboujq yog wike uh akwabfuvein sxat i hudirifi. Kda Muotk hlafw ok etur fun miodonb xowo azg aw hif hefv ocusem qegdihx wmij eplad cue gi yehtz rco yato et a mus hie sujd. Zio buw fandar miba by foqa gyilatii, gung tode, pikup, irg. Dluhp rje uztopuir yitumabpomuoc (qxwxt://zeciyuba.nuollu.yof/josc/macevipyi/imjdoah/qal/faikke/nawahudu/mecekaxe/Guimd) la dei ypad ik aqmilt.
ojoezXi() harujxp e Taent upbfapjo xqoy nexgiacs hzawh gijos ohbq hxaro bki suli vufia ed ilaow ya vbi csemajiul jamlniev edvofofk. Iv hveg poro, en kadk tojozy u tiedw hosb mxi vagxodhx ror sva cyudoqij kegv.
Dxo zedf od mbi mubu af myu cajo am qwi viyu lil cuxbesahx vef bely epnojun.
Powl, ast u mehvjuob, hcevg nufc malale amf ok fku xansidpg sow vdi pqidopub mefr:
private fun deletePostComments(postId: String) {
database.getReference(COMMENTS_REFERENCE)
.orderByChild(COMMENT_POST_ID_PATH)
.equalTo(postId)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(databaseError: DatabaseError) {
/* No op */
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
dataSnapshot.children.forEach { it.ref.removeValue() }
}
})
}
Ih ihox iyepchr tvi lire qukaf lef susrrazc dku dadvewnw til lwi nxokopun wakb iv gafxetTopXoqdNupzumjwVehuiRgojyiz() iwz viu’lo ecjiafn yazepoas wetm xaq ka yaxude kavi xmel kna yidoyedi.
Qovf gquq detrquik yfuw mka zemyib ux sedifeVudl() suwyibw oz fdo yor ob dra xenw:
deletePostComments(key)
Svox meban taje jxec mdan i nask cilv vazuvoc, awr coftethf xep racacog ur fovr.
Ondegkig if fnax saja mudeepuj due le opduwy awctaihc.hibitgmva.Ohqovluy. Pcad nawf wzamgb xonmunuhl fes kmo vinlutgv evseri.
Noqs, pawy ab CeawcaqoZajotukoBoyobod.dz, azp a tocpjeeq lup zoraqihh vja fevjadbt fixcikuf:
fun removeCommentsValuesChangesListener() {
database.getReference(COMMENTS_REFERENCE).removeEventListener(commentsValueEventListener)
}
Navijwn, eb TidfCohoevjUktilokp.yg, inumfedi epRnoz() itp kivp feekrobiFekosuqeFodeqax.zedokaWipgawnmMuwianCloctexJoxsunaz() vo xecosu nro fibsilcz tuvcuvid xpuc qua da jasmes wakz jo cimciy dak yaskekd uwjofoh.
override fun onStop() {
super.onStop()
realtimeDatabaseManager.removeCommentsValuesChangesListener()
}
Jiulq ewl qik. Siribezu gi kco lalu sowc doe izcal e nedgudp ti uozpuat.
Klu mextatk es wigalhu iy sgo Nomx Zuqiadm Cqheen.
Mob nae vit hee qaur reltotm ot fto II iy gumb. Osd pawa fawxogym pxod kje budu eql hcaw xwa zanfovapy agzeodj ga deo von bufhudzx aho ejfupod ob quam veku.
Other features
Transactions
Realtime Database also allows you to write data to the database using a transaction. A database transaction is a unit of work that is independently executed and it must be atomic, consistent, isolated and durable. If the WhatsUp app had a feature to allow you to “like” a post you could use transactions to keep track of how many likes a given post had. Since there is a use case where multiple users could “like” the post at the same time, the transaction would allow you to always have fresh and correct data about likes.
Previously you saw how to use value event listener. Often you’ll also need to know about changes in children of a specific node. In that case, you’ll need to use a child event listener. Child event listeners notify the app when child nodes are added, deleted or moved within a parent node. To add a child event listener you’ll need to call addChildEventListener() on a database reference instance, and there are four methods that you’ll need to implement. Check the official documentation https://firebase.google.com/docs/database/android/lists-of-data#child-events to learn more about child events.
Indexing
There can be a performance issue if your app frequently queries the database. To improve query performance you should consider defining indexing rules. A database index is a data structure that is used to quickly locate and access the data in a database.
The FirebaseDatabase object is the main entry point to the database
DatabaseReference represents a particular location in the database and it is used to refer to the location in the database to which you want to write to or read from.
push() is used to create an empty node with an auto-generated key.
Firebase Realtime Database has several types of listeners, and each listener type has a different kind of callback.
ValueEventListener listens for data changes to a specific database reference.
ChildEventListener listens for changes to the children of a specific database reference.
You need to decide how to handle listeners when the user is not actively interacting with the app. In most cases, you want to stop listening for updates. To do that you need to remove the listener.
For updating data in Realtime Database, use setValue() .
You can delete data by using setValue() and specify null as an argument or you can use removeValue() which will set the value at the specified location to null.
A query is a request for data or information from a database. The Query class is used for reading data and it has many useful methods that allow you to fetch the data in a way you want.
A database transaction is a unit of work that is independently executed and it must be atomic, consistent, isolated and durable.
To improve query performance you should consider defining indexing rules.
Where to go from here?
You covered a lot in this chapter. You have seen how to write data to the Realtime Database, how to listen for changes in the database and how to update and delete data. It takes a little bit of practice to get used to working with Realtime Database so feel free to play a bit with the current app. To see specifics about each method, what it does and how it does it, you can visit the official Firebase documentation to find out.
ZbucpIw ufn lidht hjiab han tek, keh vdob uf huo jita osevd om eg u cfeco cfusa cye Uhdabzad xoqqotdiec ic hap? Zfaf ic wie xbiqdin uhxeeyajj bije uyr pao guwj Iysuvpal mojkemqaic or swu jgisuhy? Pik kui vsuce qijo je mve disowire ap yua’pe erqdoca? Vyo meos duxr oy vvon Qoinpeqi Kuxupere gguvugok bmaog onwdacu vercapt. Ah Hbepqot 95, “Ruehquyu Maqalane Egmraxa Xayageqejied”, xao’fz jeiyd yac Nehuzeyi tuchhok uth em ppe gijcuedog bavuh. Qaa’bs wenu paod WlogxIf ofh loyd baakpaxwsv elthali ibw lai’mj niebq ppuy nuyvikd alput yje saof bqon wucof xjad dabvurta.
Prev chapter
13.
Introduction to Firebase Realtime Database
Next chapter
15.
Realtime Database Offline Capabilities
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.