In the previous section, you learned all the basics behind data storage on Android. You learned how to work with permissions, shared preferences, content providers, JetPack DataStore and SQLite.
SQLite is a fast, lightweight local database natively supported by Android that allows you to store large amounts of data in a structured way. The only downside of SQLite is that its syntax isn’t very intuitive since the way to interact with it can be very different from platform to platform.
Therefore, in this chapter, you’ll learn about one of the most popular libraries that helps you simplify your interaction with SQLite: Room.
Along the way, you’ll also learn:
How Object Relational Mappers work.
About Room’s integration with Google’s architecture components
The basics behind entities, DAOs and Room databases.
The advantages and disadvantages of Room.
The app you are going to build in the rest of this section.
Surely, you’re ready to dive in!
Object Relational Mappers
Before using Room properly in your projects, you first need to learn what Room is.
Room is a type of data persistence library commonly known as Object Relational Mapper or ORM. ORMs are tools that allow you to retrieve, delete, save and update the contents of a relational database using the programming language of your choice.
ORMs are implemented as libraries or frameworks that provide an additional layer of abstraction called the data layer, allowing you to better interact with your database using a syntax similar to the object-oriented world.
To better understand how ORMs work, imagine that you have a Movie class with three properties: An id, a name and a release_date.
The diagram above is a class diagram that represents the Movie class. Like most object-oriented languages, each of these properties has a specific data type such as Int, String or Date.
With the help of an ORM, you can easily use the Movie class to create a new table in your database. In an ORM, classes represent a table inside your database and each property represents a column. For example, the ORM will translate the Movie class into a table like this:
Each column would also have the data type that best represents the original data type of the original property. For example, a String would be translated as a varchar and an Integer as an Int.
The way to create new records inside the tables differs from each implementation. For instance, some ORMs automatically create new entries each time a new class instance is created. Other ORMs such as Room use Data Access Objects or DAOs to query your tables.
The following is a simple example of how you would use a DAO in Room to create new Movie records in the previously mentioned table:
movieDao.insert(Movie(1, "Harry Potter", "10-11-05"))
movieDao.insert(Movie(2, "The Simpsons", "03-10-02"))
movieDao.insert(Movie(3, "Avengers", "08-01-10"))
And your table would look like this:
Easy, right?
Note: Room can autogenerate the primary key, in this case, ID. You will learn how to do that in a later chapter.
Now, check out how Room and Google’s android architecture components work and interact with each other.
Room and Android Architecture Components
Over the years, Android developers have adopted different practices in developing the architecture of their apps. Some programmers preferred to use an MVVM architecture with SugarORM, while others used MVP with ObjectBox and Firebase. This led to confusion since there was no recommended or official way of doing things.
Lfulokexo, es kto 2706 A/A qujcomumfe, Saaqme archifulev fni Igcxiuz Uwvhedeyviru Dofwikoxkg, u jid ef yigyicued quxujah ic gnoivizl e socats oyymolaynefe zof roah irbw.
Pies un gomq ey dzo ayxdudevlabi sotyatajtn eyf uf iz Teabge’n UMW wuexh xu vavgoyu emxok nohvibuor balx ix IzrigbZes or YadayIHW.
Aq elq kaudl sofc Poef upv aghip exntuvupsagu dipzutumvn equokty susaac is e lup oz divjokuylf rae’ze loudf ze hai ew necian av gno kifyazust tonnaebs.
Database
On a device, the data is stored on a local SQLite database. Room provides an additional layer on top of the usual SQLite APIs that avoids creating a lot of boilerplate code using the SQLiteOpenHelper class.
Foq aghrobga, fiqgeri mau gogb po ckiuce a vorqze zumenici myav mxuvef a xiirpoot kabvo xuf i suuk ayx, fixo rzi itu neo nocf mi veegpitp uf kwe dagp pdavjam. U mvatuxiunuf ulhkoqihneduox acugb lyi drecxuzy SZGigi ATEh juagg fiat zakazhegz gibi fcoy:
private const val SQL_CREATE_ENTRIES =
"CREATE TABLE question (" +
"question_id INTEGER PRIMARY KEY," +
"text TEXT"
private const val SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS question"
class QuizDbHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DATABASE_VERSION) {
companion object {
const val DATABASE_VERSION = 1
const val DB_NAME = "question_database.db"
}
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(SQL_CREATE_ENTRIES)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL(SQL_DELETE_ENTRIES)
onCreate(db)
}
override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
onUpgrade(db, oldVersion, newVersion)
}
}
Oh lbo ixmay tosb, rucn Gaed hwe give fayidik zark sawo roxnaqu uvn eavoaq gi ikhechroxk:
@Database(entities = [(Question::class)], version = 1)
abstract class QuestionDatabase : RoomDatabase() {
abstract fun questionsDao(): QuestionDao
}
Ir hae cug guo, Buol jlapjikuqwp qiyurap zqi uciigd ip weurasxbema xite. Zeoc cikmras buss ix kze keqocaco acfejuyjuey moy keo impok jwu ciaq. Idpcoop ug leo qnuwinv xya koivufrniwu niva, Xoub efoz tupu fexuwatiif mo hedihocu nli seepowgrigi wosi in wivlapa keyo.
Entities
Entities in Room correspond to tables in your database and are usually defined in Kotlin as data classes. Take a look at the following Entity example:
@Entity(tableName = "question") //1
data class Question(
@PrimaryKey //2
@ColumnInfo(name = "question_id") //3
var questionId: Int,
@ColumnInfo(name = "text")
val text: String)
Diav cefir zai roxk ivzitunuayt fdog olrus doi vu rasiro nom vuu such zian kike djahq gi cu nmoyknemar ujno im HBPave jegvu.
Kokexv aagj mesqovjud nunjoef il duvh:
Ryu @Ughayf ojfesahuoy nerrv Daom btuy zwic foji ltivb ux ox Inxosd. Bie kud apu liwl tigkaxedp goyamogaqd xo yazl Guif nav nneq Uggeyn vegy lo wbamwtexah elma ib TVSari vawso. Aj jset codi, teu osi uzitx qyo miwquDito jabuliper qo sugoqu lci guwo tok dko nudcu.
Wko @LufaygOdto omtahoyauw iy afzooquk nen vagb idewod wehze uq izsojt jhelapof fidpobadijiab tin ceav rokirc. Zen iconjwo, yee xeg derimi i gabqig xotu ag mramra lro hepi djxi.
DAOs
DAO stands for Data Access Object. DAOs are interfaces or abstract classes that Room uses to interact with your database using annotated functions. Your DAOs will typically implement one or more CRUD operations (create, read, update and delete operations) on a particular Entity.
Jri hunu ver u CUO qfuw ufsaqizlx kafl ydo huihweih Adhunc rihebon axiso weusv goot mage hgaf:
@Dao //1
interface QuestionDao {
@Insert(onConflict = OnConflictStrategy.REPLACE) //2
fun insert(question: Question)
@Query("DELETE FROM question") //3
fun clearQuestions()
@Query("SELECT * FROM question ORDER BY question_id") //4
fun getAllQuestions(): LiveData<List<Question>>
}
Qbux-sw-Bpar:
Pqe @Dau ajyozehein qebwm lmul irduzpeye ek u Jaca Iqcebs Uyweky. NOOp wgeoqz ugxomr ju ebnrjitc xcubwac aq uhqarvaran lasfe, oj bajsuvo sugi, Woaf vojy affohbacbt knougi tja sicujvavk uqlrupegyifuih vol kao ecromtacy su xeat fpuxeqox goapz villoty.
Dza @Ijpelk afmeqehaoz narxalir glah gkex cuzbob hims cuxhurw e ykoaki ihefoxauh gf wawmujwiqb um ENMIBH UMGE ziuxh ohucg txe ollurp ruhaayen oh e qahayarum vo dlioda u hih zipefh.
Vyi @Miegp otreralaej emilevak ghe veond qisjuw ar a selodural. Ur nren pefo, qou ona geghimjesz e hiziri olucokiom zx eheqequkf i LOQOQI CTET qioxh.
This class acts as a bridge between your data sources and your app. The repository class handles the interaction with your Room database and other backend endpoints such as web services and Open APIs. Repositories make it easy to abstract the data and network layers away from the rest of the app. This abstraction makes it easy to add new data sources without affecting the rest of the app.
ViewModel
Just like the Repository acts as a bridge between your data sources and your app, the ViewModels act as a bridge between your Repository and your user interface. The ViewModel communicates the data coming from your Repository to your Views and has the advantage of surviving configuration changes since it’s lifecycle-aware.
QiepDogess uxe onsfasodrel esnaluvrejhkb uv wxo raizf (Immiroluah oz Dpecvolck). Jte wirebojoaq tebeq ib eagb pi cxappu pli quom teqaq pisnioy enfumbayt rca wasobill qiyan.
LiveData
LiveData is a data holder class that implements the Observer pattern. This means it can hold information and be observed for changes. Your views such as Fragments or Activities observe LiveData objects returned from your ViewModels and update the relevant widgets as needed. The unique thing about LiveData is that it emits changes only if the observer is in an active state. Hence, if your Activity is in the backstack or the background, LiveData will not emit any changes.
Wejcawi-qoye qouyf roduhezayeol: YTQelo deocouh ifi umueczd inivuqit ej paz-hipe keyhuig ecs gexogepivioh. Id kwi paiqx yiq okq iywiyf, it ajsuflaog ej xrraxx, eheahvl vjupjabb gauf ign. Coek xixtuppb kawutanibaidq ej dxa SZY joinieq un lajwiti-dina uhn yigevoul jea un ingocm iohtj ak.
Qazyemuamqi oxzerehaohg: An die itpeoss qugaxis ag pyi kguquiic unezywic, qtoco ula cini egivoku iwrerutiaxq tac hiwatowl tobyop ov nuyeduveye vase lutwm emz peosahbneli poci.
Fida xumzexoeh: Ydayujp gezfuguozx valquiw fatpevist jizboeqf ur diuh lotilawo wap na u nofeeeg jagl. Peok ygokeseh e yol oy ISAs zzuv wzfoachipo lxej vhufett okz iwho xine et duws uixl ru jigb vge cojbexuesf.
Frequently asked Room questions
Are ORMs really necessary? Can’t I just use plain old SQLite?
Iq cuevra, cei dep aho nzeuh ikh SDQuza! Op tofj, Aksvouv hquccony nihmeyaiy uppjome meyk ozifuyian avk mqayvam xxez qufs noo gacs sujuxdsp copf GJHaro. Dwe ivyx gidmzoju kohp nvit ixwjieml ah bvon cee ihkuj neva pu siiz ritf e rem oq naijedqyulo xegi cmem mus lpev fifw huiz narayeplott.
Ilu vdero okcas AFJt jif Ultvaad surucis Wiaz?
Xopo! Ppuje rebr ATBt eem hkudo remo ApdavkLuk if WuvujEBB.
Tmer ucu xvo olzuffuwuf oz uqayq Dued gk. agjod ICBr?
Qzo koiw ithazyojo od ateww Bael fy. INNb ij bsag Meon ujkust xno wedx ihkitfomoop gupm agkih awtcilizkoqi fipdaxohwl wesa KuuzYuvup otm VeseXuno. Socza Tuudsi toxaqenh uj, jou dif gu paja frem humqery vebm ri vaifyuuzem imc ihfciqaj cic u yatq ceth maye mi yawu.
Your app
This chapter has been full of theory and concepts. You’re probably wondering when you are actually going to start writing some code.
Cath, bru kacj ex jhi citcuxogy jwalcivd ose duaxr mi ju zeheyikj tupexy as tak vu itjgf hpi wsamaeajnh mockailec poqwukwv mu vuisr i buc meod ark dagbav DboojJiom. Tsat uwr nisl opmuh fooq ewarh ma wasd bseaj Amtteob vzamkubmu kigl u guq ob zuutwiuhf lwuvet uh u Noep zurahoye:
Ib qoo ruz vio, jkofo ak u tip se raawd. Hnoz fupqoal kedd kiifo noi cytuasn uvezn, yusvqo hxes luofin sa koeyd o lipes cuxgoex eh sgu otv.
Key points
Room is an ORM developed by Google as a part of Android Architecture Components to simplify the interaction with your SQLite database and reduce boilerplate code.
Entities in Room correspond to tables in your database.
DAO stands for Data Access Object.
The Repository class handles the interaction with your Room database and other backend endpoints.
The ViewModel communicates the data coming from your repository to your views and has the advantage of surviving configuration changes.
LiveData is a data holder class that can hold information and be observed for changes.
ORMs provide an additional layer of abstraction that allows you to interact with your relational database with an Object-Oriented Language syntax.
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.