项目搭建与依赖配置:Gradle 依赖、Room 注解处理器、WorkManager 初始化、Retrofit 集成
2.1 本章概述
搭建离线同步项目的第一步是将核心组件接入 Android 构建系统。本章围绕 Room、WorkManager、Retrofit 三者的 Gradle 依赖声明、注解处理器配置、WorkManager 初始化方式以及 Retrofit 实例的集成流程展开,并厘清各组件在离线同步架构中的职责边界。
组件职能一览
| 组件 | 职责 | 依赖声明(KTS 格式) |
|---|---|---|
| Room | 本地持久化、DAO 操作、离线缓存 | room-runtime + room-ktx |
| WorkManager | 后台同步调度、约束管理、链式任务 | work-runtime-ktx |
| Retrofit | 网络请求、REST API 封装、拦截器链 | retrofit + converter-gson |
2.2 组件间依赖关系
下图展示了离线同步项目中各库的引用关系与初始化顺序。箭头方向表示“依赖”或“初始化触发”。
2.3 Gradle 依赖声明
在项目 build.gradle.kts(Module: app)中添加以下依赖。注意使用 KTS 脚本格式,版本号建议统一管理在 libs.versions.toml 中。
// app/build.gradle.kts
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp") // 使用 KSP 代替 kapt(性能更好)
}
android {
// ...
}
dependencies {
// Room
val roomVersion = "2.6.1"
implementation("androidx.room:room-runtime:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
ksp("androidx.room:room-compiler:$roomVersion") // 注解处理器
// WorkManager
val workVersion = "2.9.0"
implementation("androidx.work:work-runtime-ktx:$workVersion")
// Retrofit + Gson
val retrofitVersion = "2.9.0"
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
}关键点:Room 注解处理器必须显式声明。如果使用 kapt,则改为
kapt("androidx.room:room-compiler:$roomVersion")。未配置注解处理器将导致 DAO 编译失败,报错如“cannot find symbol RoomDatabase”或“TypeConverter not processed”。2.4 Room 注解处理器配置
Room 在编译期通过注解处理器生成数据库实现类(如 AppDatabase_Impl)。使用 KSP 时的额外配置:
// 在 app/build.gradle.kts 的 android 块中
android {
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
arg("room.incremental", "true")
}
}
上述配置会导出数据库 schema 至 app/schemas 目录,便于版本迁移测试。增量编译可加快后续构建。
2.5 WorkManager 初始化方式
WorkManager 2.6+ 默认使用 自动初始化(ContentProvider 注册),无需手动调用。但如果需要自定义配置(如自定义网络状态监听、日志级别),需在 AndroidManifest.xml 中移除默认提供程序,并手动初始化。
方式一:默认自动初始化(推荐简单场景)
<!-- AndroidManifest.xml 无需额外配置 — 系统自动注册 ContentProvider -->
方式二:手动初始化(需要自定义配置时)
<!-- AndroidManifest.xml 中移除默认初始化 -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
然后在 Application.onCreate() 中通过 Configuration 构建:
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
val config = Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.INFO)
.setWorkerFactory(MyCustomWorkerFactory())
.build()
WorkManager.initialize(this, config)
}
}
调试建议:在开发阶段将日志级别设为
Log.VERBOSE 或 Log.DEBUG,便于跟踪 WorkManager 的任务调度、约束判断和执行状态。2.6 Retrofit 集成与网络层配置
Retrofit 实例通常在 Application 或依赖注入容器中单例创建。以下为标准配置:
// RetrofitClient.kt
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
private const val BASE_URL = "https://api.example.com/"
private val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY // 调试阶段用 BODY,生产用 HEADERS 或 NONE
}
private val okHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.connectTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
.readTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
.writeTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
.build()
private val gson = GsonBuilder()
.setLenient()
.create()
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
定义 API 接口:
interface ApiService {
@GET("sync/items")
suspend fun getItems(): List<Item>
@POST("sync/items")
suspend fun postItem(@Body item: Item): Response<Void>
}
2.7 常见错误与排查
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
编译时 cannot find symbol AppDatabase_Impl | Room 注解处理器未配置或 kapt/ksp 插件未应用 | 确认添加了 ksp("androidx.room:room-compiler:$version") 且模块应用了 KSP 插件 |
WorkManager 初始化崩溃:IllegalStateException: WorkManager is already initialized | 自动初始化与手动初始化冲突 | 使用 AndroidManifest 中的 tools:node="remove" 禁用自动初始化 |
Retrofit 请求返回 java.net.SocketTimeoutException | 超时时间过短或网络不可用 | 增大 OkHttp 超时时间或添加重试拦截器 |
| 依赖版本冲突(如 Kotlin 版本与 Room 不兼容) | 库版本未对齐 | 使用 BOM 管理版本,或参考 AndroidX 版本映射 |
2.8 性能与稳定性优化备忘
- 依赖精简:避免引入完整 Guava 库;Retrofit 可搭配
converter-scalars替代 Gson 以降低包体积(若无需 JSON 序列化)。 - OkHttp 连接池:单例 OkHttpClient 复用连接、降低延迟。
- Room 增量编译:启用
room.incremental=true减少二次构建时间。 - WorkManager 惰性初始化:仅在第一次调用
WorkManager.getInstance(context)时触发初始化,避免 Application 启动耗时增加。 - 网络日志切面:在
BuildConfig.DEBUG条件判断下添加HttpLoggingInterceptor,发布版本自动移除。
2.9 配置验证小实验
执行以下命令验证 Gradle 依赖是否正确拉取:
./gradlew app:dependencies --configuration implementation | grep -E "(room|work|retrofit)"
输出应包含类似条目:
+--- androidx.room:room-runtime:2.6.1
+--- androidx.work:work-runtime-ktx:2.9.0
+--- com.squareup.retrofit2:retrofit:2.9.0
若缺少 Room 注解处理器,可检查 ksp 的配置:
./gradlew app:kspKotlinDebug --info | grep "room-compiler"
如输出版本号,则注解处理器已生效。
下一步建议:确认依赖无误后,即可进入第3章“定义 Room 数据库与 DAO”。本章配置是后续所有编码的基础,务必确保构建通过。