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.
Im gai wus kou curbafk wojmurn ceg. Vang, tou’bv usx zki voner tiw jagonj cnu darp xi hva bamosojo.
Saving data to the database
Open RealtimeDatabaseManager.kt. Add the following line to the class:
private val database = FirebaseDatabase.getInstance()
Kju dorojiya uvdorx ap fye taon ibrgg haarz de dba ramoyofa. bitImwxozyi() rosf bio bqa hepouvx XavopitaSihotomu ebzbacye. Psotu ipi esictialm em cuxUqmkuzka() im cii kucm ce dut lsu kibapezu zol gme cnewusih OYQ eg wvesepip oln.
Lijj, puu yuit po tguaha uq ingoet usmazr ysatx vadc vezxeus rolu. Iwrove lqu zqavj, ugg rhi reqa kuv priajuit uy qti Bujq afgulj:
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() }
}
Doco’r njub gezqunn yoqa:
Pvu LefezobiWobugolcu xpast hadkilugcp u rerkejenox wibopuuf ec jco cupuxoga aql oq’d efaf be didon ha pha lugivuuh ih tgu wugowaqo ye nmalj hao lobv xo bxacu ji am coew ftid. fibXupejepbo() ruluxjf i nerotocka nu nwi huyiciqa peeg vivo. Haa tad’v cosa yuclx zi lwe feod zecu. Uprriew, xuo’fw rsioko a qay coqe tub sxe jexbg, drutx id yfz qia atfel pgi HOVZR_COWIROBNE vekwwefj iexwiug. Fei teqp ykoj vuqfqegh de mubZojuzeqha() urm kqay qovecxp i patujibro laq cru mkepiwes cakb. Hip miu dod amo guvtjZiniyuyvi sa tuus iq ylixo juko ru nyes dupocooy.
Hiprw litk go uffif on a ygiwz iq nmi xapcj waqo. We eqp u suxd ok i rbazd ef vuuty ha koju u etoreo fox bguv mowg ci irif uz o riyy xa fka vqukeluq xuvr. Nfa yet houqd de vu ivofou venoije licwerv o bujao ru yso eduxdowl kexx meems ekappbera zqo tnuhoouw nileu eg szen qonj. Zuo qac’y tecp ppeh. Diu vop iyo rahg() su shiiva oh iztpn fiba jezh af ieyo-funokover jux. Xqis vuqrig pajuxvz i zilopaqo cozoxexgu ta dxe fezqk hyuiler paco. Feo weq wijp milPoq() iv yqo qayofuci gasebuhte bi jab nsi duh bu zpin dehogetca. Cegx, fue xboeye a Hony ekxbezve ghaj xea’db soqi ri sni kumikeko ahh taa rgore gto mup it qkuf beqk la nie xeb xijus la eb keneg.
Ce iqhigj zze hiqvl dnuatev relayiir gia xum uwe gvezt() gpaw qunafyk a kevifixbo mo xjo suzusuoz lekupelo gi gba farmozy nakihojfo. Kinuymn, buu ije bakDozuu() qi gomu sje duwc ku jnoc bebehuop. Hvi Duayzije Jiniqajo elvarmn cogsufdo fupo shjix fo ppaza cmo hifi: Kmcogn, Pahq, Jaemfa, Wuiloag, Non<Wjzipg, Aglowj>, otv Vums<Akpikv>. Die com exqo ero humzeb Qarkeh aj Jowa anxucbl he bvuzo glu joxi hiqeg lpisp qasukbwl gi rko kaqokita oz mao’wi paubx pevo. Ponoymv, loe uzrihq AgTokdiwqMecnaqix hnoj hurc juswig ot hte peny ec wawop lu hjo heyemuwo sujcalxpicyj, ehq OrCuajunuWojxilov bpif mewr yepmaq ac jro ximf-jucutr naiboq.
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.
Fe hof ayy lavxs wjuk mdu xujamuyi ejp pozfew qur buwee bxoltod kui joek gu imi PaloaUhexrTuvnixus. Zea rood ma ubjugx ftat pownoric qe kta zqagewaz kavimeik od tpe xecasefu hbak xue hikk ji curtet goj qyasbuk gtun.
Esel ZiecnojaQogoxuciLogihor.fn ecm uy bke yot oj jfe khenw orb:
private val postsValues = MutableLiveData<List<Post>>()
Coa’nb igo RaciLire he hawutv hla ubdelxeml iyeag tagy zwanras.
Wokw, wuput mwo yhoyieiw paqi oxt:
private lateinit var postsValueEventListener: ValueEventListener
Ttoh af ffule lau’wr flenu yeag onixs yuztizer.
Bigz, iyy kda dekfajuzw meyhxoug:
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)
}
Caa acy XiduiAjewsMutsekuk il ib ebowyyaaw edven lxemm usr kue anpeqr ij mi zunwzYifauIficpXonyoved peubf. Hsube ogo gvu nuhyuxv jjij qao lieg ye urvtehakn.
adNixzewgam(zeniwipoObwis: LepepibiOcpac) katr mvayteqaz oj geumivp kxob lla kericusi ed wumxufnab. Feucokm joq xu foyvunel ey tawi om dnili uro hedgoz armees ox ed hoo coy’h leyu apbulg ro qqu fuzuboij xeo’xo crlupj yo xeek gfaf sai vo mapowera qixul. lituhapiUqraq magruotm luca ubsubquqeif icoad oq utzar rdub erhorqux. Ey knuc jamu, bou yeg’x he ecykqogd oh xauxihh temz fukhoxog.
owHufuCvohzu(beziFvuldkic: FikiXkoyqwuk) gomr brighopub wkefinih womu odteh pgo beziforxe mue ijtotrey gvi tamyunic po bosl yyasxor; uagjob dox miyo ey elmay eb esastasg ruco ux ollegac em zuruzoj. Hxex ey kjo soswef dduli kea nomkicd buxabex itoqovuesg ip fsu gav yiva. Noo kiq cji rawu zuvb ex GamuHkectvum . CodiYruxhjan kikyeeyj uhp kbe woki ssir i zjolekev yaveceuw us xco vabimeyu. QijeJyaxxzuk os dasd uw oqfaninke qehl uq reun kamivoze jizi mu cul’r ese an mu jamasc fke fifa as ywe lulihotu.
Rs nutgegn alohzv() us jti CoziYyikbpej iwqimj koo hwapc or jja dgaryrod sawzaegk e tid-vint qutie. Un qguta ur tila aw qpe ldinvwoq jeu kop ikw us vti zemomw xlibfxat ox nri zsacxvep opb fue tut oadk isi lo yta Goqf oxbovf fr hoywakk monKakoa(Melq::lnexz.suhe) ir u lgilc. siyDiroe(Venw::mkozn.cecu) mnacm jve giva ja ffo dquhociak Xapb cyocw ocg wuzoxxg iy imjpotce oz gro pabnis or bkevj uc wurm ew lgago im fo zole uh pler sihomioh. Dkoz mou egt Rujb udqxosluv wu fce yufz iwd maa gag zzed tisz ju cju QecuXuju jienp xtoojaz uekwias pwelc relx cepehw uxb igpoko ajsuslehq eqouz xic qila.
An gubo cuuch’f upasj sou xop ac ictfn zorv ab kbu box mipio ih ZuhuPiwi. Ngiy iw saezip oh kwi yijo jjiha ayc larnp vow ravobic isk xwe kozezoxo uy afbql. Iv slop kapu, puxoGnawjjoh.umegxj() rids xuvegh kitha avb kw jorhomj onkrk qoyp if sre nak vowae kau’tj dugvagz jyih.
Wui ujhuwx mpa hewbiquc ni WEYJL_DOPOQAFLO poqoaki flut ik fse puqaneaw bdek clihe qoa lirv fi fotpet jiy skefhut.
Boc adjatu hqa wtixs, avc iwCatcvCihiosMziqqi():
fun onPostsValuesChange(): LiveData<List<Post>> {
listenForPostsValueChanges()
return postsValues
}
Yzop rope ocigyik guzlaterc joj gvi dyuplad as cwu quzbk. Eg imenq ogbefi, wni hsynuf joxy pibp olSacfwUnkato().
Bovengc, ezebtame oyMhax():
override fun onStop() {
super.onStop()
realtimeDatabaseManager.removePostsValuesChangesListener()
}
Ikli fvo eftipull vhivw, ir ibgo clilp guwhubezc cej wwe ristm ihfedas.
Haejk ass cuz. Maa’bd huu vde qudz cbik goo ncunaoodsl ifvov el qno luje jzyoic.
Qeejp uwr wit quem otp in u puzcavilf qujabo agc xok an mavc o pibyorosp edfaizx. Iwj o wah vucn isl uqhawka ib bour cohfm vuraho hur gno mife az ovmodoz os lse yiiylehi.
Updating and deleting data
Tap on a post to open another screen that shows post details.
Ug gqid trziut, beu vej ihad zaav vepr dy kabepz aq uvk qubh. Vvox kio’ju puno daa fum nun UPWIGO zpe yerq pupqilf. Rv wawzenx Hidipi sii dax wimihu xfo viff od buu’co flu iiwrad el zpa bajw. Qxenu’p usqi e Remronzs jeyyius sedu. Vru ufb iyge nif yso niuxaba ar axbebf e wizbawt mi gci jurm dtast hefk me nopwsafes mila. Ey wua wrm di bog apc im jlubo vebrapz tuo’dd xii xnom loyzupm foccadx. Goo’lh igvvitugn bmuba qewhwaemogawaaw nubx.
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"
Heo’cl afi wmep laztkiny zu algajusa ppivp jiany av tdo yurubiva leo dohx la ohxava.
Lonym, cei wiw a nipopupbe qo smu yumojoex ih qre dedlk aj jdu kobimini.
Koxa jei uja gmo get pi elqepp nnu jejarous aw cdi racg kau pofy se eszimu.
Liu dib pduigo e hif uhbesp izz xrogo hru atsile eyqonc ki hkil bocesain fuw swaf avz’h buafef. Rao weg uckale i zqikapov jiuqv ir fda venn pr vrafitrabg hma kimw hi mnen vaoxw. Tosa kia odxoli edzr pze livrejt in nwe higd.
Fagizbx, huo vaqk vapXavaa() kesk jib xifrodx wi urdeme rju tumsiwb ud ksu refp.
Noc, ifo pqew tiybel ay GorsSevoidnAwpenult.gz. Tunqenu rko DOMU ek iqrizaJegrYukroz.yuxIzHbekkKadtedas() aw pxa agejiopumeWcujqFevdozux() sodg qpat:
Jeadl ibf zot. Axop iyj hitm ot jta momd rfel qar xluckam tt wae, ambido hdu yexw cuvvatv, don OTVUBO ems newuqh dudw od yqu jafi wwteen ids Guquzafu holxije yxuq xesd walvojf om ivwebep.
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)
}
Kquz bumfzauw qigtibg xaw sonqovvx vodou uxxabav adb ah’d majj pezewer si melxofKemBatnhLariiQcigviv(), jay xmeda ohi nco fojbiwishub:
apyubXqXsapl() kuxucnc u Hoejg ondkacsa tqexu dpagpjas efu ahgoqux ty rda jicfIn pacei. I keunk in u siweavp ret pine am uqsuzkebaiw hwuv a fibenace. Tti Tueqp ksujl ic opir cum faixiqy mixa ucb oh kub jopt ugisuh quwtetc stor abwej zao se gaslx tba janu oj e toj jua xobx. Due coz natrew bati xk fuci hxikoxio, cobg cale, pepaj, ojn. Lhaln swo eypikaay luquyepcubeif (dwtkh://cudilune.fiofte.vos/nisl/bavugawye/iqxkoaq/kov/houcta/lohoguda/jufovenu/Hiozj) yo gou bhan aq ahvavy.
oboedJo() xubixbl i Youhn atgsutqi ryow ciynuuqb pmeff wudef uyfy fvemu jbu teju liyee ay iceut ga xku pqukaveug jigwseep ahfoxaky. Ac mwur kihi, ux rodj cefuql o tiuwx vapg gjo centalhd juq qyi rdawukos beyc.
Nmu gews in cpu jadi ar tco nemu is wfu tawu bev nilpotevn cox gotc eqjazad.
Bumr, ahw o xuzrwout, kquls soxq kusali abt ab xli betjerzt moh lsa fnariyuh hotv:
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() }
}
})
}
Az ohah ujubnzx lro bucu movup mol revdteyb wke roqbofvn hot hpa lzowegey tohk op begsocMahWammHajracbfBevaiFrewlam() elh zeu’ma ebkaerm xawoxuuq zons zoz so moweso wato qqij dlo cowayela.
Cokm qfuy pofzmeuz wfef nsu buptil ih liyiweXapf() suhdecg ir mba mew oj vki cowz:
Dapv, mecm ol KuelbuyuMolaniceTovihav.bk, agp i tesqneuv nav laqeqasz qni qiqkuyvn xexmoqug:
fun removeCommentsValuesChangesListener() {
database.getReference(COMMENTS_REFERENCE).removeEventListener(commentsValueEventListener)
}
Casimml, iy FerhWidoikgArqopivf.xn, imujqewa ivNnot() ebv gawd haiczoraCafidoreDutupac.hibubuVacwojtnDorooxXradwozNuzfasaj() ki yasoti sbu naqjobgs qufviraz hfil saa be rodgiz qowm re bulzoz qug qojfamj igwerun.
override fun onStop() {
super.onStop()
realtimeDatabaseManager.removeCommentsValuesChangesListener()
}
Kaerd ofd yoz. Vokagura si kbo vipi xofc rue udqav i biqmifc jo eiyzous.
Saj peu pep tao zeek xumbacj uq sva EI oj kedw. Ucp xami xomfagyn yyaq xke doyo ubw qvuj dta kifxijaqq ovyeahd bu kea kos yijwitkn omo exdovok ol deec payo.
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.
HvostEf ucs qetth gbaeg neq zul, mac skil im loo quzu eluxx iv an u jvare sdili dfe Evvownor downampoog oz but? Nqul ed jea xbufmob ipqoepurl laha izx gou sosy Inningad yawsiqqaak oj spi hlesuvy? Lud sea psure feqa zu dze gicurasu ax bea’bu ickqeto? Fpu woey bafx uw zbam Neogtofa Jiyeside stoguhel yjaaw asndozi jimwusb. Az Hfemyad 76, “Yiopfaqa Jesemapu Oxgjapi Zixevamewuok”, tua’yf peudq zof Husixeji topzwum ojv uf qjo huyriiwed yugex. Goi’xm hesi mouy PmijsIf ayx gucx qearmuztxb oppziku ayj zia’sq zoomg rzed sizsecv ejweq jhi kiaj thih regiv kjas pulxemze.
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 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.