Room är ett bibliotek för att arbeta med SQLite i Android, som ingår i Jetpack. Det tillhandahåller ett abstraktionslager ovanpå rå SQLite och automatiserar skapandet av tabeller, exekvering av frågor och konvertering av data till Kotlin- och Java-objekt. Enligt Android Developers kompilerar Room SQL-frågor under byggfasen och kontrollerar korrektheten av syntax och relationer mellan Entity och tabeller.
Huvudpunkter
Room är ett persistensbibliotek från Android Jetpack som tillhandahåller objektrelationell mappning för SQLite. Room löser tre huvudproblem med rå SQLite: att skriva stora mängder boilerplate-kod för att skapa tabeller, avsaknad av SQL-frågekontroll vid kompilering och manuell konvertering av Cursor till objekt.
Biblioteket använder en annotationskompilator (kapt eller KSP) som genererar implementationen av abstrakta klasser RoomDatabase och DAO under byggfasen. Detta garanterar att syntaxfel i SQL och typskillnader upptäcks innan appen startas, inte vid körning efter publicering i Google Play.
Enligt Google I/O 2023 används Room i 68% av Android-appar som arbetar med lokal data. Det är standarden för datalagring på enheten, rekommenderad av Google för alla nya projekt — istället för föråldrade SQLiteOpenHelper och ContentProvider.
Implementera Room i projekt där lokal cachning av serverdata, offline-läge eller lagring av strukturerad användardata med möjlighet till komplexa SQL-frågor krävs.
Room är en del av Android Jetpack och rekommenderas officiellt av Google för alla nya projekt som arbetar med lokal data. Till skillnad från Realm eller ObjectBox använder Room inbyggt SQLite, vilket garanterar kompatibilitet med alla tredjepartsverktyg för databasarbete — från DB Browser till DataGrip. Utvecklaren kan öppna appens .db-fil och utföra SQL-frågor direkt, vilket förenklar felsökning och dataanalys under utvecklingsprocessen.
Entity är en dataklass annoterad med @Entity, som Room omvandlar till en databastabell. Varje fält i klassen blir en kolumn i tabellen och varje instans blir en rad. Room använder reflektion för att komma åt fält, därför krävs @PrimaryKey-annoteringen för en obligatorisk identifierare.
@Entity-annoteringen informerar Room om att klassen är en tabell. Parametern tableName anger tabellnamnet om det skiljer sig från klassnamnet. @PrimaryKey definierar primärnyckeln med möjlighet till automatisk generering via autoGenerate = true.
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
@ColumnInfo(name = "full_name")
val name: String,
@Ignore
val tempData: String?
)
@ColumnInfo anger kolumnnamnet i tabellen om det skiljer sig från Kotlin-fältnamnet. @Ignore utesluter fältet från tabellen — det sparas inte i databasen. @ForeignKey beskriver främmande nycklar för relationer mellan tabeller med kaskadoperationer vid borttagning eller uppdatering.
Room stöder nästlade objekt via @Embedded-annoteringen. Fälten i den nästlade klassen vecklas ut till kolumner i föräldratabellen med ett prefix för att undvika namnkonflikter. Till exempel, en Address-klass med fälten city och street, inbäddad i User, skapar kolumnerna address_city och address_street i users-tabellen, vilket eliminerar behovet av att skapa separata tabeller för enkla värdobjekt.
Room stöder endast primitiva typer och deras omslag. För lagring av listor, Date eller anpassade typer används @TypeConverter — statiska konverteringsmetoder mellan en anpassad typ och en SQLite-primitiv, till exempel mellan List och en JSON-sträng.
DAO (Data Access Object) är ett gränssnitt eller en abstrakt klass annoterad med @Dao, som innehåller metoder för dataåtkomst. Varje metod är annoterad med en SQL-operation: @Insert, @Update, @Delete eller @Query med en explicit SQL-fråga.
@Query-annoteringen tar emot en SQL-sträng som kontrolleras av Room vid kompilering för korrekt syntax och överensstämmelse mellan kolumnnamn och Entity-fält. Room stöder parametriserade frågor via syntaxen :paramName.
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: Int): User?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Query("SELECT * FROM users ORDER BY name ASC")
fun getAllUsers(): Flow<List<User>>
}
@Insert stöder OnConflictStrategy-strategier för att hantera konflikter vid insättning av dubblettposter. Flow som returtyp säkerställer reaktiv UI-uppdatering vid varje dataändring i tabellen — prenumerationen startas om automatiskt vid varje INSERT, UPDATE eller DELETE.
@Transaction-annoteringen garanterar atomisk exekvering av flera operationer i ett enda transaktionsblock. Room låser databasen under exekvering och förhindrar race conditions vid samtidig åtkomst från flera trådar.
RoomDatabase är en abstrakt klass som förenar Entity och DAO i en enda åtkomstpunkt till databasen. Den skapas via Room.databaseBuilder med angivande av schemaversion och lista över Entity-klasser. Databasinstansen rekommenderas att skapas som singleton via lazy-delegat för att undvika flera anslutningar.
Migrering i Room är en Migration-klass som beskriver ett SQL-skript för övergång från en gammal schemaversion till en ny. Om ingen migrering tillhandahålls vid schemaändring kastar Room IllegalStateException. Detta skyddar mot oavsiktlig förlust av användardata vid uppdatering av appen.
val migration_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0")
}
}
val db = Room.databaseBuilder(
getApplication(),
AppDatabase::class.java,
"app_database"
).addMigrations(migration_1_2)
.build()
För utveckling kan fallbackToDestructiveMigration användas, som tar bort den gamla databasen och skapar en ny vid versionsskillnad. Detta läge är endast avsett för felsökning — i produktionsversioner måste migreringar skrivas.
För testning av databasen tillhandahåller Room en speciell klass Room.inMemoryTestBuilder, som skapar en databas i RAM-minne utan lagring på disk. Efter varje test förstörs databasen automatiskt, vilket garanterar fullständig isolering av testscenarier. I kombination med biblioteket android-arch-core-testing kan utvecklaren hantera databasens livscykel och kontrollera migreringarnas korrekthet utan att behöva rensa tillståndet manuellt.
Prestandan för Room beror direkt på strukturen av frågor och index. För analys av långsamma frågor tillhandahåller Room flaggan enableQueryCallback, som loggar alla SQL-frågor med exekveringstid. Utvecklaren kan använda denna logg för att hitta frågor som tar längre tid än 100 millisekunder och optimera dem genom att lägga till sammansatta index via @Index-annoteringen i @Entity eller skriva om underfrågor till direkta JOIN-kopplingar med @Relation.
Room stöder även databaskryptering via SQLCipher. Anslutning av biblioteket net.zetetic:android-database-sqlcipher och användning av SupportFactory istället för standard säkerställer transparent kryptering av all data på disk utan att ändra DAO-frågor och Entity-struktur. Detta är nödvändigt för appar som arbetar med personuppgifter och uppfyller kraven i GDPR och den ryska lagen 152-FZ om skydd av personuppgifter. Krypteringslösenordet kan lagras i Android Keystore för skydd mot extraktion via verktyg på rotade enheter.
Room stöder inbyggt Kotlin Coroutines från och med version 2.1. DAO-metoder kan vara suspend-funktioner som utför frågor i bakgrunden utan att blockera huvudtråden. Room hanterar automatiskt dispatcher och använder Dispatchers.IO för läs- och skrivfrågor.
För reaktiva frågor returnerar Room Flow — en kall dataström som avger ett nytt värde vid varje ändring av den berörda tabellen. ViewModel prenumererar på Flow via stateIn eller collect, vilket säkerställer automatisk UI-uppdatering utan manuell notifiering av adaptern.
Room stöder även Paging 3 via en speciell PagingSource-implementation som laddar data sidvis från SQLite. Detta är effektivt för stora listor med tusentals poster: Paging 3 laddar endast de rader som är synliga på skärmen och uppdaterar dem automatiskt vid ändringar i databasen.
Använd Paging 3 med Room vid visning av nyhetsflöde, operationslogg eller produktlista med offline-åtkomst och oändlig scrollning.
Vanliga frågor
Room automatiserar skapandet av tabeller, konvertering av Cursor till objekt och SQL-kontroll vid kompilering. SQLiteOpenHelper kräver manuell skrivning av schema, hantering av Cursor och har ingen frågekontroll innan appen startas, vilket ökar risken för fel.
Ja, vid ändring av Entity (lägga till/ta bort fält, ändra typ) krävs en migrering. Utan den kastar Room IllegalStateException vid start. För utveckling kan fallbackToDestructiveMigration aktiveras, men i releasen är korrekta migreringsskript obligatoriska.
Room stöder @ForeignKey för kaskadoperationer och @Relation för nästlade objekt. För komplexa JOIN-frågor används @Transaction-annoteringen med @Query som returnerar POJO med nästlade entiteter via @Embedded och @Relation.
Ja, Room är fullt kompatibelt med Java. Istället för suspend-funktioner används LiveData eller RxJava Observable, istället för Flow — LiveData. Room med Java stöder alla samma annoteringar men kräver mer boilerplate-kod för asynkrona operationer.
Room stöder kryptering via SQLCipher från Zetetic. Använd SupportFactory från biblioteket net.zetetic:android-database-sqlcipher istället för Room.databaseBuilder och skicka krypteringslösenordet. All data på disken kommer att krypteras transparent för DAO-frågor.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också