手把手教你玩轉(zhuǎn)Room:Android數(shù)據(jù)庫(kù)的保命指南
聽說(shuō)你要搞Android本地?cái)?shù)據(jù)庫(kù)?別慌!Room這貨就是官方給的救命稻草,不用再被原生SQLite虐到脫發(fā)了。今天咱們用簡(jiǎn)單的方式,掰開揉碎了講講這玩意兒怎么玩,保你半小時(shí)上手!
三大金剛(核心組件)
數(shù)據(jù)身份證(Entity)
這玩意兒就是數(shù)據(jù)庫(kù)里的表格模板,用注解就能搞事情。舉個(gè)栗子:
@Entity(tableName = "肥宅快樂表") // 表名隨便起
dataclass 宅男(
@PrimaryKey(autoGenerate = true)
val 編號(hào): Int = 0, // 自動(dòng)生成主鍵
@ColumnInfo(name = "江湖稱號(hào)")// 給字段起花名
val 昵稱: String,
val 年齡: Int,
@ColumnInfo(defaultValue = "false")
val 是否單身: Boolean
)
//??
@Entity(tableName = "Otaku")
dataclass Otaku(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
@ColumnInfo(name = "name")
val name: String,
val age: Int,
@ColumnInfo(defaultValue = "false")
val isSingle: Boolean
)
小貼士:@Index可以給常用字段加速,但別亂加,跟吃蛋白粉一樣適量才好
專屬服務(wù)員(DAO)
定義怎么調(diào)戲數(shù)據(jù)庫(kù),增刪改查都能整:
@Dao
interface 宅男管家 {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspendfun 新增宅男(宅男: 宅男)
@Query("SELECT * FROM 肥宅快樂表 WHERE 是否單身 = 1")
fun 查所有單身狗(): Flow<List<宅男>>
}
//??
@Dao
interface OtakuDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspendfun insert(otaku: Otaku)
@Query("SELECT * FROM Otaku WHERE isSingle = 1")
fun getSingleOtakus(): Flow<List<Otaku>>
}
數(shù)據(jù)城堡(Database)
管著整個(gè)數(shù)據(jù)庫(kù)的家當(dāng):
@Database(entities = [宅男::class], version = 1)
abstract class 宅男宇宙 : RoomDatabase() {
abstract fun 管家(): 宅男管家
}
//??
@Database(entities = [Otaku::class], version = 1)
abstract class OtakuDatabase : RoomDatabase() {
abstract fun otakuDao(): OtakuDao // 保持管家服務(wù)
}
實(shí)例教學(xué)
第一步:加裝備胎
在module的build.gradle里塞這些:
dependencies {
// 基礎(chǔ)三件套
implementation "androidx.room:room-runtime:2.6.1"
kapt "androidx.room:room-compiler:2.6.1"
implementation "androidx.room:room-ktx:2.6.1"
// 可選外掛
implementation "androidx.room:room-paging:2.6.1" // 分頁(yè)加載
implementation "androidx.room:room-rxjava3:2.6.1" // 給RxJava愛好者
}
第二步:搞點(diǎn)事情
在ViewModel里調(diào)戲數(shù)據(jù)庫(kù):
class 宅男管理局(privateval 管家: 宅男管家) : ViewModel() {
// 實(shí)時(shí)監(jiān)控所有單身狗
val 單身貴族: Flow<List<宅男>> = 管家.查所有單身狗()
.flowOn(Dispatchers.IO) // 后臺(tái)線程保流暢
fun 新增成員(昵稱: String, 年齡: Int) {
viewModelScope.launch {
管家.新增宅男(宅男(昵稱 = 昵稱, 年齡 = 年齡))
// 自動(dòng)生成ID美滋滋
}
}
}
//??
class OtakuViewModel(privateval otakuDao: OtakuDao) : ViewModel() {
val singleOtakus: Flow<List<Otaku>> = otakuDao.getSingleOtakus()
.flowOn(Dispatchers.IO)
fun addOtaku(name: String, age: Int) {
viewModelScope.launch {
otakuDao.insert(
Otaku(name = name, age = age, isSingle = true)
)
}
}
}
坑爹預(yù)警(必看保命)
主線程禁忌
別在主線程搞數(shù)據(jù)庫(kù)!Room會(huì)直接給你甩臉崩潰。用協(xié)程、RxJava或者LiveData保平安。調(diào)試時(shí)可以開allowMainThreadQueries(),但上線前一定記得刪!
版本升級(jí)翻車現(xiàn)場(chǎng)
改表結(jié)構(gòu)時(shí)記得升級(jí)version,建議用Migration類處理。實(shí)在懶可以用:
fallbackToDestructiveMigration()
但會(huì)刪數(shù)據(jù)!(別問我怎么知道的)
索引的玄學(xué)
高頻查詢字段加索引,但每個(gè)索引會(huì)讓寫入速度下降。主鍵自帶索引,不用重復(fù)加。
類型轉(zhuǎn)換騷操作
想存Date類型?用TypeConverter變身:
class TimestampConverter {
@TypeConverter
fun dateToTimestamp(date: Date?) = date?.time
@TypeConverter
fun timestampToDate(timestamp: Long?) = timestamp?.let { Date(it) }
}
版本進(jìn)化史
版本 | 系統(tǒng) | 黑科技 |
2.2.x | 4.1+ | 協(xié)程支持、預(yù)裝數(shù)據(jù)庫(kù) |
2.5.x | 4.1+ | 自動(dòng)遷移、Upsert操作 |
2.6.x | 4.1+ | 性能起飛、全文搜索 |
高階玩法(裝逼必備)
聯(lián)合作戰(zhàn)(Room+Hilt)
@Module
@InstallIn(RoomComponent::class)
object 數(shù)據(jù)庫(kù)裝備庫(kù) {
@Provides
@Singleton
fun 召喚數(shù)據(jù)庫(kù)(上下文: Context): 宅男宇宙 {
return 宅男宇宙.啟動(dòng)基地(上下文)
}
@Provides
fun 召喚管家(數(shù)據(jù)庫(kù): 宅男宇宙): 宅男管家 {
return 數(shù)據(jù)庫(kù).管家()
}
}
// 在ViewModel里直接召喚
@HiltViewModel
class 高級(jí)管理局 @Inject constructor(
privateval 管家: 宅男管家
) : ViewModel() { }
//??
@Module
@InstallIn(RoomComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideDatabase(context: Context): OtakuDatabase {
return OtakuDatabase.getDatabase(context)
}
@Provides
fun provideDao(database: OtakuDatabase): OtakuDao {
return database.otakuDao()
}
}
@HiltViewModel
class OtakuViewModel @Inject constructor(privateval otakuDao: OtakuDao) : ViewModel() {
}
騷操作合集
- @Transaction保證多個(gè)操作原子性
- @RawQuery直接寫原生SQL(慎用?。?/li>
- @Relation處理一對(duì)多關(guān)系
- @Fts4搞全文搜索(2.6+專屬)
總結(jié)
Room這玩意兒就像樂高積木
- ?? Entity是基礎(chǔ)積木塊
- ?? DAO是組裝說(shuō)明書
- ??? Database就是樂高城堡
記住:官方給的輪子使勁用就完事了,別總想著自己造輪子!遇到問題多查官方文檔,保你頭發(fā)茂密~
最后送大家一張Room護(hù)身符:
SELECT * FROM 頭發(fā) WHERE 狀態(tài) = '茂密';