Room ay isang library para sa pagtatrabaho sa SQLite sa Android na bahagi ng Jetpack. Nagbibigay ito ng abstraction layer sa ibabaw ng raw SQLite, na nag-automate sa paggawa ng mga table, pag-execute ng mga query, at pag-convert ng data sa mga object ng Kotlin at Java. Ayon sa Android Developers, kino-compile ng Room ang mga SQL query sa yugto ng build, sinusuri ang kawastuhan ng syntax at mga ugnayan sa pagitan ng Entity at mga table.
Mga Pangunahing Punto
Room ay isang persistence library mula sa Android Jetpack na nagbibigay ng object-relational mapping para sa SQLite. Nilulutas ng Room ang tatlong pangunahing problema ng raw SQLite: pagsulat ng maraming boilerplate code para sa paggawa ng mga table, kawalan ng pagsusuri ng SQL query sa yugto ng compilation, at manu-manong conversion ng Cursor sa mga object.
Gumagamit ang library ng annotation compiler (kapt o KSP) na bumubuo ng implementasyon ng abstract na mga klase ng RoomDatabase at DAO sa yugto ng build. Ginagarantiyahan nito na ang mga syntax error sa SQL at hindi pagkakatugma ng uri ay natutukoy bago patakbuhin ang app, hindi sa runtime pagkatapos ng pag-publish sa Google Play.
Ayon sa Google I/O 2023, ang Room ay ginagamit sa 68% ng mga Android app na nagtatrabaho sa lokal na data. Ito ang pamantayan ng pag-iimbak ng data sa device na inirerekomenda ng Google para sa lahat ng bagong proyekto — sa halip ng lumang SQLiteOpenHelper at ContentProvider.
Ipatupad ang Room sa mga proyekto kung saan kinakailangan ang lokal na caching ng data mula sa server, offline mode, o pag-iimbak ng nakaayos na data ng user na may kakayahang magsagawa ng mga kumplikadong SQL query.
Ang Room ay bahagi ng Android Jetpack at opisyal na inirerekomenda ng Google para sa lahat ng bagong proyekto na nagtatrabaho sa lokal na data. Hindi tulad ng Realm o ObjectBox, gumagamit ang Room ng native na SQLite, na ginagarantiyahan ang compatibility sa anumang third-party na tool para sa pagtatrabaho sa database — mula sa DB Browser hanggang DataGrip. Maaaring buksan ng developer ang .db file ng app at direktang mag-execute ng mga SQL query, na nagpapadali sa debugging at pagsusuri ng data sa proseso ng pag-develop.
Entity ay isang data class na may anotasyong @Entity, na ginagawang table ng database ng Room. Ang bawat field ng klase ay nagiging column ng table, at bawat instance ay nagiging row. Gumagamit ang Room ng reflection para ma-access ang mga field, kaya kinakailangan ang @PrimaryKey na anotasyon para sa mandatoryong identifier.
Ang anotasyong @Entity ay nagsasabi sa Room na ang klase ay isang table. Ang parameter na tableName ay nagtatakda ng pangalan ng table kung ito ay naiiba sa pangalan ng klase. @PrimaryKey ay tumutukoy sa primary key na may posibilidad ng auto-generation sa pamamagitan ng 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 ay nagtatakda ng pangalan ng column sa table kung ito ay naiiba sa pangalan ng Kotlin field. @Ignore ay nagbubukod ng field mula sa table — hindi ito mai-save sa database. @ForeignKey ay naglalarawan ng mga foreign key para sa mga ugnayan sa pagitan ng mga table na may cascade operations sa pagtanggal o pag-update.
Sinusuportahan ng Room ang mga nested object sa pamamagitan ng anotasyong @Embedded. Ang mga field ng nested class ay ibinubuka sa mga column ng parent table na may prefix para maiwasan ang conflict ng pangalan. Halimbawa, ang Address class na may field na city at street, na naka-embed sa User, ay gagawa ng mga column na address_city at address_street sa users table, na nag-aalis ng pangangailangan na gumawa ng mga hiwalay na table para sa simpleng value object.
Sinusuportahan lamang ng Room ang mga primitive na uri at ang kanilang mga wrapper. Para sa pag-iimbak ng mga list, Date, o custom na uri, ginagamit ang @TypeConverter — mga static na metodo ng conversion sa pagitan ng custom na uri at SQLite primitive, halimbawa, sa pagitan ng List at isang JSON string.
DAO (Data Access Object) ay isang interface o abstract na klase na may anotasyong @Dao, na naglalaman ng mga metodo para sa pag-access ng data. Ang bawat metodo ay may anotasyong SQL operation: @Insert, @Update, @Delete o @Query na may tahasang SQL query.
Ang anotasyong @Query ay tumatanggap ng SQL string na sinusuri ng Room sa yugto ng compilation para sa kawastuhan ng syntax at pagtutugma ng mga pangalan ng column sa mga field ng Entity. Sinusuportahan ng Room ang mga parameterized query sa pamamagitan ng syntax na :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 ay sumusuporta sa mga estratehiya ng OnConflictStrategy para sa paghawak ng mga conflict kapag naglalagay ng mga duplicate na record. Ang Flow bilang return type ay nagbibigay ng reaktibong pag-update ng UI sa bawat pagbabago ng data sa table — ang subscription ay awtomatikong nagre-restart sa bawat INSERT, UPDATE o DELETE.
Ang anotasyong @Transaction ay ginagarantiyahan ang atomikong pag-execute ng maraming operasyon sa isang transaction block. Ni-lock ng Room ang database habang nag-e-execute, pinipigilan ang race condition sa concurrent access mula sa maraming thread.
RoomDatabase ay isang abstract na klase na pinag-iisa ang Entity at DAO sa iisang punto ng pag-access sa database. Ito ay nilikha sa pamamagitan ng Room.databaseBuilder na may pagtukoy ng bersyon ng schema at listahan ng mga Entity class. Ang instance ng database ay inirerekomenda na gawin bilang singleton sa pamamagitan ng lazy-delegate upang maiwasan ang maraming koneksyon.
Migrasyon sa Room ay isang Migration class na naglalarawan ng SQL script para sa paglipat mula sa lumang bersyon ng schema patungo sa bago. Kung ang migrasyon ay hindi ibinigay sa pagbabago ng schema, ang Room ay nagtatapon ng IllegalStateException. Pinoprotektahan nito laban sa aksidenteng pagkawala ng data ng user sa pag-update ng app.
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()
Para sa pag-develop ay maaaring gamitin ang fallbackToDestructiveMigration, na nagtatanggal ng lumang database at gumagawa ng bago kapag hindi tugma ang mga bersyon. Ang mode na ito ay para lamang sa debugging — sa production release ay kinakailangang sumulat ng migrasyon.
Para sa pag-test ng database, ang Room ay nagbibigay ng espesyal na klase na Room.inMemoryTestBuilder, na lumilikha ng database sa RAM memory nang hindi nagse-save sa disk. Pagkatapos ng bawat test, ang database ay awtomatikong nasisira, na ginagarantiyahan ang kumpletong isolation ng mga test scenario. Kasama ng library na android-arch-core-testing, ang developer ay maaaring mamahala ng lifecycle ng database at suriin ang kawastuhan ng mga migrasyon nang hindi na kailangang manu-manong mag-clear ng estado.
Ang performance ng Room ay direktang nakadepende sa istraktura ng mga query at index. Para sa pagsusuri ng mabagal na query, ang Room ay nagbibigay ng flag na enableQueryCallback, na nagla-log ng lahat ng SQL query kasama ang oras ng pag-execute. Maaaring gamitin ng developer ang log na ito para mahanap ang mga query na tumatagal ng higit sa 100 millisecond at i-optimize ang mga ito sa pamamagitan ng pagdaragdag ng compound index sa pamamagitan ng @Index na anotasyon sa @Entity o muling pagsulat ng mga subquery sa direktang JOIN connections gamit ang @Relation.
Sinusuportahan din ng Room ang encryption ng database sa pamamagitan ng SQLCipher. Ang pagkonekta ng library na net.zetetic:android-database-sqlcipher at paggamit ng SupportFactory sa halip ng standard ay nagbibigay ng transparent na encryption ng lahat ng data sa disk nang hindi binabago ang mga DAO query at istraktura ng Entity. Ito ay kinakailangan para sa mga app na nagtatrabaho sa personal na data ng mga user at tumutugon sa mga kinakailangan ng GDPR at Russian 152-FZ na batas tungkol sa proteksyon ng personal na data. Ang encryption password ay maaaring itago sa Android Keystore para sa proteksyon laban sa pag-extract sa pamamagitan ng mga tool sa naka-root na device.
Room ay native na sumusuporta sa Kotlin Coroutines simula bersyon 2.1. Ang mga DAO method ay maaaring maging suspend function na nag-e-execute ng mga query sa background nang hindi hinaharangan ang main thread. Awtomatikong pinamamahalaan ng Room ang mga dispatcher, gamit ang Dispatchers.IO para sa read at write query.
Para sa mga reaktibong query, ang Room ay nagbabalik ng Flow — isang malamig na stream ng data na naglalabas ng bagong halaga sa bawat pagbabago ng apektadong table. Ang ViewModel ay nag-subscribe sa Flow sa pamamagitan ng stateIn o collect, na tinitiyak ang awtomatikong pag-update ng UI nang walang manu-manong abiso ng adapter.
Sinusuportahan din ng Room ang Paging 3 sa pamamagitan ng espesyal na implementasyon ng PagingSource na naglo-load ng data nang pahina mula sa SQLite. Ito ay mahusay para sa malalaking listahan na may libu-libong record: Ang Paging 3 ay naglo-load lamang ng mga row na nakikita sa screen at awtomatikong nag-a-update ng mga ito sa mga pagbabago sa database.
Gamitin ang Paging 3 kasama ang Room kapag nagpapakita ng news feed, operation log, o listahan ng produkto na may offline access at walang katapusang pag-scroll.
Mga Madalas Itanong
Room ay nag-a-automate ng paggawa ng table, conversion ng Cursor sa object, at pagsusuri ng SQL sa yugto ng compilation. Ang SQLiteOpenHelper ay nangangailangan ng manu-manong pagsulat ng schema, pagproseso ng Cursor, at walang pagsusuri ng query bago patakbuhin ang app, na nagpapataas ng panganib ng error.
Oo, sa pagbabago ng Entity (pagdaragdag/pag-alis ng field, pagbabago ng uri) kinakailangan ang migrasyon. Kung wala ito, ang Room ay nagtatapon ng IllegalStateException sa startup. Para sa pag-develop ay maaaring i-enable ang fallbackToDestructiveMigration, ngunit sa release ay kinakailangan ang tamang migration script.
Sinusuportahan ng Room ang @ForeignKey para sa cascade operations at @Relation para sa nested object. Para sa kumplikadong JOIN query, ginagamit ang @Transaction na anotasyon na may @Query na nagbabalik ng POJO na may nested entity sa pamamagitan ng @Embedded at @Relation.
Oo, ang Room ay ganap na compatible sa Java. Sa halip ng suspend function, gamitin ang LiveData o RxJava Observable, sa halip ng Flow — LiveData. Ang Room sa Java ay sumusuporta sa lahat ng parehong anotasyon, ngunit nangangailangan ng mas maraming boilerplate code para sa asynchronous na operasyon.
Sinusuportahan ng Room ang encryption sa pamamagitan ng SQLCipher mula sa Zetetic. Sa halip ng Room.databaseBuilder, gamitin ang SupportFactory mula sa library na net.zetetic:android-database-sqlcipher, na nagpapasa ng encryption password. Lahat ng data sa disk ay mai-encrypt nang transparent para sa mga DAO query.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din