Android 离线优先的数据同步设计

举报
yd_223002268 发表于 2026/09/20 08:46:52 2026/09/20
【摘要】 Android 离线优先的数据同步设计离线优先并不意味着所有页面永远展示缓存,而是让界面拥有稳定的本地数据源,并在网络可用时按业务规则同步。设计不当时,常见问题包括本地修改被旧响应覆盖、离线操作重复提交、多个同步任务互相抢写,以及用户看到无法判断新旧的数据。 一、建立单一可观察数据源页面优先观察本地数据库,网络同步只负责更新数据库。这样界面不会在接口结果和本地结果之间反复切换。class ...

Android 离线优先的数据同步设计

离线优先并不意味着所有页面永远展示缓存,而是让界面拥有稳定的本地数据源,并在网络可用时按业务规则同步。设计不当时,常见问题包括本地修改被旧响应覆盖、离线操作重复提交、多个同步任务互相抢写,以及用户看到无法判断新旧的数据。

一、建立单一可观察数据源

页面优先观察本地数据库,网络同步只负责更新数据库。这样界面不会在接口结果和本地结果之间反复切换。

class NoteRepository(
    private val noteDao: NoteDao,
    private val remoteDataSource: NoteRemoteDataSource
) {
    fun observeNotes(): Flow<List<Note>> {
        return noteDao.observeAll()
            .map { entities -> entities.map(NoteEntity::toDomain) }
    }

    suspend fun refresh() {
        val response = remoteDataSource.queryNotes()
        noteDao.replaceRemoteSnapshot(response.map(NoteDto::toEntity))
    }
}

数据库事务负责确保快照替换期间不会暴露中间状态。

二、记录同步元数据

仅保存业务内容不足以处理同步。通常还需要:

  • 本地修改时间。
  • 服务端版本或更新时间。
  • 当前同步状态。
  • 最近一次失败原因。
  • 稳定的操作标识。
enum class SyncState {
    SYNCED,
    PENDING_CREATE,
    PENDING_UPDATE,
    PENDING_DELETE,
    FAILED
}

同步状态是数据层事实,界面可据此显示“待同步”或“失败”,而不是根据网络是否连接来猜测。

三、离线写入先落本地

用户编辑完成后,先在本地事务中保存内容并创建待同步操作,界面立即从数据库看到变化。

suspend fun saveLocalEdit(note: NoteEntity, operation: SyncOperationEntity) {
    database.withTransaction {
        noteDao.upsert(note)
        syncOperationDao.insert(operation)
    }
}

业务内容与操作记录必须共同成功。否则可能出现界面显示已保存,但没有任何任务负责同步。

四、让同步操作具备幂等性

后台任务可能重复执行。每个离线操作应有稳定标识,服务端和客户端据此识别重复提交。创建类操作尤其不能每次重试都生成新业务对象。

操作成功后,在同一事务中更新本地业务记录并删除队列项。若进程在服务端成功后、本地记录前终止,下一次重试仍应得到同一业务结果。

五、明确冲突解决规则

本地和远端同时修改同一对象时,需要字段所有权和冲突策略。常见选择包括:

  • 服务端版本优先。
  • 本地未同步编辑优先。
  • 最后修改时间优先。
  • 不同字段分别合并。
  • 标记冲突并让用户选择。

时间优先只有在双方时钟和时间语义可靠时才成立。金融确认、审批等关键数据不应仅凭客户端时间覆盖。

六、删除也要建模

离线删除后不能立即丢掉所有同步线索。可以保留删除标记或待删除操作,等服务端确认后再彻底清理。

如果同步刷新时服务端仍返回该对象,本地删除状态不应被直接覆盖。删除由谁拥有最终解释权,必须在协议中明确。

七、网络恢复不等于立即同步全部

网络状态只说明当前可能具备通信条件,不保证服务可用。同步任务仍应处理超时、身份失效和业务拒绝。

大量积压操作恢复时要控制并发和顺序。同一对象的创建、更新、删除必须按依赖执行,不同对象是否并发则根据服务能力决定。

持久后台任务应交给项目已有的任务调度组件,不能只依赖页面协程。

八、向用户表达数据状态

离线优先不能掩盖数据时效性。页面可以显示:

  • 最近同步时间。
  • 当前离线状态。
  • 某条记录正在同步或同步失败。
  • 需要用户处理的冲突。

旧数据如果可能导致错误决策,就不应以正常样式无提示展示。是否允许继续操作也要按业务风险控制。

九、限制队列和存储增长

连续编辑同一草稿时,可以在保证语义一致的前提下合并多条待更新操作。创建后立即删除且从未同步的对象,可能直接取消两项操作。

不能合并有审计意义的动作,例如逐笔交易指令。队列压缩规则必须与业务语义一致。

十、测试异常恢复

重点覆盖:

  • 无网络时编辑是否成功落本地。
  • 进程重启后待同步操作是否仍存在。
  • 同一操作重复执行是否产生重复数据。
  • 服务端成功、本地提交前中断后能否恢复。
  • 本地编辑与远端更新冲突是否按规则处理。
  • 删除标记是否会被远端旧快照覆盖。
  • 账户退出时队列是否按范围处理。

总结

离线优先架构的基础是本地单一数据源和持久操作队列。通过同步元数据记录状态,以幂等操作支持重试,再明确更新、删除和冲突的最终解释权,应用才能在断网、进程重建和多端修改下保持数据可信。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。