B19_SunnyWeather到阅读客户端

Android 基础补强 B19|从 SunnyWeather 读懂 MVVM,再迁移到自己的阅读客户端

《第一行代码》第 15 章把前面学过的网络、存储、界面和 Jetpack 组织成天气应用。读这一章最有价值的问题是:为什么数据要经过这些位置,刷新时谁负责什么,以及失败后界面如何表达。

本篇结合工作区 SunnyWeather 示例的 Repository 与依赖配置,讨论如何把思想迁移到 DevCommunity。它是代码阅读与改造思路,不是已完成的天气接口联调记录,也不要求把整个旧工程复制成新项目。

先追一条请求,不先背目录

从城市搜索出发:用户输入关键词,界面或 ViewModel 发起搜索,Repository 调用网络层,返回城市数据或错误,再由界面展示。天气刷新则需要组织实时天气与未来天气,形成页面所需的组合结果。

text 复制代码
用户意图 → 屏幕状态持有者 → Repository → 网络或本地数据
                                    ↓
界面展示 ← 可观察的状态 ← 成功结果、缓存或错误规则

这个图不是规定每次都必须经过相同数量的类。每一层应该承担可说明的职责:网络层描述协议,Repository 决定数据来源与组合,状态持有者管理屏幕呈现,界面负责展示与事件。当前官方架构建议同样强调清楚的 UI 与数据层边界。架构建议

从现有代码观察两个设计选择

工作区示例的 Repository 使用 LiveData 构建结果,并通过统一的辅助函数包装异常;刷新天气时在协程作用域内并发获取两类天气,再组合返回。这里可以学习"把来源组合限制在一个位置"和"给上层一致的结果入口"。

阅读时也要保留时代背景。当前文件仍有较旧的目标 SDK 和部分依赖配置,不能直接当作新工程的推荐版本;LiveData 也不等于不能继续使用,是否调整取决于界面和协程组织方式。

更值得检查的是异常语义:宽泛捕获 Exception 时,取消异常是否被当成普通失败处理。迁移代码时应保留协程取消传播,让已经结束的业务任务不会继续像普通结果一样提交状态。Android 协程最佳实践

并发请求先规定失败关系

下面是独立教学模型,演示两类结果缺一不可时的组合。需要 kotlinx.coroutines 的 async 与 coroutineScope;Service 的实现必须保证调用方式适合所在上下文。代码没有连接真实天气服务,也未随稿编译。

kotlin 复制代码
data class CurrentWeather(val temperature: Double)
data class Forecast(val description: String)
data class WeatherPage(val current: CurrentWeather, val forecast: Forecast)

interface WeatherService {
    suspend fun current(placeId: String): CurrentWeather
    suspend fun forecast(placeId: String): Forecast
}

class WeatherRepository(private val service: WeatherService) {
    suspend fun refresh(placeId: String): WeatherPage = coroutineScope {
        val current = async { service.current(placeId) }
        val forecast = async { service.forecast(placeId) }
        WeatherPage(current.await(), forecast.await())
    }
}

这个策略强调两个任务属于同一次操作。如果业务允许部分成功,应该另外设计部分内容与错误提示,而不是只把 coroutineScope 换个名字就认为完成容错。哪些结果可以独立展示,是业务问题;作用域与异常机制只是实现选择。

对阅读客户端,首页文章和本地收藏可能来自不同来源,但未必需要采用天气页的"缺一不可"规则。网络失败时仍可显示缓存,收藏读取失败也需要单独判断影响范围。迁移的是分析方法,不是照搬成功条件。

把天气项目映射到阅读项目

天气应用场景 阅读客户端对应问题 需要重新设计的部分
搜索城市 搜索文章 防抖、分页、旧结果身份
记住选中城市 保存本地收藏或阅读状态 多条结构化记录与查询
刷新天气 刷新首页文章 保留旧内容、缓存顺序
显示组合结果 文章与收藏状态合并 多页面事实来源一致
发布安装包 交付学习项目 实际版本、测试和说明

如果每个页面都直接知道真实接口和数据库,替换数据源会牵动很多地方。先定义 UI 真正需要的 Repository 能力,再使用 Fake 验证状态,能更早发现职责问题。接口不必一开始抽象到支持所有产品,满足当前稳定需求即可。

从旧示例迁移的可控顺序

第一步记录旧工程当前能否构建、能否访问服务;第二步只追踪一个查询;第三步在新工程用 Fake 表达相同能力;第四步接入真实数据;第五步再考虑状态工具和持久化变化。每次只改清楚的一层,保留前后的行为对照。

如果接口不可用,不应把整个项目判断成毫无价值。仍能阅读分层、状态和调用关系,但要准确区分"理解了代码"与"完成了真实联调"。同理,Gradle 同步成功不证明 API 密钥、响应字段和业务状态仍然有效。

故障实验与预期

让实时天气请求成功、预测请求失败,观察当前全有或全无策略怎样表现。再明确一个部分成功方案,写出界面应该保留什么、重试哪个来源,然后实现与验证。阅读项目可用首页刷新失败但收藏仍可查看作为类似思考。

第二个实验让旧搜索晚于新搜索返回。检查 Repository 只负责获取数据,还是还偷偷修改了全局 UI;若后者存在,会更难约束请求身份。预期把结果提交规则放在可控制的业务边界,并给出取消与失效条件。

三道原创面试自测

MVVM 是否就是三个目录? 不是,关键是职责、依赖和数据流。追问"怎么证明",从一次操作追踪到数据和界面,说明每一步能否独立替换和验证。

两个 async 是否总能加快请求? 只对确实可并发且受资源条件支持的工作有意义,还要考虑失败关联。追问"一个失败呢",按业务决定全部失败或部分展示,不能忽略取消语义。

旧项目最值得保留什么? 清楚的问题拆分和可解释的调用关系。追问"哪些要重新核验",依赖、平台行为、接口协议与异常处理都需要按当前环境验证。

完成本篇后,应能从天气项目提炼一种设计方法,再解释为什么阅读客户端作出不同选择,而不是只换应用名称和图标。

相关推荐
美狐美颜sdk2 小时前
直播APP源码可以直接接入视频美颜sdk吗?技术方案详解
android·人工智能·音视频·美颜sdk·直播美颜sdk
用户69371750013845 小时前
2026,程序员的时代拐点到了
android·前端·后端
浪潮IT馆6 小时前
Android Studio 非最新版本下载安装教程
android·ide·android studio
xiaozongt19898 小时前
MasterGo + Claude Code 生成 Android 布局:完整实践指南
android
Anhty9 小时前
2026最新免费手机音频处理工具 !!
android·功能测试·ios·智能手机·音视频
2501_9159090611 小时前
iOS应用从开发到上架App Store的完整发布流程与步骤指南
android·ios·小程序·https·uni-app·webview
狗凯之家源码网11 小时前
AI 步数修改提交系统源码应用场景与落地指南
android·数据库·人工智能·运动步数
ZHOUPUYU12 小时前
PHP 9.0 前瞻:下一代 PHP 会带来哪些新功能?
android·开发语言·php
JMchen12 小时前
性能优化——让Native代码飞起来
android·c++·性能优化