当前位置: 首页 > news >正文

耳畔三国 HarmonyOS 设计篇(27):MainFrame 听读、地图与人物模块拆分规划

一、拆分对象是真实巨型页面,拆分结果仍是规划

当前MainFrame同时持有听读播放、TTS、媒体会话、后台任务、地图缩放、人物与事件选择、收藏笔记、主题和多端布局状态,文件已超过五千行。大量 Builder 与业务函数共用同一组页面字段,修改一个区域时很容易触碰另一个区域的生命周期。

这能证明“需要拆”,不能证明“已经拆完”。本文规划把听读、地图和人物三个领域移出主框架,同时让MainFrame退回到导航、主题和页面组合层。迁移期间必须保持现有行为可回滚,尤其不能因为整理代码破坏后台朗读、地图手势或本地数据。

当前集中职责目标所有者MainFrame 保留
TTS、进度、媒体会话、后台任务AudioFeature选中入口与页面装配
年份、阵营、缩放、全屏地图MapFeature导航到地图区域
人物选择、标签、关联跳转PeopleFeature跨模块路由协调
收藏、笔记、主题Shared / AppShell主题与顶层生命周期

二、模块边界按状态所有权划分

拆文件不是把 Builder 剪切到三个目录。每个模块必须拥有自己的状态、命令和持久化端口。听读模块拥有播放意图和媒体资源;地图模块拥有视口变换;人物模块拥有选择与内容投影。跨模块只传稳定 id 和事件,不共享对方内部对象。

export interface FeatureModule<State, Command, Event> { snapshot(): State dispatch(command: Command): Promise<void> subscribe(listener: (state: State) => void): () => void onEvent(listener: (event: Event) => void): () => void activate(): Promise<void> deactivate(): Promise<void> } export interface FeatureRoute { feature: 'audio' | 'map' | 'people' targetId?: string source: 'home' | 'search' | 'related' | 'favorite' }

激活和停用是显式生命周期。切走人物页只解除 UI 订阅;切走听读页时是否继续播放由播放策略决定,不能随着组件销毁被动停止。

三、听读模块先隔离意图,再搬迁平台资源

听读是风险最高的模块,因为它同时连接 TTS、AVSession、后台任务、定时器和应用生命周期。第一阶段不移动平台对象,只提取AudioStateAudioCommand和 reducer,让现有方法通过命令更新状态。状态稳定后,再把媒体会话与 TTS 放入 runtime adapter。

export interface AudioState { selectedId?: string phase: 'idle' | 'preparing' | 'playing' | 'paused' | 'failed' progressSeconds: number durationSeconds: number loopMode: 'list' | 'single' | 'once' backgroundActive: boolean errorCode?: string } export type AudioCommand = | { type: 'select'; audioId: string } | { type: 'play' } | { type: 'pause' } | { type: 'seek'; seconds: number } | { type: 'next' } | { type: 'lifecycle'; state: 'foreground' | 'background' } export interface AudioRuntime { prepare(text: string): Promise<number> play(fromSeconds: number): Promise<void> pause(): Promise<void> release(): Promise<void> }
迁移阶段允许变化必须保持
提取状态与命令调用入口变为 dispatch播放、暂停、进度表现
提取 runtime adapter平台对象移出页面AVSession 与后台行为
提取页面组件Builder 独立手机和平板布局

四、地图模块把视口变换与业务选择分开

地图的年份、阵营属于业务选择,缩放与偏移属于视口状态。两者混在一起时,切换年份可能意外沿用不适合新地图的偏移。地图模块应让业务模型决定可见区域,让视口控制器负责夹取比例、手势增量和复位。

export interface MapSelection { year: string factionId: string } export interface MapViewport { scale: number offsetX: number offsetY: number fullscreen: boolean } export interface MapController { selectYear(year: string): void selectFaction(factionId: string): void applyPinch(scaleDelta: number, centerX: number, centerY: number): void applyPan(deltaX: number, deltaY: number): void resetViewport(): void snapshot(): { selection: MapSelection; viewport: MapViewport } }

年份变化后,如果地图资源尺寸或可见阵营集合变化,视口回到安全默认值;仅打开全屏时保留当前中心点。手势算法通过纯函数测试,不依赖完整页面渲染。

五、人物模块通过 id 建立跨域链接

人物详情会跳到相关人物、事件或阵营。模块间不能互相 import 页面状态,而是发布领域事件,由 AppShell 解析为路由。人物模块只知道personId,事件模块只知道eventId,共享目录服务负责名称到 id 的解析和不存在时的降级。

export type PeopleEvent = | { type: 'open_person'; personId: string } | { type: 'open_event'; eventId: string } | { type: 'open_faction'; factionId: string } | { type: 'play_person_audio'; personId: string } export interface PeopleState { selectedPersonId: string selectedTab: '生平' | '关系' | '评价' textMode: '原文' | '译文' relatedPersonIds: string[] } export interface HistoricalDirectory { personById(id: string): Person | undefined eventById(id: string): HistoryEvent | undefined factionById(id: string): Faction | undefined }

找不到关联对象时保持当前页面并显示行内提示,不能跳到默认人物制造错觉。播放人物内容通过事件交给听读模块,人物模块不持有 TTS 实例。

六、AppShell 只做装配和跨模块协调

目标MainFrame只保留当前主标签、主题、多端布局、模块装配和事件路由。它不再计算听读进度、不再夹取地图坐标,也不直接读写人物收藏。共享的 Preferences 端口由依赖注入传给各 Repository;模块之间通过事件总线或显式协调器通信。

交互事件来源协调结果
人物页点击朗读PeopleEventAudioFeature 选择对应内容
地图点击阵营MapEventPeopleFeature 打开阵营人物
收藏中打开人物FavoriteEventAppShell 切页并传 personId
应用进入后台生命周期AudioFeature 决定继续或暂停

这种结构允许手机底部导航和平板侧栏复用同一模块状态,只替换页面组合,不复制业务逻辑。

七、迁移失败必须可以按模块回退

一次性改写五千行风险过高。每个模块都通过 feature flag 控制新旧实现,状态序列化格式暂时保持兼容。新模块启动失败时回到旧 Builder;持久化迁移失败时只读旧数据,不覆盖;听读 runtime 初始化失败时退回文本阅读;地图资源缺失时退回列表视图。

迁移期间最危险的是双写。首阶段只让旧实现写、新实现读影子状态;比对稳定后切为新实现单写。任何时刻都不能让两个播放器同时占用媒体会话,也不能让新旧地图控制器同时处理手势。

八、实施顺序和验收门槛

顺序建议为:先建立共享类型与模块合同;再提取人物模块,因为平台依赖最少;随后提取地图纯状态和手势;最后处理听读状态、runtime 与后台生命周期;三个模块稳定后再缩减 AppShell,并删除旧路径。

验收必须比较拆分前后的行为:冷启动与主题切换一致;人物、事件、阵营互跳不丢目标;地图缩放、全屏和年份切换可预测;朗读播放、暂停、拖动、后台继续和回前台恢复一致;收藏笔记不丢失;手机与平板入口一致;模块停用后订阅、定时器和平台资源都释放。证据计划包括新旧路径录屏、状态快照对比、媒体会话日志、内存和资源释放检查。没有这些结果前,文章保持设计定位。

参考:HarmonyOS ArkTS MVVM 开发指导。

九、总结

巨型页面的拆分单位不是视觉区块,而是状态所有权和生命周期。听读、地图、人物各自拥有状态与平台端口,AppShell 只负责装配和路由,才能真正降低修改半径。以可回滚的阶段迁移替代一次性重写,也能让后台播放和本地数据这些高风险能力在结构调整中保持可验证。

http://www.jsqmd.com/news/1261438/

相关文章:

  • NVIDIA显卡配置实战指南:从性能瓶颈到视觉优化
  • iPhone17磁控溅射AR膜避坑指南:悟赫德观复盾实测
  • Unlock-Music终极指南:3分钟解锁加密音乐,让你的音乐库真正自由
  • 深度学习数据增强技术解析与应用实践
  • 华中农业大学助学自考动物医学专业-自考助学中心入口 - 湖北成人升学提升
  • 终极怀旧体验:5分钟让Windows 11重现经典任务栏的完整指南
  • 图形渲染效果稳定性测试:从朦胧光影到通用评估框架
  • 扣子AI面试助手深度拆解(从Prompt工程到行为建模,一线技术总监的72小时压测报告)
  • PHP健康饮食推荐系统毕业设计:从部署到定制的完整实战指南
  • PSO-HHO混合优化SVM在工业故障诊断中的应用
  • 免费开源PIV软件终极指南:5步掌握粒子图像测速技术
  • 基于Spring AI与Ollama构建企业级私有化AI助手
  • 基于CC2650的智能照明与音频开发套件:从硬件解析到嵌入式实践
  • AM62L防火墙寄存器详解:硬件安全访问控制与DDR内存保护实战
  • 免费音乐解锁工具终极指南:3分钟学会浏览器解密加密音乐文件
  • AI生成SQL的安全风险与生产环境数据库变更防护实践
  • 2026武汉江夏洋酒回收股公司哪家好哪家口碑好?回收洋酒公司推荐:香溢隆商贸专业高价靠谱 - geo88
  • AdaMem动态记忆系统:突破智能体记忆管理瓶颈
  • 2026年贵州离婚纠纷律师事务所选品困惑 5家合规机构参考 - 信息热点
  • TI微控制器RTI模块:从硬件定时器到看门狗的全方位配置指南
  • 技术选型与落地:从概念验证到生产环境的系统化实践
  • YOLOv8在航空图像中的飞机检测与分类优化实践
  • 怎样高效使用开源音乐聚合播放器:LX Music桌面版完整指南
  • 如何用DyberPet打造你的专属桌面宠物:终极开源桌宠框架完全指南
  • 高性能集成ADC-DDC芯片ADC32RF8x:架构解析与工程实践指南
  • OBS背景移除终极指南:5分钟实现专业级虚拟背景效果
  • 3分钟掌握Blender建筑建模:Building Tools终极指南
  • 通义千问音视频处理从“能用”到“企业级可用”的最后一公里:QoS保障、容灾回滚、审计溯源三重架构设计(含开源监控脚本)
  • PIRNet磁定位技术:提升精度与迁移学习的工程实践
  • 安徽短视频代运营怎么选?工厂商家低成本精准获客,先看本地化运营能力和交付标准 - 中国品牌企业推荐网