【鸿蒙原生应用开发实战】第五篇:项目总结——ArkTS 最佳实践与从 MVP 到生产的升级之路

【鸿蒙原生应用开发实战】第五篇:项目总结------ArkTS 最佳实践与从 MVP 到生产的升级之路

历时四篇,我们完整实现了"萌宠日记"鸿蒙原生应用的全部五个页面。这一篇作为系列收官,不做新功能开发,而是回头看------总结整个项目中的架构决策、踩过的坑、ArkTS 严格模式下的编码规范,以及从 MVP 到生产环境的升级路线图。


一、项目架构回顾

1.1 页面总览

复制代码
pages/
├── Index.ets          ← 首页(宠物卡片 + 快捷入口 + 动态信息流)
├── AddPetPage.ets     ← 添加宠物(表单录入)
├── PetDetailPage.ets  ← 宠物详情(三 Tab 切换)
├── AlbumPage.ets      ← 萌宠相册(网格/列表 + 筛选)
└── ReminderPage.ets   ← 提醒管理(分类统计 + 待办 + 开关)

1.2 各页面代码量统计

页面 代码行数 @Builder 方法数 @State 变量数 核心复杂度
Index.ets 381 4 3 ForEach + Scroll 嵌套
AddPetPage.ets 323 7 9 多类型表单状态管理
PetDetailPage.ets 428 8 9 Tab 切换 + 柱状图
AlbumPage.ets 234 6 3 网格/列表双模式
ReminderPage.ets 339 7 2 开关控制 + 分类统计

合计 1705 行 ArkTS 代码,覆盖了鸿蒙原生开发的绝大多数核心场景。

1.3 路由拓扑

复制代码
Index (首页)
├── pushUrl → AddPetPage (添加宠物)
├── pushUrl → PetDetailPage (宠物详情)
├── pushUrl → AlbumPage (相册)
└── pushUrl → ReminderPage (提醒)

PetDetailPage
└── pushUrl → ReminderPage (提醒设置)

所有页面都是单向跳转,没有循环依赖。router.back() 统一返回上一页。


二、核心设计模式总结

2.1 @Builder 组件化拆分

这是本项目中最核心的架构模式。每个页面将 UI 拆分为多个 @Builder 方法,然后在 build() 中按顺序组装。

为什么不用自定义 @Component?

方案 适用场景 本项目的选择
@Builder 方法 页面内拆分,逻辑简单 ✅ 首页4个、详情页8个
自定义 @Component 跨页面复用,逻辑复杂 ❌ 暂不需要
全局 @Builder 函数 全局通用 UI ❌ 暂不需要

决策原则 :如果一段 UI 只在一个页面内使用 ,就用 @Builder 方法拆分。如果跨页面复用 ,再提取为 @Component

2.2 状态管理策略

本项目的状态都在页面级别 ,没有跨页面共享状态。每个页面的 @State 数量控制在 10 个以内:

typescript 复制代码
// 典型模式
struct Index {
  @State pets: Pet[] = [];
  @State moments: Moment[] = [];
  @State selectedPetIndex: number = 0;
}

如果需要跨页面共享状态(比如添加宠物后首页需要刷新),后续可以引入:

  • @Provide / @Consume:父子组件跨层级传值
  • AppStorage / LocalStorage:应用级/页面级状态存储
  • Emitter:事件总线模式

但目前 MVP 阶段,页面独立管理状态是最简单的方案。

2.3 数据驱动 UI

整个项目遵循"状态变化 → UI 自动更新"的响应式模式:

复制代码
用户交互 → @State 变量变化 → UI 自动重新渲染
     ↑                              |
     └────── onChange/onClick ──────┘

不需要手动操作 DOM,不需要调用 setState(),不需要标记脏更新。这是 ArkTS 声明式框架的核心优势。


三、ArkTS 严格模式踩坑全记录

3.1 arkts-no-untyped-obj-literals

错误信息

复制代码
Object literals cannot be used without a type annotation.

问题代码

typescript 复制代码
// ❌ 错误
const params = router.getParams();

解决方案

typescript 复制代码
// ✅ 正确
const params: Record<string, Object> = router.getParams() as Record<string, Object>;

根因 :ArkTS 严格模式禁止使用无类型标注的对象字面量。从 router.getParams() 返回的 Object 必须显式转换。

3.2 arkts-no-noninferrable-arr-literals

错误信息

复制代码
Type of array literal cannot be inferred.

问题代码

typescript 复制代码
// ❌ 错误
tabs = ['健康档案', '体重记录', '疫苗记录'];

解决方案

typescript 复制代码
// ✅ 正确
tabs: string[] = ['健康档案', '体重记录', '疫苗记录'];

根因:数组字面量必须显式声明类型。这是 ArkTS 为了运行时性能做的类型约束。

3.3 app_name 重复定义

错误信息

复制代码
Resource 'app_name' conflict: duplicate definition in multiple modules.

解决方案 :只在 AppScope/resources/base/element/string.json 中定义,不要在 entry 模块中再定义一次。

3.4 router 导入路径

错误信息

复制代码
Cannot find module '@kit.AbilityKit' or its corresponding type declarations.

解决方案

typescript 复制代码
// ✅ 正确(API 23)
import router from '@ohos.router';

// ❌ 错误(API 23 不导出 router)
import router from '@kit.AbilityKit';

根因 :API 23 的 @kit.AbilityKit 不导出 router。这是 SDK 版本的差异。

3.5 ForEach key 冲突

潜在 Bug :当同一个页面有多个 ForEach 且数据源的 id 范围重叠时,key 可能冲突。

解决方案

typescript 复制代码
// 为不同的 ForEach 添加区分后缀
(r: Reminder) => r.id.toString() + 'today'
(reminder: Reminder) => reminder.id.toString()

四、性能优化建议

4.1 列表渲染优化

当前项目中,所有数据都是一次性加载到内存中。当数据量增大时(比如 1000+ 条动态),需要考虑:

优化手段 说明 实施难度
懒加载 分页加载,初始只加载前20条
List 组件 替代 Scroll + ForEach,支持回收复用
LazyForEach 数据懒加载 + 按需渲染
数据不可变 整体替换数组而非增删元素

4.2 @Builder 的实例化开销

每次调用 @Builder 方法都会创建新的组件实例。对于频繁切换的 UI(如 Tab 切换),应该用 if-else 避免同时渲染所有内容:

typescript 复制代码
// ✅ 只渲染当前 Tab,切换时销毁旧 Tab
if (this.currentTab === 0) {
  this.buildHealthTab()
} else if (this.currentTab === 1) {
  this.buildWeightTab()
} else {
  this.buildVaccineTab()
}

而不是:

typescript 复制代码
// ❌ 所有 Tab 同时渲染(浪费性能)
Column() { this.buildHealthTab() }.visibility(...)
Column() { this.buildWeightTab() }.visibility(...)
Column() { this.buildVaccineTab() }.visibility(...)

4.3 避免不必要的状态更新

@State 变量的每次赋值都会触发 UI 重新渲染。以下写法会造成不必要的性能浪费

typescript 复制代码
// ❌ 不必要的中间状态
this.isLoading = true;   // 触发一次渲染
this.data = fetchData(); // 触发第二次渲染
this.isLoading = false;  // 触发第三次渲染

// ✅ 合并状态更新
this.data = fetchData();
this.isLoading = false;

4.4 图片资源优化

虽然本项目使用 Emoji 替代了图片,但如果后续接入真实图片,需要注意:

  • 图片使用 Image 组件时设置 objectFit(ImageFit.Cover)
  • 列表中的图片使用 layoutWeight 约束尺寸,避免大图溢出
  • 图片文件放在 resources/base/media/ 目录,使用 $media 引用

五、从 MVP 到生产环境的升级路线图

5.1 第一阶段:功能完善(当前 MVP)

  • ✅ 5 个页面完整 UI
  • ✅ 页面路由跳转
  • ✅ 宠物数据展示
  • ✅ 表单录入界面
  • ✅ 相册筛选 + 双模式
  • ✅ 提醒管理 + 开关控制

5.2 第二阶段:数据持久化

当前所有数据都是硬编码的,重启应用数据就会丢失。生产环境需要:

需求 技术方案 优先级
本地存储 @ohos.data.preferences (轻量 KV) ⭐⭐⭐⭐⭐
结构化数据 @ohos.data.relationalStore (RDB) ⭐⭐⭐⭐
文件存储 @ohos.file.fs (图片文件) ⭐⭐⭐
云同步 接入华为云服务 ⭐⭐

推荐路径 :先用 preferences 存宠物基本信息,用 relationalStore 存动态和提醒数据。

5.3 第三阶段:真实功能对接

功能 待接入 API 说明
拍照上传 @ohos.multimedia.camera 调用系统相机
相册选择 @ohos.file.picker 选择系统相册图片
推送通知 @ohos.notification 疫苗/驱虫到期提醒
日历同步 @ohos.calendar 提醒同步到系统日历
分享 @ohos.share 分享萌宠动态

5.4 第四阶段:体验优化

  • 骨架屏:数据加载中的占位 UI
  • 下拉刷新Swiper + Refresh 组件
  • 主题切换:暗色模式支持
  • 动画过渡:页面转场动画、列表项入场动画
  • 无障碍:内容描述、大字体适配

六、开发工具与调试经验

6.1 DevEco Studio 实用技巧

  1. 预览器 Previewer:实时预览 UI 变化,不用每次跑真机
  2. HiLog 日志:替代 console.log,支持分级过滤
  3. Profiler 性能工具:检测 UI 渲染帧率
  4. 代码格式化Ctrl+Alt+L 一键格式化

6.2 命令行构建

bash 复制代码
node "D:\DevEco Studio\tools\node\node.exe" \
  "D:\DevEco Studio\tools\hvigor\bin\hvigorw.js" \
  --mode module \
  -p module=entry@default \
  -p product=default \
  -p requiredDeviceType=phone \
  assembleHap \
  --analyze=normal \
  --parallel \
  --incremental \
  --daemon

构建产物是 .hap 文件,位于 entry/build/default/outputs/ 目录。

6.3 调试建议

  • 真机调试优先:模拟器在某些 API 行为上和真机有差异
  • 分步构建 :先 Build → Analyze 检查代码问题,再 Run
  • 关注编译警告:很多运行期 Bug 在编译期就有警告提示

七、写给初学者的话

7.1 入坑鸿蒙开发需要什么基础?

前置技能 重要程度 说明
TypeScript 基础 ⭐⭐⭐⭐⭐ ArkTS 是 TypeScript 的子集
移动端布局思维 ⭐⭐⭐⭐ Flexbox 布局概念
响应式编程理解 ⭐⭐⭐ @State 驱动 UI 更新
Java/Android 经验 ⭐⭐ 有最好,没有也没关系

7.2 学习路线建议

  1. 先看官方 Codelab:华为官方提供 Hello World 级别的案例
  2. 手写一个小项目:就像我们这个"萌宠日记"一样,从简单到复杂
  3. 理解严格模式:ArkTS 的 strict 模式是最大的"坑",也是最大的"保护"
  4. 多看 build 日志:70% 的错误都在编译期暴露,认真阅读错误信息

7.3 心态建议

鸿蒙开发目前还在快速发展期,API 在不同版本之间可能有差异。这既是挑战也是机会:

  • 挑战:网上资料不如 iOS/Android 丰富,遇到问题可能需要自己啃官方文档
  • 机会:竞争小,现在入局鸿蒙开发的人少,早起的鸟儿有虫吃

八、项目完整代码汇总

8.1 配置文件

文件 路径 作用
app.json5 AppScope/app.json5 应用全局配置
module.json5 entry/src/main/module.json5 模块配置
build-profile.json5 项目根目录 构建配置
main_pages.json resources/base/profile/ 页面路由注册
color.json resources/base/element/ 颜色资源
float.json resources/base/element/ 字号/尺寸
string.json AppScope/resources/base/element/ 应用名

8.2 页面文件

文件 路径 行数
Index.ets entry/src/main/ets/pages/ 381
AddPetPage.ets entry/src/main/ets/pages/ 323
PetDetailPage.ets entry/src/main/ets/pages/ 428
AlbumPage.ets entry/src/main/ets/pages/ 234
ReminderPage.ets entry/src/main/ets/pages/ 339

8.3 Ability 入口

文件 路径 作用
EntryAbility.ets entry/src/main/ets/entryability/ 应用入口,加载首页

九、写在最后

五篇博文,从项目初始化到全部页面实现,我们完整走了一遍鸿蒙原生应用(Stage 模型 + ArkTS + API 23)的开发流程。

复盘整个"萌宠日记"项目,我认为最值得记住的几点:

  1. ArkTS 的严格模式是把双刃剑------写的时候觉得很繁琐,但编译期捕获了大量潜在 Bug
  2. @Builder + @State 是 ArkTS 开发的基石------理解这两个概念,就能看懂 90% 的鸿蒙页面代码
  3. 从 MVP 开始,逐步迭代------不要一开始就想做完美的架构,先跑起来再说

如果你跟着这个系列一起做了一个自己的鸿蒙应用,那我的目的就达到了。有任何问题欢迎评论区交流!


开发环境 : DevEco Studio + HarmonyOS API 23 (SDK 6.1)

框架 : Stage 模型 + ArkTS

系列汇总:

相关推荐
木咺吟2 小时前
鸿蒙原生应用实战(五):路由导航与工程优化 — 从开发到上线的完整流程
华为·harmonyos
风满城332 小时前
【鸿蒙原生应用开发实战】第三篇:表单录入与详情展示——AddPetPage + PetDetailPage 完整实现
华为·harmonyos
风满城332 小时前
【鸿蒙原生应用开发实战】第一篇:从零搭建“萌宠日记“项目——Stage模型与工程架构解析
华为·harmonyos
charlee442 小时前
Unity项目适配华为鸿蒙系统的原生库加载问题排查与解决
华为·unity3d·鸿蒙·cmake·c/c++·relro
狼哥16863 小时前
《新闻资讯》二、公共能力层模块实现指南
ui·华为·harmonyos
Ww.xh3 小时前
启用Hypervisor解决模拟器问题
华为·harmonyos
金启攻4 小时前
【鸿蒙原生应用实战】第二篇:装备库页面——分类筛选与数据驱动UI
harmonyos
木咺吟6 小时前
鸿蒙原生应用实战(四):愿望单与个人统计 — 数据聚合与可视化
华为·harmonyos
木咺吟6 小时前
鸿蒙原生应用实战(二):游戏库列表与筛选排序 — 卡片式UI设计
harmonyos