Room 是 Android 官方推荐的数据库框架,它是 SQLite 的抽象封装,提供了更便捷的数据库操作方式,支持 Kotlin 协程和 LiveData。以下是 Room 的基本使用方法:


1. 添加 Room 依赖

build.gradle.kts(模块级)中添加 Room 相关依赖:

1
2
3
4
5
6
7
8
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:

1
ksp("androidx.room:room-compiler:$room_version")

2. 创建数据库实体(Entity)

使用 @Entity 注解定义数据库表:

1
2
3
4
5
6
7
8
9
10
11
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 操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

1
2
@Query("SELECT * FROM diary_entries ORDER BY date DESC")
fun getAllDiariesFlow(): Flow<List<DiaryEntry>> // 使用 Flow 以支持实时监听

4. 创建数据库(Database)

使用 @Database 注解创建 Room 数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 里封装数据库操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 文件,并写入以下代码:

1
2
3
4
5
6
7
8
9
10
11
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 中使用

ActivityFragment 里使用 ViewModel:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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 线程:

1
2
3
suspend fun insertDiary(entry: DiaryEntry) {
diaryDao.insertDiary(entry) // Room 在 IO 线程执行
}

对于 不支持协程的函数(如 getAllDiaries()),应使用 withContext(Dispatchers.IO)

1
2
3
fun getAllDiariesBlocking(): List<DiaryEntry> {
return runBlocking { withContext(Dispatchers.IO) { diaryDao.getAllDiaries() } }
}

总结

Room 提供了 简单、安全、高效 的数据库管理:

  1. Entity(表) → @Entity
  2. DAO(数据操作) → @Dao
  3. Database(数据库实例) → @Database
  4. ViewModel(封装业务逻辑)
  5. Activity/Fragment(UI 层使用数据库)

你可以结合 Flow 进行 实时监听,结合 Kotlin 协程 进行 异步处理,使数据库操作更加流畅高效。