- 博客(91)
- 收藏
- 关注
原创 D26_数据库迁移与可复现构建
新增字段表示用户是否阅读过文章,需要先确定三条规则:旧记录默认未读;字段值与业务含义写清楚后,才能选择数据库默认值。SQL 不是完整 Room 迁移实现。还需要更新 Entity、提升数据库版本、注册对应迁移,并使列名、可空性和数据库默认值一致。Kotlin 构造参数的默认值与数据库 schema 的默认值不是同一个东西,不能只给属性写= false就认为数据库结构声明完整。Room 迁移本系列前面的 Room 示例采用当前文档对应代际。
2026-10-16 08:49:59
233
原创 D24_窗口适配与渲染检查
在自己的模拟器上看起来合适的详情页,换成分屏、大字体或横屏后,分享按钮可能被挤出屏幕。这类问题不能只靠把文字缩小解决,因为真正变化的是可用空间、阅读需求与交互路径。本文对应课程 D24,联系《第一行代码》第 4 章布局、第 5 章不同设备界面和第 12 章界面体验。书中的传统 View 知识用于建立尺寸与布局概念,Compose 的窗口适配属于进一步实践。
2026-10-16 08:41:26
393
原创 D23_Handler线程与回调持有
在后台线程里调用主线程 Handler 的 post,回调到底在哪执行?退出页面以后,延迟任务为什么仍可能持有 Activity?这两个问题可以通过同一个小实验讲清楚,不必一开始就背诵整套源码。本文对应课程 D23,回查《第一行代码》第 10 章的线程与异步消息处理。练习入口和故意制造的故障只用于调试,最终应从正式业务流程中移除。下文的现象是实验预期,没有虚构设备实测结果。
2026-10-16 08:34:43
176
原创 D22_行为测试与虚拟时间
文章列表能打开,不意味着数据链路已经可靠。这一天先不追求覆盖率数字,而是把四个已经承诺给用户的行为变成可以自动检查的约束。本文对应课程 D22。书籍的网络、存储与 Jetpack 内容提供被测试对象,本篇的 Fake、协程测试和 Compose 测试属于工程实践拓展。示例是教学用的独立逻辑,不代表 DevCommunity 已经具有这些测试。
2026-10-15 14:56:27
251
原创 D21_第三周系统功能回归
标签:Android、调试、状态管理、项目复盘。前六天增加了主题、滑页、传统列表、网页阅读、分享和后台任务。每个功能单独演示都正常,连起来却可能出错。这个案例是用于复现与推理的实验,不是已经发生在用户项目里的真实经历。本文对应 D21。相关基础回读《第一行代码》第 3—5 章的页面与列表、第 7—8 章的存储与组件、第 10—11 章的服务与网络,以及第 13.6 节后台任务。今天不增加新库,目标是把多个局部正确的功能组成一个一致的系统。
2026-10-15 14:54:15
239
原创 B20_PermissionX与库API设计
权限库可以减少重复注册、结果整理和回调分发,但不能替应用决定为什么需要某项权限,也不能绕过用户选择和系统限制。调用者仍负责把申请放在合适业务时机,解释用途,并处理拒绝后的替代路径。只返回一个 Boolean 常常不够。一次请求多项权限时,可能部分获得、部分拒绝;有些能力又随系统版本、授权范围和后续设置变化。API 应表达实际返回结果,而不是把复杂情况压成一个容易误解的“全部搞定”。
2026-10-15 14:50:31
159
原创 D19_系统分享与文件URI
发布摘要:先分享文章标题和链接,再用最小 FileProvider 配置分享导出的文本文件,理解 Intent、URI 和临时授权。标签:Intent、FileProvider、Android、文件分享。文章阅读页增加分享按钮,第一版只需要把标题和链接交给系统分享面板。cacheDir路径塞进去:另一个应用没有权限访问我们的私有目录。两种分享看起来都是“发送”,实际传递的数据和授权完全不同。本文对应 D19;
2026-10-15 14:45:07
193
原创 D18_WebView阅读与返回
练习版针对受控、不含表单的页面和普通链接导航,内嵌入口限制为业务确认过的 HTTPS 主机;回调捕获的其他合法 HTTPS 链接交给外部浏览器,异常协议拒绝。主机应解析后精确比较,不能使用“字符串包含本站域名”,否则本站域名.evil.example也会通过。首次加载与回调捕获的网页内跳转使用同一判断。这里的允许列表不代表自动审查所有子资源,也不是完整浏览器隔离方案。不覆盖 POST 导航,不能用下面的客户端证明任意网页的全部主框架导航都被限制;
2026-10-14 08:34:25
299
原创 D17_传统View与Compose互操作
发布摘要:建立独立的传统列表练习入口,掌握列表身份、Fragment 的 View 生命周期,以及 ComposeView 的释放边界。标签:Fragment、RecyclerView、ViewBinding、Compose。主项目用 Compose,不代表可以跳过传统 View。维护已有代码时,经常需要在 Fragment 列表上增加一个提示区,或者把一个旧控件放进新界面。真正难的不是两套语法,而是它们拥有不同的对象寿命。
2026-10-14 08:28:38
214
原创 D16_HorizontalPager页签与状态
标签:Compose、HorizontalPager、导航、Android。进入详情回来,列表回到顶部;来回切十次,接口也请求十次。本课不是只完成一个能拖动的容器,而是明确每一种状态由谁管理。本文对应 D16。书中第 4 章的列表和第 5 章的页面组织提供基础,Compose Foundation Pager 属于路线扩展。下面代码是未编译运行的核心片段,使用项目现有 Compose BOM 对应的 Foundation、Material3 和协程依赖。
2026-10-14 08:20:19
123
原创 D15_DataStore主题设置
发布摘要:给 DevCommunity 增加跟随系统、浅色、深色三种主题,重点解决设置持久化、启动闪烁和写入状态的问题。标签:Android、DataStore、Compose、状态管理。真正应当先考虑的是数据如何使用。文章需要按时间排序、按编号查找,主题只需要读取一个选择。本课用主题偏好练习小型设置的保存,同时把“用户希望什么”和“界面当前显示什么”区分开。本文对应学习路线 D15;
2026-10-14 08:12:58
260
原创 D14_第二周数据链路验收
标签:Android、项目复盘、数据一致性、测试、面试表达本文对应 28 天课程 D14,回顾《第一行代码》第 3 版第 7、10、11、13 章涉及的存储、异步、网络与 Room。今天冻结新框架,用一个小需求检查第二周的代码是否能承受变化。下面是可执行的验收方案和推演,不虚构已经发生的个人排错经历。
2026-10-13 08:15:41
175
原创 D13_离线缓存与一致性
标签:Android、离线缓存、Room、Repository、数据一致性本文对应 28 天课程 D13,连接《第一行代码》第 3 版第 7、11、13 章。今天的目标是在断网时仍能浏览已经保存的首页文章元数据。缓存标题、作者和 URL 不等于缓存网页全文,文章详情中的外部页面仍可能需要网络;这一点应在界面和博客中讲清楚。
2026-10-13 08:15:04
79
原创 D12_Room本地收藏
本文独立建立bookmark换设备不会自动出现,这是需要明确的功能边界。Room 提供 SQLite 之上的实体、DAO 与数据库抽象,能在构建时检查许多 SQL 问题。核验时官方入门页已经采用 Room 3 的、KSP 和 SQLite Driver;不要把 Room 2 的导包与 Room 3 的依赖混用。已有工程应先记录所用代际,再使用同一套指南。Room 官方入门。
2026-10-13 08:11:01
161
原创 D11_搜索防抖与请求竞态
用先慢后快的两次搜索复现响应乱序,设计关键词、任务序号和重试入口,保护成功、失败与 finally 三条状态写入路径。标签:Android、搜索、协程取消、防抖、竞态本文对应 28 天课程 D11,承接《第一行代码》第 3 版第 11 章的网络调用知识。用户输入代表最新意图,而服务端完成顺序不一定服从输入顺序。本文围绕这个差异设计搜索功能,代码为局部教学片段,未在现有工程编译验证。
2026-10-13 08:07:42
145
原创 D10_分页刷新与失败重试
页面至少有三种加载:第一次进入时没有内容,刷新时可能已经有内容,追加时前面若干页仍然有效。把它们都表示成一个全屏转圈,会让刷新或追加错误把用户正在读的文章移走。状态首先应回答“已有内容是否仍可用”,然后才是“当前是否忙”。本例选择简单互斥策略:一个首页请求未结束时忽略新的刷新和追加。刷新成功替换当前列表并重置下一页;刷新失败保留原列表及原分页位置。追加成功合并结果并推进下一页;追加失败保留内容及失败页码。产品也可以选择刷新打断追加,但那需要额外处理取消和请求身份,本课不把两种策略混在一起。
2026-10-12 08:19:33
100
原创 D08_协程挂起调度与取消
把文章列表的数据返回延迟两秒,分别观察界面响应、任务寿命和旧结果覆盖。通过一个可取消的加载入口,区分 suspend、Dispatcher、Job 三个容易混淆的概念。标签:Android、Kotlin、协程、ViewModel、异步编程今天对应 28 天课程的 D08。阅读《第一行代码》第 3 版第 10 章异步处理内容时,可以先保留一个问题:等待数据的时候,界面为什么还能接收点击?书中的线程基础帮助理解执行环境,本文进一步用协程组织 DevCommunity 的屏幕任务。
2026-10-12 08:16:53
159
原创 D09_Retrofit接口与数据转换
接口能在浏览器打开”只能证明某次 HTTP 访问有响应。接入 App 前还要确认请求方法、Base URL、参数位置、页码起点和返回包裹结构。玩 Android 首页采用 GET,路径为,请求页码从零开始;需要 Manifest 的网络权限。下面只读取文章列表需要的字段,不把整份返回内容搬进界面。玩 Android 开放 APIRetrofit 根据注解构造接口调用并转换响应,OkHttp 承担底层 HTTP 工作。二者之间还存在转换器:服务器返回的 JSON 字节必须按选定的序列化规则变成对象。
2026-10-11 08:09:28
181
原创 D06_Navigation3返回栈
导航不只是点击后换一块界面。本文把 Home 和 Detail(id) 表达成返回栈状态,处理连续点击、无效 ID 与恢复后的数据缺失,并区分导航条目、Activity 任务栈和 Pager。标签:Navigation3、Compose导航、返回栈、状态恢复、Android。
2026-10-10 08:33:30
195
原创 D05_ViewModel与单向数据流
本阶段由 ViewModel 拥有屏幕上的完整文章集合和搜索词,界面只消费状态并报告操作。Repository 负责提供文章数据,它的接口描述调用者需要什么,而不暴露假数据如何创建。以后换成远端数据源时,界面不需要知道具体 HTTP 工具。数据库课才建立长期事实来源。统一状态也不是把所有变量机械装进一个大对象。本例只保存基础事实,筛选结果与数量按需计算;计算昂贵时再基于测量选择缓存方式。
2026-10-10 08:23:56
338
原创 D04_生命周期与状态恢复
页面看起来“刷新了”,背后可能是重组、Activity 重建或进程重启。本文通过实例标识、生命周期日志和搜索草稿实验,建立按数据寿命选择恢复机制的方法。标签:Activity、生命周期、状态恢复、rememberSaveable、Android。
2026-10-10 08:19:19
420
原创 D03_Compose列表与稳定身份
从一张卡片扩展到可滚动列表时,必须同时处理业务身份、组合身份与状态归属。本文用排序、插入和筛选实验说明稳定 key 的意义,以及它为什么不能替代正确的数据更新逻辑。标签:Jetpack Compose、LazyColumn、状态提升、列表、Android。
2026-10-10 08:08:13
396
原创 D02_Kotlin文章模型与数据清洗
文章模型不仅是字段集合,也要承载明确的数据约定。本文从六条受控输入出发,处理空作者、空标题、重复 ID 与搜索规则,用纯函数和输入输出检查把业务决定固定下来。标签:Kotlin、数据类、集合、空安全、Android学习。
2026-10-09 08:18:02
497
原创 D01_工程与第一张文章卡片
第一天不追求页面数量,而是打通工程构建、设备运行、点击事件和状态更新。用一张文章卡片解释 Activity、Composable 与可观察状态的分工,再通过故障实验确认代码为什么有效。标签:Android入门、Kotlin、Jetpack Compose、状态管理、第一行代码。
2026-10-09 08:17:11
437
原创 B20_PermissionX与库API设计
权限库可以减少重复注册、结果整理和回调分发,但不能替应用决定为什么需要某项权限,也不能绕过用户选择和系统限制。调用者仍负责把申请放在合适业务时机,解释用途,并处理拒绝后的替代路径。只返回一个 Boolean 常常不够。一次请求多项权限时,可能部分获得、部分拒绝;有些能力又随系统版本、授权范围和后续设置变化。API 应表达实际返回结果,而不是把复杂情况压成一个容易误解的“全部搞定”。
2026-10-09 08:16:34
524
原创 B19_SunnyWeather到阅读客户端
第一行代码》第 15 章把前面学过的网络、存储、界面和 Jetpack 组织成天气应用。读这一章最有价值的问题是:为什么数据要经过这些位置,刷新时谁负责什么,以及失败后界面如何表达。本篇结合工作区 SunnyWeather 示例的 Repository 与依赖配置,讨论如何把思想迁移到 DevCommunity。它是代码阅读与改造思路,不是已完成的天气接口联调记录,也不要求把整个旧工程复制成新项目。
2026-10-09 08:09:10
349
原创 B18_Context对象传递与调试边界
工具类缺少 Context,就传一个 Activity 进去;跳转需要数据,就把完整对象塞进 Intent。短期内可能都能工作,但当对象开始被长期保存,或数据越来越大时,便利写法会暴露生命周期和边界问题。本篇对应《第一行代码》第 14 章,重点回查全局 Context、Intent 传对象、日志和调试。目标不是禁止便利工具,而是理解它们依赖谁、保存什么,以及发生故障时怎样获得可靠证据。
2026-10-08 14:42:26
219
原创 B17_LifecycleLiveData与Flow
阅读《第一行代码》第 13 章时会遇到 Lifecycles 和 LiveData,进入现代 Compose 示例又常看到 StateFlow。容易产生的误解是:换成 Flow,就不需要考虑生命周期;或者旧项目使用 LiveData,说明它已经不能维护。本篇比较它们的职责,重点回查 13.3 的 Lifecycles 与 13.4 的 LiveData,再连接 D05 的状态组织。迁移依据应是业务和维护需要,不是简单按出现先后给工具排座次。
2026-10-08 14:39:19
186
原创 B16_Material主题与可访问交互
第一行代码》第 12 章介绍 Toolbar、抽屉、悬浮按钮、Snackbar、卡片、刷新和折叠标题栏。学习这一章时,如果只记住控件名字,很容易做出每个页面都有按钮、整体交互却不一致的应用。本篇从文章阅读客户端出发,理解这些组件背后的职责,再联系 Compose Material 3。它补充日课中的界面实践,不要求把书中的每一种控件都塞进 DevCommunity。
2026-10-08 14:33:18
262
原创 B15_HTTP解析与OkHttp拦截器
发布摘要:从原始 HTTP 响应拆解状态码、业务码与解析错误,再通过 OkHttp 拦截器理解请求链和响应体释放。标签:HTTP、OkHttp、JSON、Android 网络。接口返回了 200,页面为什么仍然没有文章?可能响应中的业务码表示失败,也可能 JSON 结构不符合客户端预期,还可能模型转换后被过滤掉。只在最外层显示“网络异常”,会把服务器状态、数据协议和客户端逻辑混成一个问题。本篇暂时绕开高层封装,看一次请求如何变成可展示的数据。
2026-10-08 14:29:10
196
原创 B14_Service启动绑定与线程
发布摘要:通过本地绑定服务实验,理解 Service 生命周期、启动与绑定叠加,以及为什么服务不会自动创建后台线程。标签:Service、Binder、生命周期、后台任务。面试中常见回答是“Service 用来执行后台耗时任务”。这句话漏掉了关键限制:Service 是组件,线程是执行上下文;服务的生命周期回调默认运行在应用主线程。在回调里直接做长时间计算,仍然可能卡住整个应用。本篇先通过一个简单绑定实验把生命周期看清,再讨论后台执行的选型。
2026-10-07 16:50:51
289
原创 B13_通知图片相机与影音
发布摘要:围绕一张文章附件,理解通知渠道与权限、系统照片选择器、拍照输出 URI,以及播放器的资源寿命。标签:通知、Photo Picker、相机、Media3。《第一行代码》第 9 章把通知、拍照、选图和播放音视频放在多媒体主题下,但实际开发时它们不是“一套权限加几个按钮”。通知由系统展示,图片可能来自另一个内容提供者,拍照可以委托相机应用,播放器则持有解码与输出资源。先回答由谁执行、内容在哪里、谁负责释放,API 才不会混成一团。本篇是第 9 章基础补强,适合放在 D19 后的选修时段。
2026-10-07 16:11:42
222
原创 B12_运行时权限与ActivityResult
发布摘要:以录音入口为例设计权限状态,理解声明、申请、拒绝、解释和重新检查,并把权限结果与实际功能分开。标签:Android 权限、Activity Result、生命周期。“点按钮申请权限,允许后开始录音”只覆盖了最顺利的一条路径。实际用户可能拒绝、退出对话框、去设置关闭权限,也可能在系统回收进程后返回应用。如果代码把第一次授权结果永久存成 true,下一次调用受保护 API 仍可能失败。本篇研究权限流程本身,录音只是帮助确定边界的场景。
2026-10-07 16:10:41
345
原创 B11_ContentProvider与内容访问
书中的自定义 Provider 帮助理解 URI 匹配、查询和增删改。不要把所有传入字符串原样拼进 SQL;值通过选择参数绑定,排序字段等无法作为值绑定的位置采用白名单。Provider 可能被并发访问,不能假定所有调用都在同一工作线程。对外暴露还需要设计 exported、读写权限及 URI 临时授权策略。把 exported 改成 true 并不意味着访问已安全,更不意味着可以忽略调用者权限。内部 Repository 没有跨应用访问需求时,也无需为“看起来完整”额外创建 Provider。
2026-10-07 14:55:10
280
原创 B10_文件SharedPreferences与SQLite
分别保存学习草稿、界面偏好和文章记录,比较三种传统持久化方式的数据形态、更新成本及失败处理,再连接 DataStore 与 Room。标签:Android、SQLite、SharedPreferences、文件存储、第一行代码本文对应《第一行代码》第 3 版第 7 章,也为 28 天课程 D12、D13、D15 补充存储基础。选择存储工具之前,先问数据如何读取、如何更新、需要什么约束。文中的练习片段未编译运行,不修改你的项目数据库;真实迁移需要先明确已有 schema 和数据保留要求。
2026-10-06 15:38:42
146
原创 B09_广播注册与系统限制
用应用内部的广播练习注册范围、导出属性和接收时机,再理解现代系统的隐式广播限制及广播与持久状态的区别。标签:Android、BroadcastReceiver、广播、生命周期、第一行代码本文对应《第一行代码》第 3 版第 6 章,补充 28 天项目课程中较少单独展开的四大组件基础。书中的广播示例适合理解消息分发,移到现代系统上还需要核对注册方式、目标版本和来源限制。下文示例为教学练习,未在当前工程和设备组合上编译运行。
2026-10-06 15:35:30
322
原创 B08_Fragment事务通信与双生命周期
用列表进入详情再返回的过程,理解 Fragment 事务、返回栈、View 生命周期及结果通信,避免对旧 View 更新和重复添加页面。标签:Android、Fragment、生命周期、ViewBinding、第一行代码本文对应《第一行代码》第 3 版第 5 章,以及 28 天课程 D17 的传统界面练习。Fragment 是受宿主管理的界面组件,但 Fragment 对象存在和它的 View 存在不是同一件事。
2026-10-06 15:29:16
232
原创 B07_RecyclerView复用与DiffUtil
标签:Android、RecyclerView、DiffUtil、ListAdapter、第一行代码本文对应《第一行代码》第 3 版第 4.6 节,并补强 28 天课程 D17。RecyclerView 不只是“能滚动的数组”:数据、条目 View、位置以及业务 ID 是不同概念。下面围绕同一份文章数据写传统列表,示例未在你的工程编译,布局与依赖需配套补齐。
2026-10-06 15:21:46
335
原创 B06_XML控件布局与ViewBinding
从一张传统文章卡片出发,理解尺寸与布局参数、控件更新、资源复用和 ViewBinding,学会定位长标题及横屏布局问题。标签:Android、XML、ViewBinding、布局、第一行代码这一篇对应《第一行代码》第 3 版第 4 章,也是 28 天课程 D17 的基础补强。主项目使用 Compose,并不意味着存量 View 代码可以跳过。维护传统页面时,首先要看懂 XML 如何生成对象、父容器如何安排子控件,以及数据变化后谁来更新显示。
2026-10-03 16:00:37
530
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅