Android používa SQLite databázu. Jedná sa o ľahučkú single-user databázu extrémne vhodnú práve pre mobilné aplikácie. Po niekoľkých iteráciách obslužných nástrojov sa teraz pre jej obsluhu používa knižnica Room. Žiadne iné alternatívy sa v podstate nepoužívajú.
V tejto téme sa pozrieme na konfiguráciu databázy pomocou Room a následne niektoré základné CRUD operácie.
Ako referenciu používam oficiálny návod pre prácu s Room Databázou.
Potrebovať budeme Kotlin Symbol Processing plugin a samotné Room závislosti:
plugins {
id("com.google.devtools.ksp") version "2.3.10"
}
dependencies {
implementation("androidx.room3:room3-runtime:3.0.2")
ksp("androidx.room3:room3-compiler:3.0.2")
}

Architektúra Room databázy je založená na 3 komponentoch:
INSERT, alebo SELECTTabuľka v SQL databáze je definovaná niekoľkmi stĺpcami. Tieto stĺpce majú napríklad tieto vlastnosti:
Všetky tieto veci vieme vyjadriť pomocou jednoduchej data triedy a vhodne aplikovanými anotáciami. Pozrime si príklad:
@Entity
data class User(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "first_name") val firstName: String,
@ColumnInfo(name = "last_name") val lastName: String
)
Tu vidíme zopár anotácií:
@Entity - označuje, že táto trieda reprezentuje tabuľku v databáze@PrimaryKey - označuje, že uid je primárny kľúč@ColumnInfo - označuje, že firstName / lastName sú klasické stĺpce tabuľkyAk si vytvorím inštanciu tejto triedy, táto bude reprezentovať jeden riadok v tabuľke User. A voila, máme abstrakciu
pre tabuľku, stĺpec aj riadok databázovej tabuľky.
Samozrejme si viem predstaviť rovno písať nejaké DB query, ktoré by s entitou User priamo interagovali… Vo svete
Room, to ale takto nefunguje (nad dôvodmi môžeš rozmýšľať po dlhých večeroch). Namiesto toho pracujeme s konceptom
nazývaným Data Access Object (DAO). DAO je trieda, ktorá definuje operácie nad tabuľkou. Napríklad:
@Dao
interface UserDao {
@Query("SELECT * FROM user")
suspend fun getAll(): List<User>
@Query("SELECT * FROM user")
fun getAll(): Flow<List<User>>
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
suspend fun loadAllByIds(userIds: IntArray): List<User>
@Insert
suspend fun insertAll(vararg users: User)
@Delete
suspend fun delete(user: User)
}
Zopár poznámok:
suspendsuspend, ale vráti Flow@Query, @Insert, @Delete, @Update a @Upsert (= Insert or Update)Ak sa nám podarí dostať k UserDao, môžeme začať prácovať s databázou.
Poslednou abstrakciou je samotná definícia databázy. Teda nejaké označenie, aké má databáza obsahovať tabuľky a aké DAO.
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Táto trieda reprezentuje našu databázu s jednou tabuľkou User a jedným DAO UserDao. Stále ale nie je konkrétnym
objektom. Nevieme, kde sa táto databáza reálne na disku nachádza. V praxi definujeme iba názov súboru, s ktorým má naša
databáza pracovať. Jej inštanciu tak vytvoríme nasledovným spôsobom:
val database =
Room.databaseBuilder<AppDatabase>(applicationContext, "database-name")
.setDriver(AndroidSQLiteDriver())
.build()
Teda v súbore database-name sa bude nachádzať databáza AppDatabase, ktorá má jedinú tabuľku User a jediný DAO
UserDao. UserDao obsahuje 5 vyhradených funkcií pre prácu s databázou. Máme tak istotu, že programátor používa
iba vymedzený set funkcií a tak minimalizujeme riziko vzniku chýb.
Premenná database je typu AppDatabase. Má teda k dispozícii funkciu userDao(), ktorá vráti inštanciu UserDao.
Takže ak spravím nasledovné:
val userDao = db.userDao()
zrazu mám k dispozícii všetky funkcie definované v UserDao.
val users: List<User> = userDao.getAll()
userDao.insertAll(User(1, "John", "Doe"))
userDao.delete(User(1, "John", "Doe"))
… magic …
Room nám poskytuje aj ďalšie funkcionality: