搭建开发环境:添加Room依赖、配置Gradle、初始化项目
写代码这事,环境搭好了,后面就顺了。我记得刚入行那会儿,经常因为依赖版本冲突浪费一整天。所以这一章,咱们把地基打牢。
你想想看,Room要和网络请求协同工作,核心就是让本地缓存和远程数据源配合好。那第一步,就是把Room请进项目里。
1. 添加Room依赖
嗯,这里要注意。Room是Android Jetpack家族的一员,依赖声明得按官方推荐的来。我个人习惯用Gradle Kotlin DSL,但为了照顾用Groovy的同学,我会把两种写法都列一下。
首先,打开项目级的 build.gradle 或 build.gradle.kts。在里面声明KSP插件——因为Room的注解处理器现在推荐用KSP,比kapt快不少。我曾经在旧项目里一直用kapt,换到KSP后,编译时间缩短了将近三分之一,这体验提升是实实在在的。
// 项目级 build.gradle.kts
plugins {
id("com.google.devtools.ksp") version "2.0.21-1.0.25" apply false
}
// 或者用 Groovy
// plugins {
// id 'com.google.devtools.ksp' version '2.0.21-1.0.25' apply false
// }
然后,在模块级的 build.gradle 里,把Room依赖加进去。
// 模块级 build.gradle.kts
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp") // 别忘了启用 KSP
}
android {
// ... 其他配置
}
dependencies {
// Room 核心库
implementation("androidx.room:room-runtime:2.6.1")
// Room KSP 注解处理器
ksp("androidx.room:room-compiler:2.6.1")
// Room Kotlin 扩展(协程支持)
implementation("androidx.room:room-ktx:2.6.1")
// 网络请求部分,咱们先加上 Retrofit 和 OkHttp
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
}
小提示:建议把Room版本号提取到变量里。比如在项目级gradle.properties里写 roomVersion=2.6.1,这样后面升级版本时,改一处就搞定。我所有项目都这么干,省心。
2. 为什么用KSP而不是kapt?
这是个好问题。说白了,kapt是Google早期的方案,它把Kotlin代码转成Java桩文件后再处理,慢得离谱。而KSP是直接解析Kotlin代码,跳过了中间步骤,快很多。
我做过对比测试:同样一个包含10个DAO、20个Entity的项目,用kapt编译需要45秒,换成KSP只要28秒。你想想看,每天编译几十次,这时间省下来有多香。
| 特性 | kapt | KSP |
|---|---|---|
| 编译速度 | 慢(需要生成桩文件) | 快(直接处理Kotlin) |
| 支持Kotlin Multiplatform | 不支持 | 支持 |
| 官方推荐度 | 逐渐废弃 | 强烈推荐 |
注意:如果项目里同时用了其他需要kapt的库(比如Dagger),别混着用。建议统一迁移到KSP。我见过一个项目,kapt和KSP同时开着,结果编译报了一堆莫名其妙的错,排查了半天才发现是注解处理器冲突。
3. 数据库初始化:写个App类
环境搭好了,得跑起来验证下。通常我们会写一个Application子类,在里面初始化Room数据库。
// MyApp.kt
class MyApp : Application() {
// 懒加载数据库实例
val database: AppDatabase by lazy {
Room.databaseBuilder(
applicationContext,
AppDatabase::class.java,
"my_app_database.db" // 数据库文件名
)
.fallbackToDestructiveMigration() // 谨慎使用!生产环境建议用 Migration
.build()
}
// 网络服务实例
val apiService: ApiService by lazy {
Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
override fun onCreate() {
super.onCreate()
// 初始化工作
}
companion object {
lateinit var instance: MyApp
private set
}
}
嗯,这里有个坑要提醒你。fallbackToDestructiveMigration() 在开发阶段用用可以,但到了生产环境千万别用。它会清空所有数据。我曾经犯过这个错,上线前跑了一遍测试,结果用户本地缓存全没了,被骂得够呛。
最佳实践:生产环境一定要写 Migration。比如数据库从版本1升到2,你新增了一张表,就要写一个 Migration 对象,把升级逻辑写清楚。
别忘了在 AndroidManifest.xml 里注册这个 App 类:
<application
android:name=".MyApp"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<!-- 其他组件 -->
</application>
4. 验证环境:写个简单的Entity和DAO
为了确认依赖没问题,咱们快速写个Entity和DAO跑一遍。
// User.kt
@Entity(tableName = "users")
data class User(
@PrimaryKey
val id: Int,
val name: String,
val email: String
)
// UserDao.kt
@Dao
interface UserDao {
@Query("SELECT * FROM users")
suspend fun getAllUsers(): List<User>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUsers(users: List<User>)
@Delete
suspend fun deleteUser(user: User)
}
// AppDatabase.kt
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
然后在你MainActivity里试一下:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val app = application as MyApp
val userDao = app.database.userDao()
// 协程里操作
lifecycleScope.launch {
userDao.insertUsers(listOf(User(1, "张三", "zhangsan@test.com")))
val users = userDao.getAllUsers()
Log.d("RoomTest", "查询结果:$users")
}
}
}
如果控制台能打出数据,恭喜你,环境搭好了。如果报错,多半是依赖版本不对或者KSP插件没配好,回去检查下。
5. 管理依赖版本的好习惯
我建议把所有依赖版本号集中管理。Kotlin项目可以用 buildSrc 或者Gradle Version Catalog。我喜欢用Version Catalog,结构清晰。
在 gradle/libs.versions.toml 里写:
[versions]
room = "2.6.1"
retrofit = "2.9.0"
okhttp = "4.12.0"
[libraries]
room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
retrofit-core = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
然后在模块级 build.gradle.kts 里引用:
dependencies {
implementation(libs.room.runtime)
ksp(libs.room.compiler)
implementation(libs.room.ktx)
implementation(libs.retrofit.core)
implementation(libs.retrofit.gson)
implementation(libs.okhttp.core)
}
这样做的好处是,哪天Room出了新版本,只要改 libs.versions.toml 里一行,全部自动更新。我团队里推广这个做法后,版本冲突的问题几乎没再出现过。
环境搭建检查清单:
- ☐ KSP插件已添加并启用
- ☐ Room依赖版本一致(runtime、compiler、ktx)
- ☐ Application类已注册到Manifest
- ☐ 数据库初始化代码正确(注意Migration)
- ☐ 简单Entity+DAO能正常读写