1. 课程介绍:离线优先架构与本地存储概述

说实话,这几年做移动端 App,我越来越觉得“离线优先”不是什么 fancy 概念,而是刚需。用户在山里、地铁上、电梯里,随时都可能断网。如果 App 一离线就摆烂,那体验基本就废了。我最早带的一个项目,上线后被用户吐槽“一进地下室就白屏”,那会儿才意识到:网络稳定只是一种美好的假设。

那离线优先架构到底怎么落地?本地存储就是地基。Android 上两大主力选手——Room 和 DataStore,各有所长。但选型不是拍脑袋,得结合场景、一致性要求、查询复杂度来做决策。这章我们先把全景图理清楚。

1.1 什么是离线优先架构?

离线优先,英文叫 Offline-First。核心思想很简单:默认数据先从本地读取,本地没有才去网络拉;写操作也先写本地,再排队同步到服务端。对比传统的 Online-Only:

  • Online-Only:网络断了,App 直接废了,顶多给个错误提示。
  • Offline-First:断网时照样操作本地数据,联网后自动同步冲突。

我在一个电商 App 里用过这套方案。用户在飞机上购物车加了一堆东西,落地后 Wi-Fi 一开,后台自动提交订单。这体验,你说香不香?

离线优先 ≠ 离线可用
离线可用只是保底功能,离线优先是把本地数据当作一等公民。两者区别在于:离线优先要求数据在本地有完整副本,并且能处理同步冲突。

1.2 为什么需要本地存储?

离线数据总要有个家。本地存储就是那个「安全屋」。但 Android 上本地持久化方案五花八门:SharedPreferences、SQLite、File、Room、DataStore……我自己的经验是:SharedPreferences 只适合存几个简单标记,比如“是否已经引导”,复杂数据千万别碰。而 Room 和 DataStore 是官方主推的现代存储,值得深入理解。

她俩分工其实挺明确:

  • Room:面向关系数据,支持复杂查询、索引、迁移。适合订单、联系人、消息列表这类结构化数据。
  • DataStore:面向键值对或 Proto 数据,轻量、异步、无 SQL 负担。适合设置项、偏好、缓存快照。

我在一个项目中同时用了 Room 存储用户资料库,DataStore 存储 App 主题和语言偏好。各司其职,互不干扰。那个项目的同步逻辑至今没出过数据一致性问题,嗯,值得骄傲一下。

1.3 Room vs DataStore:选型决策框架

选型不是非此即彼,而是看场景。我画了个简单的对比表,帮你快速决策:

维度 Room DataStore
数据模型 关系型(实体+DAO) 键值对或 Proto 字节
查询能力 SQL(流式查询、聚合、排序) 仅按 key 读取 / 写入
数据规模 大(上千条记录) 小(KB ~ MB 级别)
并发安全 通过 DAO 和事务保证 内置事务,读取无锁
迁移成本 需写 Migration 脚本 基本无需迁移(Proto 版本兼容)
适用场景 数据库级数据 配置、序列化对象、快照

我的选型口诀:
如果数据之间有关联关系,需要 JOIN、排序、分页 —— 选 Room。
如果数据只是简单的键值对或单条 Proto 对象 —— 选 DataStore。

1.4 快照一致性是什么?

快照一致性,听起来挺学术。说白了,就是保证用户在任何时刻看到的本地数据,都是一张完整的不矛盾的「快照」。比如聊天列表里,消息的已读状态和未读数不能对不上。

我记得有一次,用户反馈在飞机上编辑了一条笔记,落地后打开发现内容前后不一致。查了半天,原来是本地写操作没有用事务保护,一部分字段写进去了,另一部分还在内存里。这就导致了「半份数据」被展示。快照一致性就是通过事务或原子写入,保证要么全部成功,要么什么都不变。

Room 的 @Transaction 注解可以一次性提交多个 DAO 操作,保证原子性。DataStore 内部基于 Flow,每次写都是整个替换,天然保证了快照一致性。但要注意:在跨存储(Room + DataStore)的场景下,需要自己协调事务边界。

我曾经踩过的坑:
在 Room 中同时更新两个实体,忘记加 @Transaction,结果网络中断导致部分写入。从那以后,我所有涉及多表写入的操作,一律包在事务里。教训啊,朋友们。

1.5 离线优先架构核心组件

下面这张图,把离线优先架构的关键模块画出来了。你可以把它当作整门课的索引图:

离线优先架构核心组件 本地存储层 远程层 Room 关系型存储 事务 + 流式查询 DataStore 键值 / Proto 原子写入 Remote API REST / GraphQL / gRPC 网络不稳定 Sync Engine(同步引擎) 冲突解决、分批同步、重试机制 确保本地与远程最终一致 Repository 数据路由 + 缓存策略 UI Layer 观察 Flow / LiveData 关键点:本地存储(Room + DataStore)为离线优先提供数据基座,Sync Engine 保证快照一致性。 Flow 推送

这张图里,你可以看到 Room 和 DataStore 都位于本地存储层,它们向上为 Repository 提供数据,向下不与网络直接交互。Sync Engine 是连接本地与远程的桥梁,负责拉取远程数据写入本地,同时也把本地未同步的数据推送到服务器。整个过程的快照一致性,由 Room 的事务和 DataStore 的原子写入来保障。

本章小结:
离线优先架构的核心是“写本地优先、本地当权威源”。Room 和 DataStore 是 Android 官方的两把利刃,选型时对照数据复杂度决定。快照一致性不是锦上添花,而是防止数据混乱的生命线。后面的章节,我们会逐层深入每个组件的实现细节和最佳实践。