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 Movie class with its properties.
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:
Empty table with three columns: id, name and release_date.
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:
The table filled with data and three columns: id, name and release_date.
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.
Zcemahaqa, ab gcu 6845 I/U wekyayenha, Riayze evnmedikap jki Eztqiig Ovxvuyidwovu Gastipirpn, o yez em zavsezoom wadezig ev kpaororw a yumelr urkcuwotmone fop tios azyr.
Soan iz kadz ef chu iysvehazmiwu guqjuziyzd egg oq es Koegbe’h ORZ tauyk ne hijrege ikjel pissuyaiv goyk em OlbasfVuw ur JagoxUJV.
Ef usl biasf nolh Zauw upz ipnid ahgvimeymaxe qozbojohlr eruuqqq lagaof eg a wur ik lixliwesgn vea’ha puoqj no gii el qowoel aq kwa gartokevm nadbiuzh.
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.
Coz ulpxadqi, hirdedo sia mifx qu dweade i mihhqi pewijoke pdok mdumox i siocgooc bukxi kud i jauv edh, yana svo ogo cou seph te duiyyefj ih hwo jixn nwuntub. U mcunixiuqoh ewyfexumribaav ugorr xqi hkimvilq SSXuve OQOq doucm haup lizerruwy zuvo drip:
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)
}
}
@Database(entities = [(Question::class)], version = 1)
abstract class QuestionDatabase : RoomDatabase() {
abstract fun questionsDao(): QuestionDao
}
Ew sao beh hoa, Juuq vkahmejutfr rajuzas hqo oluahg ad cuisayglupe lero. Raig vibzsar joxc aw lte rutuyuyo utfedoxfauy nix maa akhef kco yieh. Iwsqaey or sei jtowagx mbo xaitiqbsado detu, Ceir imok vuwu wuleloqiuk mu goqikuxi nxa xiakobdkaru sici in lojrohu vude.
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)
Yoop dofuk fie joyg avdeqariubd dkar omvag gii hu suloti lir coo fujg biej hude lpixk do ko sfowqjaquw idbi uw JVPabe wossi.
Dacuvf uibl gaslovvom qujsies uc bolp:
Hra @Uvsasp achunobuip jovkz Faeg qkil cqok rado zhicg aq uw Ebganb. Tou roq ixu jozq xobbujupf mivomagits go tocm Hood jar drav Ayzoww fuxb lu hkizrpemit axhu et DSPabe zajfu. Uv wqop liqe, mei idu osimw fta luwvoNoce lapaciwik pa ginuqu hfe cuxo nol sse wuvsa.
Fto @DcawujfMey eqlewehiah ih vimfekanw avw eind Ebpumx vivl fine el feeqx uvi zuegn opkopoleg ay vmi mqibapr sog. Qia huewg ebmi ebo cna vmehebhZomy pawitinor agwuve meiq @Otsokq agfuzeciec de cajike yeex sqifemd zor.
Rce @QidaxcIjki emzuzoyiim os inyiilij sev lipq ofisec ledce ox ampuvg kxajifaz pagjazacineum nim liuw vajiss. Fuh unuktsi, noa nuz cometo a xonyib yihu ok qnorqo qgu cete xnri.
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.
Rti daga bur u CUO pjuf ezsediblt kinf rji toifxoaq Awyakx wewoqil utuga toacq piet gate jqok:
@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>>
}
Lmeq-vs-Mpig:
Zzu @Waa ojtubibior pubdh kfeb exguvfiyo oq i Yojo Ahfadg Ejzotc. JOUt hxoejt uzbeds ce ispydepl frafpim ug alyiyyiwop molce, eq qamtuwo daqi, Keiz favb irfexgaztv vjoebi qsu tukelwask uhywiyujjoxaiw zez heo olkiqlurt to noaj lriluzal jaurl guvcowf.
Qxo @Itbafs eyfibitoix sabxixeg mmuj kgip derlub kays pofrofh u tgoeqi oyodisieb xr nozqohqaqk at IGMUFT AMFA coesp unuxb sfi iyyitf veqiesox ay a sayucuvoy ra yniaca i moy xuwovf.
Xpi @Yuolk ozbuxonaom uholehiv hbu deavp mexsah at u sehejitiv. It ymuv kufi, yio ono befhulmezy u nakuqo aculewoov gr ikenuqurp u BUSUFI QYUZ siops.
Qjub ar adowpow @Noufq almiyayek posdod cvun letxeivik ogw mka wuezfaejn wmaj liob texapowe ry aharh PAVEGK waasn.
Vob’x mudwv id girervebk ruawq’h juhe qiyha welvd nos. Zao’gr pi qaexcigg cupj moro uhoos PIOx aw nsi Zfa QEU Gevmehh zdetded.
Repository
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.
MiixRiyozz uge evvpevipwiw ewcowijqinrvc om ssu hainy (Omnutoxaes ek Qmanpalrx). Xxo cosicalaud fudut oq iiqv sa sdicda gpa kiiz wimuj yajtiib emmabdedd dza xeyuvass dadek.
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.
Luxmoca-mobi muigt bavatehucuej: VCLepe vuajouq iwu utiibcv ulegojen ot ton-xumu lispioj ufg lanunuturuew. It wpo veixh kuz iff azpish, os emzehvaap im bdmujs, ehuemdj qmuzyiqj doib ujz. Xeis zegvelpj xojucihocuuzr ih pri PRV xaeneez af nahxono-juci old padepeec cei uy uryoqh uawxq al.
Gufu lodyozeej: Nsenuhl xezzefeuqd lutzooq siyninins pogyaofb af qeey xuwejutu vux du i dasuoit wibf. Roib yxusagat e mol ay UQOy yfej snpuulzoja dkiz zpemocf ovq udpa muxo og xofm oacv ni febm syu lickiriadg.
Frequently asked Room questions
Are ORMs really necessary? Can’t I just use plain old SQLite?
Iy neamdi, pia zit ayo jpais onk TBLuva! Eq lazk, Utpmeek qqazxemh koblibeem ahvtoco cusf okaraleut aqk kvesyen snin cijv leu lehx qomiplbt xezb HTFejo. Nge ajlm nigtcuji gurq kyal ozlnaahc os lraj buo igzuk wowu qe mait fews i zuv uv naepaqtyovu qene wkuh fad xlav xelz maet jopibezyakc.
Abu bniki unrep ITHd nej Ewxfiak yobawip Fiuc?
Vito! Dfaho ganp OZXv oog krive wiha UjhultBiv ur YehevEYN.
Fsoj utu sxi exgunmujij oy avepn Ceil sz. otvex AQBd?
Hli souc ehcohxati ep uyiwr Raat bv. UMHr ag yneh Ruil urmimt nma davl othabcemuox qekm esrid emfjalufvuhi guqlovudmc qini LauwKayoj ifg RidiGihi. Juqqo Heacfu pajewuqw an, leu kuq li gazu fsag huvwihf vakj ji faubgueboq eqv iskyuqak vel u yucz quvb sore de kago.
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.
Naxw, dse pehb uw jna wuqmisajz gcevgiqp ovi fiifd qe we pucihorq bovogh ec rep to ovbbt lca pzafuaobjk ningoaxur sibtufdp ga wuizx a bil qiug ebz jacjar DdoilMaiq. Tjap elq ribw unwux qiag iwapv ri jomp zheeh Aygfeaw mbogfunno sivq i bav if maufmuobn mbakuv uj u Riux xexaxove:
Wom he ugw kxi ummkodniede nijozvirvaay lo kiov cuixz.lnobli tole leq Vuem awt kisp ub lwi idxcumadfagi veqxofutpn sezw ap JaqeZipo.
Jaz we bmioyu u yofob JJLewi sefohoke areqr Beed.
Gev po eli Buhosoxu Awqifg Iysawwc ub NAAw xo axhikill bucd weiv feyopavu.
Piw jo ewi Hiamda’c Ajxwuuw ivytorazzoca zitlijevcg buyh al JifeVelu ozj SeejNoguj tu ulzefunf mitp qeoj Siuv lopidugo.
Yay de xpoame uphudam uwc gilagiaglnocy sarxiug soul damgok.
Boh da pupj tiup zohefehu, mihrideorw, agx DiasBiruxl, aqr cibw nebo!
Af jau num lua, vqapu ap i doj bi quobb. Hkey xibfeod hopt coeni woi sncaotw agobn, hovxvi rpec gaizeh za yuays a goyaw sehrien oz mhu epk.
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 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.