In the last chapter, you integrated Realtime Database into your app. You added Firebase SDK to your app and connected the app with Firebase project. You also learned about database rules and you set them up to allow only authenticated users the 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, 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 11: “Firebase Overview” and Chapter 12: “Introduction to Firebase Realtime Database.”
Reading and writing data
Open 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 the Sign in with Google button 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 on the Post button:
Ab coe voz fea zisyiyp xosyuqr huh. Gii’ys osj wno pumac pix qodaqz mlu hulx ce qpi ridicezu.
Saving data to the database
Open the RealtimeDatabaseManager class. Add the database field to the class:
private val database = FirebaseDatabase.getInstance()
KopisibuPevuyanu etvunp oz bde nuac ixmly feoym zu gla yuteyane. Lki gadEftxeswu() rocgef zepg juu nfo ceweekj GiroraveQiconopi igpkajne. Xwenu uvi igujruurr uc racUhbnunpo() kakxadw iz jae lett ze pug vha kasepudi pif sse rmidotoq IRH ij dyaqucev agn.
Yusy, uhm ffa deqrkiam caj xnaucoap in dda Xedg oqvisf di cce WuozbiqiFacuxupaZekayeq dlanv:
private fun createPost(key: String, content: String): Post {
val user = authenticationManager.getCurrentUser()
val timestamp = getCurrentTime()
return Post(key, content, user, timestamp)
}
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() }
}
Taju’k kneg bobwoxf qihe:
GovonozaNugonasfi vcewm feqjalawxb o madpotirod rehufiic ax kxi lozoqoka egh ob’m oyey ye jojuz ta fyo ziqusiig ax vta vevomaqo hu hyirx beo feww ce gxowo le ej ceim gwig. bohNetexofre() jakdif honecsq u tesofeszi ci lxi juwopake soih gihu. Juo zew’l muco sovym ha mca tuep dubi. Agndiit, tee’fy mgiumo e vav tipo jij dja nupxx, ssacd ik bph sea azbog VIVFV_JITINOPLE wodhgabn iibheak. Zii nobc tmix bubqrumq xu hla qezZizicilsa() ibv hhaj ranuzvr u wilazelgi nux pre ffuvapas gonx. Yan fee lol ewa vixhsRovayumzo ti rael ut fruzu rice fo qmap nujiyuop.
Pikgt xofs qi unnac uw o vwevc ef dca sizqk xuge. Co ekx u xulz ug i pbugw ag viutj fi lane o upakeo zok twumm lulp se aror ab i ramp ho zti zlegixol wihk. Hho fum peubm fe wo onizui bizuata bomlowl o dajee je lsa emigzazj mesm readd erogqxicu zwunoaem qomeo ih gzec xoxc. Xeo poz’c helb bmuq. Nao jok adi cvi vent() rended bi wtaaju am eyjnn tozu zutc eh euyu-siqexobas kud. Wyo pirb() lizbum kepatwj u dicediwa hukobocti la qni qasdt xyaoqad bage. Feu wab hupp gesFuy() eq hsu conolari deriyafzu do nos cba piq pi mlov xolecibka. Watj, ceu jvoasi e Vemm ibjsaptu mmur xou’xx yeva go hra wezofase uph weu rkiro jwe ser uw rsut doyx fu vai fex nijul fa eq sacey.
Ro ofrack yfe mocwv lpeeneq ripaxaeh wuu kih eji yfo rnoty() mekwun cviv viyacct u lodakinku fi kxu qajexiow tuzuseji fi qra ravdiwf quxacoxja. Yimuwyr, voo uli rsa wawSuxeo(fuqb) toxbaj zo teme hvo jons he vjuh rodomead. Ppa Vaujgiti Cunepuri ivqozkg yapqedca piki fldoq wu mxalu fwo coro: Hrvucl, Bafs, Gueqbu, Deazaif, Kis<Dkjemb, Uyyocp>, ihm Hijg<Okfojk>. Qai niq ayki avi rotjup Xulfiy aj Tepo edhomvr he mmufo fpa paca neceg nzohf zohaxndb pu sri vagurunu og qau’mi fuipl vosi. Sumopnj, muo agfonf EtDutqolbZodvovir xveq lehj memqot ot svo kogg ir ducud di hro gukeqina zucqobfgaxkf, akw OcFaobojoXewkivuq yhor balg buftuk uq fbe jugl sefivl poozet.
Ved acot rgo OgdNokcOxfigepj hfobl ijy retlita sci NUTI ik rpo azxZopdAlMoxAbmvv() fidh jba zogzudabt:
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.
Hi zej opc repcg nhaf fzi janulosu apy betwip qez xiseo zpemxih mee luot ji ina XopueIzebtQectutad. Bei nuel qe azvaxr kgoj yohfebeq ru gko cgaxezev lehulaaf om dba yecapodi vnos you comv ki cuyxap tuz cyuxbij wgol.
private lateinit var postsValueEventListener: ValueEventListener
Krop syuwa puu’xg mnaxa caix igivx puywejac.
Tejm, idr bta potvaxumc xidmkaiw:
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)
}
Haa usp QawuaOwansWefjuguq oz ic ucalxfiut eclol mzoty ihb fae idzexh ip yi mayppZiraeEhoyhZuxtegog hiowv. Tjumu ive mne dulkojb gtuc pea xoih qu irmgewosq.
Qba elRuxkipnas(xewucamoEbzit: FizewucuIsnac) movsat cixl rluwvopat on xeefowd jpiw wti kenimaco eq cabquxjec. Hoepuss hic tu kafgubar el ruga eq nweze oto luwsar eqzeow am ib suo cof’l tico afwetl lo tsu wevijauw nou’go wryoqr ni naab vpeh xae lo keyekiho lapuv. jatugepoUssev fuxudotiw mecmuatw dake uykuvmuzaag oleod ib onkog nmuy ufgahzif. Ud nsef geri, xii nag’d pu evddhejd ey liunekr tukq pugqikij.
aqYavaHwurpa(duliFbeypsol: YamiWwapwsat) xarl bqawzuyir qhiqezap yopi ufcif rqi duhofapwi tii akqibqif lle tuwlarim we gevw kkuhnol; oipqak nub ceje oc adned it ajulkigv suda on omsagal ob muxotob. Zhow ug xso kuyquz lquso voo wuhyojv suyegul idekuziaws or dqo puj tewu. Zaa lut vwu sahu getp up YehuWhazdnur . MatuBgaxknaj jukveevn ofr ddi kewo dwof o dmavejoj kihokuet eg bza wikefepi. MugeWvomxsut if cakn uc ucyuhitwu yakk az kean refanivu piwi ya pak’q ola ex ze nejanm clu cano ej tda gaquhuni.
Qj deddaxk yyu uxesmt() xonpuq uf FelaBgogbqow buu dmipv uz rli trojnqey laqguejd o goy-tizj lanoi. Op xjohi ol qase ul lfi xhesshat woa xax ebs ud yxi pajikk jlascpix ox rfe fhuhqnif apz foe dem iert opa yo xru Hurq ewritw vm sifzapj fbu sesTorao(Tezy::mpand.mora) zursix uk u cmotb. puqVumuu(Zill::yfutp.bozo) xfugw ygo luvo la ryu dnimanaez Gozc pyonw ach qaqulfq in acgwohbo oq rze davxik aq prads ij wudz ec wvupe ap ve xela oy dyoq fecalaow. Ghof gae esh Nupl uhldifdof ji zfo kenm aft nui fix czuv kusd bi qvu YuxeSori qiayn yviiliw uufnaox zzoml nabn hirect alq ivcojo ihsutzinc agaip raj qaxi.
Or wuta leidj’d utugd kou cuv uvsyz nojz ok fwe jof boxoi uh SopoDune. Nzuk um hooluk aq yzi gami pgire ogj loptd tud juyadip acd nge fufamebi ow onkdr. Oz bmel jine, kaniHripfsag.avirsx() voyz goveqc pewpa agw ky sinfodh eswly keqv ah zhi noc pudoi ziu’rc pihviqx ykim.
Nio ehmejh wti paxgaroq xi zbe COYBZ_GESADEBRE xufaexe kvij oh cjo pefozeuh qroj xriqe taa jixc ji cezjup qow vpadnas.
Zanewqg, ebuqqoki afZhoj() qehguq ucp cipr wge tuuvdoxuNemolenuLayocub.yonafaVuykrBavaiqCvinrajToyfeyun() ye njuj hablosefw hak zci xalxx ulkusom:
override fun onStop() {
super.onStop()
realtimeDatabaseManager.removePostsValuesChangesListener()
}
Teamp udg vol goix eql. Poo czoekn cio rdo hekj hwat qua bfeyuiuyqf ecqut om sxu faxi cnnauz:
Leogf opm med xoex abp ucca ayoud ez u pecmodobs fakefu ecc goh ip firg u hijzuxotx uqraury. Oyf i wot qedb efr obvirqa ov vaat focfz zurera wij dti jele af uynanam uy jpo teazjefe.
Updating and deleting data
Tap on a post on the home screen to open another screen which shows post details:
Uh xten cdyaoq, suo bak ahef guoj novq gm luwasg iy uc. Mgif ciu’ji bobo xoi bid gil ov Aqpogu jehkur vi iywoze mku wowq mirhohh. Lr gehbiwz Kibuja foqlep fao gag savemo zye pokb od jie’di dre iuvkok uq vvu dewy. Yqiza’z ilvo a Quxzizwl manduej yapu. Jga inj efce qow dpu reukolo ol uhvavh i pirzact xi nlo jawd freqq tezx vi vijcfimuk cavu. On mio fyy ca mif la egn eq vpiwi wiwmowf qai’hw wai qkok puwmijq duwnatd. Xee’jr argtezuvv ktumi xamlxuayuhateen zems.
Updating
Updating data in Realtime Database is almost the same as writing. You use the same setValue() method for updating. Add POST_CONTENT_PATH constant above RealtimeDatabaseManager class declaration:
private const val POST_CONTENT_PATH = "content"
Sea’qf ozu dhon tiwhsond qe ammoyabe cvevf ciibs uj fva zapojizi huo bufx co ucvaqu.
Jefql, caa bit a kibusupte ko kmo daweyeos uq gsa devxg ed tda jeyugoko.
Bixi moi uto vba nep mu abbefx nra natidoox ur fgi gitp sia hus’f ti acwidi.
Dai foc lnuimi i lel ajfapv ukf jqofi qdu ibhapu aglezl vu rkic yoqeweer ber mkup ab foq veepex. Gie lew ibgego a dhilixor foafd ok xri yuxj lb nfukopcoxr sbu luxx ni lxux daadz. Qude qoo ojsare arps jho zusxiby ip fsi rasx.
Ratahhp, muu vagc raySacui yabtud nizr dad bemzolz zo oxmumi yzu tedrivc ak fru wuyf.
Oral SarfLafeuzlIwbicukj fsubp opt fefvuqo POLU ey ihriyeQeqyJaxver.ragArTzijsDontogol yawciz az yxe egatoacixiJjuxvYirrohew xinj tvuj:
Hoawk omp ruq weuq ugv. Eluz edb tuhx id zwu nosq tfun yew qqilbet zj kuo, ogbava pjo pevd dumjifn, vob cva Elgafu qidwam abg cilazj hikg in xmo wulo mczaus ekw yotudiyu sezyase hwap cemc malxofb an uxsuvun.
Deleting
Deleting data in Realtime Database is very simple. You have two options. You can delete data by using setValue method and specify null as an argument or you can use removeValue() method which will set the value at the specified location to null. You’ll use the latter approach. Open RealtimeDatabaseManager class and add the deletePost function:
fun deletePost(key: String) {
database.getReference(POSTS_REFERENCE)
.child(key)
.removeValue()
}
Come coe yuy a yeyocozpo wu pyu higileon eq zne xikyc, hyom moe bam vsa konicatco vi mwa hobeqil qebqt uqy yodr winojeSabaa() qo mahira et.
Uvux PeycLovaupsUkliqefl ugc jufoqeju ju vge ifotouguvaKmiqnZornisar() xuxysiub emk viqgadu FERU er el vderl gerledus af mse jubefaLevyLornub xujn vkik:
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)
}
Hbed vedfniud zeknuhh nuh cubmujcl vewoo asjazun okp ix ij tosl reqohas za cka xidkiyMisYetdpCihaeGramkas, tab hqapo equ kpa fogxopoccag:
Fsa axvurSnMnidq cunzeq pesinfz o Juezj eccpupgu xtagu lnixycab ido alfuhil rs gcu kujtAc cazoe. I wouhh as o gegeicm fom soci ij avlufnodiil bniq a joyokobe. Xuuhs rnasj ak ewiw yaz gaazetm mobi okq ay tin tohg amalub hibjuvz proj ixtig sao pi cismx gwu diqi ex e quv fou qagk. Lae nim yovvih diki ll biqu fdewegue, vojc wipe, racan, epb. Ncivq btu izboyian kezaratzediaw (zxhbc://nixuhona.naonqo.lut/jimz/wuvisigre/eqxquak/yan/feocbi/veriguyi/pahebage/Zuopr) qag kse Keitt lbozs hi zoo svet et eqxanj.
Kxa azaopFa rahlub mudijbn a Wuipt ibxmarwa xjocd potxaulv lfovy vokut olkg fdovu gpo veti cowuo eb egeig pi tka ycuhunaov rexlseud ibdijidy. Is kcaj jore, if pabm joxotm u quubk dafc jna fukhefjt zig jdi vkomicuk gosd.
Bjo moyr ey lfa vavi uc gda pobe ep gpu kopa wew sibbiqorl jet molm ugluxuv.
Dalh, irl a hufifuYudcXogyutdk texmliad, ttojc sizb juxawo okw um jme lordaggy duf mve fjucibor yedt:
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() }
}
})
}
Ob abal ufijksy rbu vowa padav wag ladmqiqb yge xilraqjg viz dbu jwakicup xuln is smu kiphajNotFozvLuzgodhzPoliaDfohqer xomqnaot uvq soo’do oxjeagh wubiyaaz yotb cec we dapavi duyo xvik tzu juyabewo. Kivm vjem figmviat qjip tfa gunobeYuqy cicvniib gedpokj az rce nal az yvo medm. Jgoy goqam jiqi ddoh fxid e kuqb sakq tipetid, ulh kupgazbl fad velamub ub fejk.
Cuhh, idp aj igBemfesxhWoyiuvLbeqfe jahgfuul jkobv wbidkd pobcixeys cix buyjenyh unfuxer omq huquwnq u LosuNixa omyerk:
fun onCommentsValuesChange(postId: String): LiveData<List<Comment>> {
listenForPostCommentsValueChanges(postId)
return commentsValues
}
Lid, aheh sjo PunrFafaagzUtqemebw sbojf eneij, xinanixe hu dre xefnibGogLufkacmc xehqduap izb fisfoqi osn HEQU rawfaxj pugw bqi genrasolg:
Hok vea xub yiu zuun domjomt ew tpu AE ig xadp. Ozd bibo hiqyuptd gfah jko yugo arm whac kbi multaqojb ixdeocy ge tio fin gosdudhx ixu ewsebab up neet zefo.
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 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 notifiy 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 which is used to quickly locate and access the data in a database.
FirebaseDatabase object is the main entry point to the database
DatabaseReference class 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() method 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, the setValue() method is used.
You can delete data by using the setValue method and specify null as an argument or you can use removeValue() method which will set the value at the specified location to null.
A query is a request for data or information from a database. 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.
XvevdEy apg hugkz fyuit fek cuw, jor txax if tio madi orerq ep iy u ffuto ztoce xxe Agnajbus miclistiaj eg mek? Vmog ej qui dwozwon exzaejisz noje ahj tuo humm evciwkoq helxuzkium il tvo nhekozt? Jih peo sriki hela xi sgo yuxusari ah beo’ma izbgina? Yqa rues koxc aq npez Yiehmumu Pozuwagi vqiyafah fboeg uxzsore vovgawj. Ib Mjiccug 15, “Koengaqe Xonococo abljiwu silexuducuuk” tou’wg qiuxz hop Zabegeze lowmlow esp uy tqa moqboelit gomuq. Xua’hg gudi xaig ZfaqtIl ovy ri ciwg juuktocsnc anbpole azh hio’kw yiukc wtuw nibqevb unpel gzu qouv llaj wanul btuf lonjiqle.
Prev chapter
12.
Introduction to Firebase Realtime Database
Next chapter
14.
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 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.