Room 是 Android 官方推荐的数据库框架,它是 SQLite 的抽象封装,提供了更便捷的数据库操作方式,支持 Kotlin 协程和 LiveData。以下是 Room 的基本使用方法:
1. 添加 Room 依赖
在 build.gradle.kts
(模块级)中添加 Room 相关依赖:
kotlin
dependencies {
val 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") // 支持 Kotlin 协程
}
如果项目使用 Kotlin Symbol Processing (KSP) 代替 kapt:
bash
ksp("androidx.room:room-compiler:$room_version")
2. 创建数据库实体(Entity)
使用 @Entity
注解定义数据库表:
kotlin
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "diary_entries") // 指定表名
data class DiaryEntry(
@PrimaryKey(autoGenerate = true) val id: Int = 0, // 主键,自动生成
val title: String,
val content: String,
val date: Long, // 以时间戳形式存储日期
val weather: String? = null
)
3. 创建 DAO(数据访问对象)
DAO 负责数据库的 CRUD 操作:
less
import androidx.room.*
@Dao
interface DiaryDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertDiary(entry: DiaryEntry)
@Update
suspend fun updateDiary(entry: DiaryEntry)
@Delete
suspend fun deleteDiary(entry: DiaryEntry)
@Query("SELECT * FROM diary_entries ORDER BY date DESC")
fun getAllDiaries(): List<DiaryEntry> // 直接返回列表(不推荐,建议使用 Flow)
@Query("SELECT * FROM diary_entries WHERE id = :id")
suspend fun getDiaryById(id: Int): DiaryEntry?
@Query("SELECT * FROM diary_entries WHERE title LIKE '%' || :query || '%'")
fun searchDiaries(query: String): List<DiaryEntry>
}
如果需要监听数据变化,可以用 Flow
:
kotlin
@Query("SELECT * FROM diary_entries ORDER BY date DESC")
fun getAllDiariesFlow(): Flow<List<DiaryEntry>> // 使用 Flow 以支持实时监听
4. 创建数据库(Database)
使用 @Database
注解创建 Room 数据库:
kotlin
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [DiaryEntry::class], version = 1, exportSchema = false)
abstract class DiaryDatabase : RoomDatabase() {
abstract fun diaryDao(): DiaryDao
companion object {
@Volatile
private var INSTANCE: DiaryDatabase? = null
fun getDatabase(context: Context): DiaryDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
DiaryDatabase::class.java,
"diary_database"
).build()
INSTANCE = instance
instance
}
}
}
}
说明:
@Volatile
确保多个线程能正确访问INSTANCE
。synchronized(this)
确保数据库实例的单例模式。
5. 在 ViewModel 中使用
在 ViewModel
里封装数据库操作:
kotlin
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.Flow
class DiaryViewModel(private val diaryDao: DiaryDao) : ViewModel() {
val allDiaries: Flow<List<DiaryEntry>> = diaryDao.getAllDiariesFlow()
suspend fun addDiary(entry: DiaryEntry) {
diaryDao.insertDiary(entry)
}
suspend fun deleteDiary(entry: DiaryEntry) {
diaryDao.deleteDiary(entry)
}
}
在 viewmodel
目录下新建 DiaryViewModelFactory.kt
文件,并写入以下代码:
kotlin
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.uibestpractice.data.DiaryDao // 替换为你的包名
class DiaryViewModelFactory(private val diaryDao: DiaryDao) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(DiaryViewModel::class.java)) {
return DiaryViewModel(diaryDao) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
6. 在 Activity/Fragment 中使用
在 Activity
或 Fragment
里使用 ViewModel:
kotlin
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private val diaryViewModel: DiaryViewModel by viewModels {
DiaryViewModelFactory(DiaryDatabase.getDatabase(this).diaryDao())
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 监听数据库变化
lifecycleScope.launch {
diaryViewModel.allDiaries.collect { diaryList ->
// 更新 UI
}
}
}
private fun addDiaryEntry() {
lifecycleScope.launch {
val newEntry = DiaryEntry(title = "新日记", content = "今天很开心!", date = System.currentTimeMillis())
diaryViewModel.addDiary(newEntry)
}
}
}
7. 线程调度(协程)
Room 允许在 suspend
函数中调用数据库操作,Kotlin 协程会自动切换到 IO 线程:
kotlin
suspend fun insertDiary(entry: DiaryEntry) {
diaryDao.insertDiary(entry) // Room 在 IO 线程执行
}
对于 不支持协程的函数 (如 getAllDiaries()
),应使用 withContext(Dispatchers.IO)
:
kotlin
fun getAllDiariesBlocking(): List<DiaryEntry> {
return runBlocking { withContext(Dispatchers.IO) { diaryDao.getAllDiaries() } }
}
总结
Room 提供了 简单、安全、高效 的数据库管理:
- Entity (表) →
@Entity
- DAO (数据操作) →
@Dao
- Database (数据库实例) →
@Database
- ViewModel(封装业务逻辑)
- Activity/Fragment(UI 层使用数据库)
你可以结合 Flow
进行 实时监听 ,结合 Kotlin 协程 进行 异步处理,使数据库操作更加流畅高效。