A Room egy ORM könyvtár az Android Jetpack csomagból, amely absztrakciós réteget biztosít az SQLite felett a helyi adatbázisokkal való munkához Androidon. A hivatalos dokumentáció szerint Android Developers, 2025, a Room automatikusan generál DAO implementációkat annotációk alapján fordítási időben, ami körülbelül 70%-kal csökkenti a boilerplate kód mennyiségét a SQLiteOpenHelper közvetlen használatához képest. A könyvtár SQL lekérdezéseket ellenőriz a fordítási fázisban, lehetővé téve a szintaktikai hibák felderítését még az alkalmazás eszközön történő elindítása előtt.
Főbb pontok
A Room egy ORM könyvtár az Android Jetpack csomagból, amelyet a Google hozott létre a helyi SQLite adatbázisokkal való munka egyszerűsítésére az Android platformon. Annotációkat biztosít az adatséma leírásához és automatikusan generálja a DAO interfészek implementációját a fordítási fázisban. Ellentétben a SQLiteOpenHelper közvetlen használatával, a Room felszabadítja a fejlesztőt a jelentős mennyiségű boilerplate kód írása alól az adatbázis kapcsolat létrehozásához, megnyitásához és kezeléséhez.
A könyvtárat a Google I/O 2017-en mutatták be az Android architektúra komponensek részeként. Azóta a Room a helyi adattárolás de facto szabványává vált, népszerűségben megelőzve olyan megoldásokat, mint a GreenDAO és a Realm Androidhoz. A Google adatai szerint a könyvtárat a Google Play-ben közzétett, helyi adatokkal dolgozó alkalmazások több mint 60%-a használja.
Kulcsfontosságú jellemző — az SQL lekérdezések ellenőrzése a fordítási fázisban annotációs processzor segítségével. Ha a fejlesztő hibát vét egy SQL parancsban, például nem létező oszlopnevet ad meg, a fordítás hibával végződik az alkalmazás telepítése előtt. Ez gyökeresen eltér a SQLiteOpenHelper megközelítéstől, ahol az ilyen hibák csak futásidőben, gyakran éles környezetben derülnek ki.
Az SQLite csak öt adattípust támogat: TEXT, INTEGER, REAL, BLOB és NULL. Azonban Java-ban és Kotlin-ban összetett típusok használatosak: Date, List, Enum és egyedi objektumok. Ezek tárolására a Room a TypeConverters mechanizmust biztosítja — statikus metódusokat, amelyek az összetett típust a SQLite számára érthető primitív típussá alakítják. Például a Date objektum Long-á (timestamp), a List<String> pedig JSON stringgé alakul Gson vagy Moshi segítségével.
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
val db = Room
.databaseBuilder(context, AppDatabase::class.java, "app-db")
.build()
A konverter deklarálásához elegendő a @TypeConverter annotációt hozzáadni egy statikus metódushoz és megadni a konverter osztályt a @TypeConverters annotációban adatbázis szinten. A Room automatikusan alkalmazza a konvertet a megfelelő típus olvasásakor és írásakor minden SQL lekérdezésben anélkül, hogy manuálisan kellene hívni a konverziós metódusokat.
A Room három fő komponensből áll: Entity, DAO és Database. Mindegyik szigorúan meghatározott szerepet tölt be és a megfelelő annotációval van ellátva. Együtt egy teljes adathozzáférési réteget alkotnak, amely elkülöníti az alkalmazás üzleti logikáját a SQLite implementációs részleteitől.
Az Entity egy adatosztály, amely egy tábla szerkezetét írja le az adatbázisban. Az osztály minden mezője megfelel a tábla egy oszlopának, és minden sor az adatbázisban az osztály egy példányának. A @Entity annotáció jelzi a Room-nak, hogy az osztály egy tábla. A @PrimaryKey annotációval ellátott mező határozza meg az elsődleges kulcsot, amely lehet auto-increment vagy összetett. A táblák közötti kapcsolathoz a @ForeignKey használatos, amely biztosítja az adatok integritását adatbázis szinten.
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
@ColumnInfo(name = "full_name")
val name: String,
val age: Int,
val email: String
)
A DAO (Data Access Object) egy interfész vagy absztrakt osztály, amely deklarálja az adatokkal való munkához szükséges műveleteket: beszúrás, olvasás, frissítés és törlés. Minden művelet @Insert, @Query, @Update vagy @Delete annotációval van ellátva. A Room automatikusan generálja ennek az interfésznek az implementációját a fordítási fázisban. Különös értékkel bír a @Query annotáció, amely SQL lekérdezést fogad stringként és ellenőrzi annak helyességét a build fázisban.
@Dao
interface UserDao {
@Insert
suspend fun insert(user: User): Long
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: Int): User?
@Query("SELECT * FROM users")
fun getAllUsers(): Flow<List<User>>
@Delete
suspend fun delete(user: User)
}
A Database egy absztrakt osztály, amely a RoomDatabase-ből származik, és belépési pontként szolgál az adatbázishoz. Tartalmazza az összes Entity listáját és absztrakt metódusokat biztosít a DAO eléréséhez. Az osztály @Database annotációval van ellátva, ahol a séma verziója és az entitások listája szerepel. Az adatbázis példányának létrehozása a Room.databaseBuilder segítségével történik az alkalmazás kontextusának, a fájl nevének és a Database osztálynak a megadásával.
A Room nem helyettesíti az SQLite-ot, hanem absztrakciós rétegként működik felette. A belső architektúra magában foglal egy annotációs processzort, kódgenerátort és kapcsolati poolt. A fordítási fázisban az annotációs processzor elemzi az Entity, DAO és Database osztályokat, majd létrehozza az implementációs osztályokat _Impl utótaggal. Az összes generált osztály a build csomagba kerül és nem látható közvetlenül a fejlesztő számára.
A kód generálása a fordítási fázisban — a Room központi mechanizmusa. Minden DAO interfészhez egy osztály generálódik az összes annotált metódus teljes implementációjával. A @Query annotációból származó SQL lekérdezések helyességét ellenőrzik: a processzor összeveti az oszlopneveket az Entity mezőkkel és ellenőrzi az SQL szintaxist. Hiba észlelése esetén a fordítás megszakad egy érthető üzenettel. Ez lehetetlen a nyers SQLiteOpenHelper használatakor, ahol a hibák csak futásidőben jelennek meg.
A generálási folyamat három szakaszból áll. Első — séma érvényesítés: a processzor ellenőrzi, hogy a @Database-ben felsorolt összes osztály érvényes Entity-e. Második — a DAO törzsének generálása: minden metódushoz egy implementáció készül a belső RoomSQLiteQuery objektum segítségével, amely előkészített lekérdezéseket hajt végre. Harmadik — a Database_Impl osztály generálása, amely megvalósítja az adatbázis létrehozását és megnyitását, valamint az összes DAO objektum inicializálását.
class UserDao_Impl(private val __db: RoomDatabase) : UserDao {
private val __insertionAdapter = __db
.createInsertionAdapter(User::class, 0)
override suspend fun insert(user: User): Long {
__db.assertNotSuspendingTransaction()
return __db.runInTransaction {
__insertionAdapter.insertAndReturnId(user)
}
}
}
A Room nem hoz létre külön szálpoolt az adatbázis műveletekhez. Alapértelmezés szerint a lekérdezések a hívó szálban futnak egy korlátozással: az olvasás és írás blokkolja a szálat. Aszinkron munkához a Room integrálódik a Kotlin korutinokkal suspend függvényeken keresztül, a LiveData-val visszatérési értékeken keresztül és a Flow-val reaktív burkolókon keresztül. Ez rugalmasságot biztosít a fejlesztőnek az architektúra megoldás kiválasztásában egy adott feladathoz.
Nézzünk egy gyakorlati példát egy jegyzetek tárolására szolgáló alkalmazás létrehozására a Room segítségével. Az alkalmazás egy Note táblát tartalmaz id, title, content és timestamp mezőkkel. A felhasználó jegyzeteket adhat hozzá, tekinthet meg és törölhet. A bemutatóhoz korutinok használatosak az aszinkron műveletekhez.
A Room Android projekthez csatlakoztatásához függőségeket kell hozzáadni az alkalmazás modul build.gradle fájljához. A Room három komponenst igényel: runtime könyvtárat, kapt annotációs processzort és opcionális korutin támogatást. A könyvtár verziója a room_version változóban van megadva a könnyű frissítés érdekében. A Room 2.4.0-tól kezdve a KSP támogatott a kapt alternatívájaként nagyobb build sebességgel.
dependencies {
def room_version = "2.6.1"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
// Opcionális: tesztelés
testImplementation "androidx.room:room-testing:$room_version"
}
A függőségek konfigurálása után három fájl jön létre: a Note Entity, a NoteDao interfész és az AppDatabase osztály. A Note Entity @PrimaryKey és @ColumnInfo annotációkkal ellátott mezőket tartalmaz. A DAO metódusokat biztosít a beszúráshoz, lista lekéréséhez és törléshez. A Database a @Database annotáción keresztül kapcsolja össze az Entity-t és a DAO-t.
@Entity(tableName = "notes")
data class Note(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val title: String,
val content: String,
@ColumnInfo(name = "created_at")
val timestamp: Long = System.currentTimeMillis()
)
@Dao
interface NoteDao {
@Insert
suspend fun insert(note: Note)
@Query("SELECT * FROM notes ORDER BY created_at DESC")
fun getAllNotes(): Flow<List<Note>>
@Delete
suspend fun delete(note: Note)
}
Az AppDatabase fájl egy absztrakt osztályként van deklarálva, amely a RoomDatabase-ből származik. A @Database annotációban szerepel a jelenlegi verzió összes Entity-je és a séma verziószáma. A példány eléréséhez singleton minta használatos a Room.databaseBuilder build metódusán keresztül az alkalmazás kontextusával. Az adatbázis példány gyorsítótárazása megakadályozza a többszörös létrehozást, amely memóriaszivárgáshoz vezethet.
Migrációk a Room-ban egy mechanizmus az adatbázis séma megváltoztatására az alkalmazás frissítésekor a meglévő adatok elvesztése nélkül. Amikor a felhasználó telepíti a módosított Entity-kkel ellátott új verziót, a Room észleli a verzióeltérést és végrehajtja a megadott migrációs lépéseket. Migráció nélkül az adatbázis törlődik és újra létrejön, ami az összes elmentett felhasználói adat elvesztéséhez vezet.
A migrációt a Migration osztály írja le, amely az adatbázis kezdeti és végső verzióját fogadja. A migrate metóduson belül egy ALTER TABLE vagy CREATE TABLE SQL lekérdezés hajtódik végre a séma módosításához. A Room nem képes automatikusan érzékelni a séma változásokat — a fejlesztőnek manuálisan kell megírnia a migrációt minden Entity változáshoz. A Room 2.4.0 verziótól kezdve elérhető a kísérleti autoMigrations funkció a migrációk automatikus generálásához.
Az autoMigrations funkció lehetővé teszi a Room számára, hogy automatikusan generáljon migrációkat az Entity verziók közötti különbségek alapján. Használatához elegendő a @AutoMigration annotációt hozzáadni a @Database-hez és megadni a séma exportálását JSON-ba. A Room összehasonlítja a szomszédos verziók sémáit és létrehozza a szükséges ALTER lekérdezéseket. Azonban az autoMigrations csak visszafelé kompatibilis változtatásokat támogat: oszlopok hozzáadása, indexek létrehozása és típusváltások kompatibilis konverziókkal.
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"ALTER TABLE users ADD COLUMN phone TEXT"
)
}
}
val db = Room
.databaseBuilder(context, AppDatabase::class.java, "app-db")
.addMigrations(MIGRATION_1_2)
.build()
Összetett változtatások hozzáadásakor, mint például oszlopok átnevezése vagy táblák egyesítése, kézi migráció szükséges ideiglenes táblák használatával. Tipikus forgatókönyv: hozzon létre egy ideiglenes táblát a régi sémával, másolja az adatokat a régi táblából az újba konverziókkal, törölje a régi táblát és nevezze át az ideiglenest. A Room garantálja, hogy minden migráció egy tranzakcióban hajtódik végre, és hiba esetén a változtatások teljesen visszavonásra kerülnek.
Gyakran Ismételt Kérdések
A Room ORM absztrakciót biztosít annotációkkal és SQL ellenőrzéssel a fordítási fázisban, míg a SQLiteOpenHelper az összes lekérdezés kézi írását és a kapcsolatkezelést igényli. A Room automatikusan generál kódot a CRUD műveletekhez és integrálódik az Android architektúra komponensekkel, beleértve a LiveData-t és a Flow-t.
A Room támogatja az összes Java primitív típust: Int, Long, Boolean, Float, Double, valamint a String, ByteArray és Date típusokat. Az összetett típusokhoz, mint a List vagy Enum, TypeConverters használatos — statikus konverziós metódusok, amelyek a nem szabványos típusokat a SQLite által támogatott formátumokká alakítják.
Igen, a Room támogatja a szinkron hívásokat korutinok nélkül, de ezek blokkolják a szálat, amelyben futnak. Aszinkron munkához használható LiveData vagy RxJava a korutinok helyett. A Google a korutinok használatát ajánlja az adatok aszinkron elérésének fő módjaként új projektekben.
Ha a Room verzióeltérést észlel az adatbázisban és nem talál megfelelő migrációt, alapértelmezés szerint IllegalStateException keletkezik a hiba leírásával. A fejlesztő felülbírálhatja ezt a viselkedést a fallbackToDestructiveMigration metódussal, amely törli a meglévő adatbázist és újat hoz létre az összes adat elvesztésével.
A Room támogatja a kapcsolatokat beágyazott objektumokon keresztül a @Embedded annotációval és kapcsolati osztályokon keresztül a @Relation annotációval. Összetett, táblák összekapcsolásával járó lekérdezésekhez egyedi POJO osztályok használatosak, amelyek mezői a @Query eredményeiből töltődnek fel az SQL JOIN operátor segítségével.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is