news 2026/10/14 7:05:00

D13_离线缓存与一致性

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
D13_离线缓存与一致性

Android 学习笔记 D13|离线列表:刷新文章时,别把用户收藏一起覆盖

摘要:把文章元数据与收藏分开存储,让数据库成为首页读取来源,设计缓存启动、刷新失败、事务替换和缓存过期行为。

标签:Android、离线缓存、Room、Repository、数据一致性

本文对应 28 天课程 D13,连接《第一行代码》第 3 版第 7、11、13 章。今天的目标是在断网时仍能浏览已经保存的首页文章元数据。缓存标题、作者和 URL 不等于缓存网页全文,文章详情中的外部页面仍可能需要网络;这一点应在界面和博客中讲清楚。

1. 首页只保留一条显示链路

最初的网络页面会把响应直接交给 UI,后来增加缓存,又在启动时从数据库读取另一份列表。如果两条链路独立写状态,容易出现网络成功显示新数据、缓存稍后返回又覆盖新数据的问题。本文选择数据库作为首页读取来源:页面观察本地查询,网络刷新成功后只更新数据库。

这意味着“刷新成功”应包括本地写入成功。HTTP 收到内容但数据库写入失败,页面仍没有新的可靠状态,不能一边显示成功一边静默丢弃。离线架构需要明确读取来源和写入责任,官方指南也把本地来源视为上层读取的重要依据。Android 离线优先指南

本课缓存首页列表,搜索结果暂不持久化;因此离线时可以浏览已有首页,但不承诺任意关键词都能搜索。功能边界越具体,实验越容易判断,而不是把所有失败都藏在“缓存机制”四个字里。

2. 用三类记录区分三种事实

文章内容表保存 ID、标题、作者、链接与更新时间。首页成员表保存文章 ID 和位置,表示某篇文章当前是否属于这份首页快照。收藏表保存用户主动选择及收藏时间。内容、列表归属、用户选择分别变化,分开之后就不必靠一张大表里的多个布尔值互相猜测。

刷新首页时可以更新文章内容并重建首页成员,不删除收藏。某篇文章从新首页消失,也不意味着它不再可收藏或详情必须立即失效。初学版本暂时保留已获取内容,之后再根据引用和期限清理;不能简单在刷新前执行“删除所有文章”,否则可能破坏收藏详情。

下面是 SQL 结构与事务的教学伪代码,旨在说明提交边界,不是可直接复制编译的 Room API。Room 2 和 Room 3 的事务调用应使用所选版本对应文档,字段及 DAO 需在工程中实现。

CREATETABLEarticle_cache(articleIdINTEGERPRIMARYKEY,titleTEXTNOTNULL,authorTEXTNOTNULL,urlTEXTNOTNULL,updatedAtINTEGERNOTNULL);CREATETABLEhome_entry(articleIdINTEGERPRIMARYKEY,positionINTEGERNOTNULL);-- 一次成功网络响应已经转换成合法模型之后:BEGINTRANSACTION;-- 逐条插入或更新 article_cache,保留 bookmark 不动DELETEFROMhome_entry;-- 按响应顺序插入新的 home_entryCOMMIT;-- 首页读取:SELECTa.*,(b.articleIdISNOTNULL)ASisBookmarkedFROMhome_entry hJOINarticle_cache aONa.articleId=h.articleIdLEFTJOINbookmark bONb.articleId=a.articleIdORDERBYh.position;

真正实现还应对网络结果按 ID 去重,并为顺序赋值,避免相同 ID 两次插入冲突。首页成员与内容更新需要在同一事务中完成,确保读者不会看到“成员已替换而文章尚未写入”的中间状态。网络请求本身应在数据库事务外进行,不能让慢网络占据长事务。

3. 缓存年龄与失败提示是不同状态

有缓存时启动,先显示本地结果,再尝试刷新;刷新失败保留内容,并告诉用户当前显示的是已有数据。无缓存时失败,则显示失败重试,不把它写成“没有文章”。成功响应为空时,本例清空首页成员并展示真正空态,但不会清空收藏或所有文章资料。

给缓存记录更新时间,可以说明数据来自什么时候。超过期限并不必然必须隐藏:新闻、配置、价格等业务对陈旧数据的容忍不同。本学习项目允许陈旧文章元数据继续展示并提示更新失败。缓存淘汰、请求节流和展示过期提示属于不同策略,不应只放一个expired就试图解决全部问题。

HTTP 缓存也不能替代这里的业务数据库。前者按 HTTP 语义复用响应,后者支持按文章 ID 查找、关联本地收藏和稳定展示。它们可以同时存在,但发生问题时必须分辨数据是网络响应缓存命中,还是本地文章表查询得到。

4. 四组离线实验

先联网加载 A、B 两篇文章,收藏 B,然后断网并重启。预期首页仍显示 A、B,B 的收藏标记仍在,刷新提示失败但内容不消失。随后清理测试数据,用无缓存状态断网进入,预期出现可重试错误而非成功空列表。

第三组让 Fake 返回相同 ID 的新标题。刷新后预期标题改变,收藏时间与收藏归属保持不变。第四组在替换首页事务中人为抛出测试异常,预期整个数据库变更回滚,旧首页仍可读取;不得只剩空成员或半份结果。故障注入仅在测试实现里进行,记录前后 ID 集合和收藏行数。

再额外观察启动顺序:数据库首次发出结果与网络刷新可以快慢不同,但页面只接受同一查询链路的输出。若仍然会新旧闪回,应检查是否还残留一个直接把网络列表写进 UI 的入口。这里的描述是验证方法,尚非你设备上的测试结论。

5. 原创面试问答与追问

问一:数据库作为读取来源有什么价值?在线与离线显示经过同一查询,减少多套列表竞争。追问:网络成功本地写入失败算刷新成功吗?本设计不算,页面的数据更新未完成提交。

问二:为什么收藏不能放进每次覆盖的网络文章里?收藏是本地用户意图,网络刷新不应重置它。追问:必须分表吗?不绝对,但更新语句必须明确保护收藏字段,分表能把边界表达得更清楚。

问三:缓存过期后一定要删吗?由业务容忍度决定,文章元数据可以带提示继续展示。追问:保存了 URL 能离线读网页吗?不能,需要另外设计全文或资源保存方案。

以上是原创自测,不代表面试鸭题库原题或官方答案。

6. D13 验收

画出“网络刷新→事务写入→数据库查询→UI”的数据流;说明收藏为何不会被刷新覆盖;完成有缓存断网、无缓存断网、同 ID 更新及写入失败回滚四组实验。书本第 7 章建立持久化基础,第 11 章提供网络来源,第 13 章连接 Room。下一课将通过取消全部收藏检验这些边界是否真的成立。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 7:04:46

用纯C#打造Blazor五子棋:组件通信与核心算法实战

花了一个周末,把“五子棋”这种几乎人人都会玩的小游戏,用 Blazor 从零搭了出来,顺便把这两年攒的 UI 交互经验全砸了进去。这个项目的成品不复杂,也没有用什么黑科技,就是用纯 C# 写完一整条交互链路:棋子…

作者头像 李华
网站建设 2026/10/14 7:04:32

制造业FMEA数字化转型:从失效分析到智能预防

1. FMEA为何沦为"睡美人":制造业的普遍困境车间里那本落满灰尘的FMEA手册,就像一位被施了魔法的睡美人——明明拥有改变企业质量命运的能力,却被锁在文件柜里长眠不醒。我在汽车零部件行业做质量总监的十年间,见过太多企…

作者头像 李华
网站建设 2026/10/14 7:04:14

大模型Tool Use手写实战:三种方案对比与面试避坑指南

1. 面试现场:从“八股文”到“手写 Tool Use”的转变1.1 为什么 Tool Use 成了面试新宠这两年技术面试的风向变了。早几年大家还在背“三次握手四次挥手”、“HashMap 扩容原理”,现在面试官更倾向于让你现场写点能跑的东西。尤其是大模型应用开发岗位兴…

作者头像 李华
网站建设 2026/10/14 7:03:41

RabbitMQ核心机制与实战:从消息队列原理到可靠投递

1. RabbitMQ到底解决了什么问题——先聊清楚“为什么需要它”1.1 同步调用的痛点做后端开发的朋友,应该都经历过这种场景:一个接口里要同时调用订单服务、库存服务、积分服务,三个下游接口都正常的时候还好,但凡其中一个慢一点、挂…

作者头像 李华
网站建设 2026/10/14 7:03:39

HBuilderX蓝牙通讯实战:plus.bluetooth接口从扫描到数据收发全解析

简介:基于HBuilderX实现的HTML5蓝牙通信示例工程,面向Web前端与移动端开发者,演示如何通过Web Bluetooth API与低功耗蓝牙设备建立连接、读取特征值并完成双向数据收发;同时给出常见异常和连接失败的处理思路。项目亲测可用&#…

作者头像 李华