数据层实现:本地数据库与网络数据源

数据层是 Repository 模式离线分层架构中直接与数据持久化和远程通信交互的边界。它屏蔽数据来源的物理差异,向上层 Repository 提供统一的数据访问接口。本章聚焦本地数据库(SQLite 与 Room)、网络 API 适配器以及数据源切换机制,阐述组件职责、选型权衡、落地方案与验收标准。

组件边界与职责

组件职责所属位置
LocalDataSource封装本地数据库操作,提供离线缓存、持久化存储数据层内(本地侧)
RemoteDataSource封装网络 API 调用,负责远程数据获取与提交数据层内(网络侧)
DataSourceSwitcher根据离线策略(如网络可用性、缓存时效)选择数据源数据层内(调度中心)
Repository组合本地与远程数据源,对外暴露纯净数据接口数据层之上(领域层)

本地数据库选型:SQLite vs. Room

维度原生 SQLiteRoom(Android官方ORM)
抽象层级直接操作 SQL,低层 API注解驱动,自动生成 DAO 与编译时验证
开发效率低,需手写 SQL 与 cursor 解析高,通过 Entity/DAO 快速映射
数据库迁移手动版本管理,易出错内置 migration 机制,自动升级
测试友好度需 mock SQLiteDatabase支持 standalone 测试,MemoryDatabase
推荐场景极简嵌入式、已有 C 库复用Android 平台标准离线分层
架构建议:在离线分层架构中优先采用 Room。它天然适配 Repository 模式,编译时校验 SQL 语句,并提供 Flow/LiveData 响应式查询,减少数据同步样板代码。

网络 API 适配器设计

网络 API 适配器(RemoteDataSource)是数据层与外部服务之间的适配边界。常见实现使用 Retrofit + OkHttp,职责包括:

  • 封装 RESTful 接口定义,返回 DataResult<T> 统一类型
  • 处理连接超时、HTTP 错误码、序列化异常
  • 提供限流、重试(指数退避)、Cookie 同步等可插拔组件
  • 对接上游 DataSourceSwitcher,反馈网络状态(如 ConnectivityManager 监听)

数据源切换机制

数据源切换是离线分层架构的核心控制流。典型策略包含:

  1. 先本地后远程(Cache-First):每次请求优先查询本地数据库,若数据不满足时效或缺失,则调用网络同步后更新缓存。
  2. 仅远程(Network-Only):强制走网络,本地仅作失败降级(Offline-Fallback)。
  3. 仅本地(Offline-Mode):完全依赖本地数据库,适用于飞行模式或用户设置离线状态。
风险点:切换过程中需要处理并发竞争(网络回调与本地写入同时发生)和数据一致性(过期数据覆盖新数据)。建议在 DataSourceSwitcher 内使用乐观锁或版本号字段,避免脏写。

数据流与控制流:信任链路

下图展示数据层内部组件间的调用关系与数据流向(图中省略外部网络细节)。

数据层组件图 & 数据流向 Repository DataSourceSwitcher LocalDataSource (Room / SQLite) RemoteDataSource (网路API适配器) Network API 读取/写入 请求/响应 HTTP调用 解析:左上绿色为本地持久化节点,右上红色为远程适配节点,中间紫色为切换调度器。 箭头方向表示控制流(Repository → 调度器 → 具体数据源),数据流为双向。

落地步骤

  1. 定义数据源接口:
    interface IDataSource<T> {
        suspend fun get(key: String): Result<T>
        suspend fun put(key: String, value: T): Result<Unit>
        suspend fun remove(key: String): Result<Unit>
    }
  2. 实现 LocalDataSource:基于 Room 的 DAO,在 Entity 中添加 version 字段用于乐观锁。
  3. 实现 RemoteDataSource:使用 Retrofit 定义 ApiService,返回 Result 类型并映射异常。
  4. 构建 DataSourceSwitcher:持有 LocalDataSource 与 RemoteDataSource 引用,依据网络状态和缓存策略选择数据源。策略可配置为策略模式枚举。
  5. 注入 Repository:Repository 只依赖 DataSourceSwitcher,由依赖注入框架(如 Hilt)提供。

选型权衡

决策点选项权衡
网络库Retrofit vs. Ktor ClientRetrofit 成熟生态好;Ktor 协程原生更轻量,但适配 Android 时需注意线程切换
序列化Moshi vs. Gson vs. Kotlin SerializationMoshi 性能好且 Kotlin 空安全;Kotlin Serialization 编译时生成,无反射开销
离线缓存策略Write-Through / Write-Back / Cache-AsideWrite-Through 强一致性但写入慢;Cache-Aside 常见于读过期场景;Write-Back 风险大

验收标准

  • 本地数据库操作(增删改查)在无网络环境下正常返回数据,且符合缓存时效逻辑。
  • 网络 API 适配器能正确处理超时(10s)、400/500 状态码,并统一转换为 DataResult.Error。
  • 数据源切换器在模拟飞行模式后自动降级至本地,恢复网络后能触发增量同步。
  • 并发写入测试(多次直接修改同一记录)最终一致且不丢失数据(基于 version 冲突检测)。
风险点小结:数据库迁移失败导致数据丢失;网络切换期间缓存与远程数据不一致;Room 的 Flow 与远程流合并时背压处理不当导致 OOM。建议在架构早期加入 version 版号控制和数据一致性单元测试。