HarmonyOS知识图谱和回顾

HarmonyOS知识图谱和回顾

HarmonyOS 的知识主线是 ArkTS 语言、ArkUI 声明式界面、Stage 应用模型、系统能力、数据架构和生产发布能力的组合。

复习时不要只记组件 API,要能解释状态如何驱动 UI、Ability 生命周期如何影响页面恢复、数据如何持久化和迁移、系统能力如何做权限和异常封装,以及发布前如何完成性能、安全、隐私和多端验证。
HarmonyOS 总知识图谱
语言与工程
ArkTS
类型系统
模块化
DTO/Entity/ViewModel
工程规范
界面体系
ArkUI
组件
状态管理
列表网格
Navigation
多端适配
应用模型
Stage
UIAbility
WindowStage
Want
生命周期
页面路由
数据与并发
Preferences
relationalStore
网络封装
taskpool
worker
错误处理
系统能力
权限
文件
通知
设备能力
统一封装
异常恢复
生产交付
测试
性能
安全
隐私
签名
发布
灰度回滚

01 知识体系图与环境基础

01 知识体系图与环境基础
一、知识体系总览
二、详细知识点

  1. DevEco Studio 2. SDK 与 API 版本 3. Stage 模型工程结构 4. HAP 与模块 5. 资源管理 三、本章 demo
    Demo 1:最小应用配置
    Demo 2:入口 Ability
    Demo 3:当前机器可运行验证
    四、面试题与详细答案
  2. HarmonyOS Stage 模型工程最关键的文件有哪些? 2. compileSdkVersion 和 compatibleSdkVersion 有什么区别? 3. 学习者为什么要先跑通空项目? 4. 可上线工程和基础 demo 的差别是什么? 五、五倍扩展知识点矩阵
  3. 学习路线完整知识体系 2. 环境安装深度清单 3. 工程目录生产实践解读 4. 版本和兼容策略 5. 运行链路拆解 六、环境与工程 demo 扩展任务
    七、常见故障与定位
    八、扩展面试题
  4. AppScope 和 entry 的边界是什么? 6. 为什么大型鸿蒙项目不能只有一个 entry 模块? 7. 如何设计鸿蒙学习路线最稳? 8. 导入别人项目失败时你会怎么排查? 9. 为什么工程化开发要记录环境版本? 10. HAP 和应用安装包是什么关系? 九、知识点详解库
  5. 环境不是一次性工作 2. SDK 版本要和项目生命周期绑定 3. 模拟器验证不能替代真机验证 4. Debug 签名和 Release 签名的风险不同 5. 入口模块不能承担所有职责 6. 配置文件是运行契约 7. 资源命名要可维护 8. 应用能力要从第一天开始记录 9. 工程入口要便于新人接手 10. 版本号不是随便写的 十、环境实战场景库
    十一、扩展面试题库
  6. 为什么 README 是工程质量的一部分? 12. 环境问题和代码问题如何区分? 13. 为什么资源要集中管理? 14. 多设备支持为什么要谨慎声明? 15. 如何规划鸿蒙项目的第一周学习? 十二、完整知识域补全
    十三、鸿蒙工程能力全景图
    十四、项目目录应如何演进

一、知识体系总览

鸿蒙开发完整知识体系,不是只会写页面,而是要形成完整能力链:环境搭建、ArkTS 语言、ArkUI 组件、Stage 应用模型、系统能力、数据架构、测试调试、性能安全、发布运营。
鸿蒙应用开发
基础:环境和工程
能力扩展:ArkTS + ArkUI
工程化:Stage + 系统能力 + 数据
生产实践:质量、性能、安全、发布治理
DevEco Studio
SDK / 模拟器 / 真机
AppScope / entry / resources
类型系统 / 模块化 / 异步
组件 / 布局 / 状态 / 列表
UIAbility / WindowStage / Context
权限 / 网络 / Preferences / Repository
测试 / 日志 / 性能
隐私 / 合规 / 上架 / 监控

二、详细知识点

1. DevEco Studio

DevEco Studio 是鸿蒙应用开发的核心 IDE,负责创建项目、下载 SDK、编辑 ArkTS、预览界面、管理模拟器、签名、编译和调试。基础阶段最重要的是先创建一个最小 Stage 模型工程并运行成功,不要一开始就堆复杂能力。

工程要求:

  • 能区分 IDE 问题、SDK 问题、项目配置问题和设备连接问题。
  • 能解释 Debug 签名和 Release 签名差异。
  • 能在多人协作中固定 SDK、依赖和构建脚本版本。

2. SDK 与 API 版本

鸿蒙项目的 compileSdkVersion 决定编译时 API,compatibleSdkVersion 决定兼容目标。项目导入失败时,第一步检查本机安装 SDK 是否与 build-profile.json5 匹配。

3. Stage 模型工程结构

text 复制代码
AppScope/app.json5                 应用级信息:包名、图标、版本
entry/src/main/module.json5        模块级信息:Ability、权限、入口
entry/src/main/ets/entryability    UIAbility 生命周期入口
entry/src/main/ets/pages           页面
entry/src/main/ets/components      组件
entry/src/main/ets/model           数据模型
entry/src/main/ets/services        业务服务、缓存、状态封装
entry/src/main/resources           字符串、颜色、图片等资源

4. HAP 与模块

HAP 是 Harmony Ability Package。简单应用通常只有 entry 一个模块;复杂应用可以拆多个 feature 模块。可上线工程要关注模块边界、依赖方向、公共模型复用、构建速度和发布包体。

5. 资源管理

字符串、颜色、图标不要散落在页面里。资源统一管理便于国际化、深色模式、品牌改版和多设备适配。

三、本章 demo

Demo 1:最小应用配置

demo/harmony-news-demo/AppScope/app.json5

json5 复制代码
{
  "app": {
    "bundleName": "com.example.harmonynews",
    "vendor": "example",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:app_icon",
    "label": "$string:app_name"
  }
}

Demo 2:入口 Ability

demo/harmony-news-demo/entry/src/main/ets/entryability/EntryAbility.ets

ts 复制代码
windowStage.loadContent('pages/Index', (err) => {
  if (err.code) {
    hilog.error(0x0000, 'HarmonyNews', 'loadContent failed')
    return
  }
  hilog.info(0x0000, 'HarmonyNews', 'loadContent success')
})

Demo 3:当前机器可运行验证

bash 复制代码
cd /Users/liuyinghui/Documents/harmonyOS/harmonyos-knowledge-system/demo/web-preview
node server.js

浏览器打开 http://127.0.0.1:4173,如果能看到新闻列表并点击详情,说明核心业务 demo 可以运行。

四、面试题与详细答案

1. HarmonyOS Stage 模型工程最关键的文件有哪些?

关键文件包括 AppScope/app.json5entry/src/main/module.json5EntryAbility.ets、页面 pages/*.ets 和资源目录。app.json5 管应用级元信息,module.json5 管模块、Ability、权限和入口,EntryAbility.ets 管生命周期和首页加载,页面文件负责 UI,资源目录负责字符串、颜色和媒体资源。

追问:为什么页面路径错会白屏?因为 WindowStage.loadContent() 根据页面路径加载 ArkUI 页面,路径错误时窗口无法渲染首页。

2. compileSdkVersioncompatibleSdkVersion 有什么区别?

compileSdkVersion 是编译时使用的 API 版本,决定代码能引用哪些接口;compatibleSdkVersion 是兼容目标,影响应用在目标系统上的兼容性判断。导入他人项目时,如果本机 SDK 缺失,常见现象是同步或编译失败。

3. 学习者为什么要先跑通空项目?

因为鸿蒙开发链路包含 IDE、SDK、签名、模拟器、设备连接、构建脚本等多个环节。如果空项目都不能运行,继续写业务代码只会放大问题。先跑通空项目可以把环境问题和业务问题分开。

4. 可上线工程和基础 demo 的差别是什么?

基础 demo 关注功能跑通;可上线工程关注可维护、可测试、可扩展、可观测和可发布。具体表现是模块边界清晰、资源统一、错误可追踪、权限最小化、性能可验证、发布流程可复现。

五、五倍扩展知识点矩阵

1. 学习路线完整知识体系

层级 学习目标 必须掌握 实操产出 质量判断标准
基础 1 知道鸿蒙应用是什么 DevEco、SDK、ArkTS、ArkUI 创建空项目 能解释项目为什么能启动
基础 2 能运行默认页面 模拟器、真机、签名 首页显示文本 能定位环境和代码问题边界
基础 3 能读懂目录结构 AppScope、entry、resources 修改应用名和图标 能说明每个配置文件职责
基础 4 能创建页面 pagesloadContent 新增页面 能处理页面路径错误
能力扩展 1 能组织小型应用 pages/components/model/services 新闻 demo 能避免页面臃肿
能力扩展 2 能做状态驱动页面 @State、列表、按钮 收藏功能 能说明状态来源
能力扩展 3 能做多设备布局 手机、平板、横竖屏 自适应列表 能处理窗口变化
工程化 1 能做真实业务接入 网络、权限、缓存 Repository 能处理失败和重试
工程化 2 能做工程治理 模块、版本、依赖 工程规范 能控制依赖方向
质量保障 能做质量保障 测试、日志、调试 验收清单 能复现并定位问题
发布治理 能做发布治理 签名、隐私、上架 发布包 能解释合规风险
长期维护 能做长期维护 监控、性能、回归 迭代计划 能降低长期维护成本

2. 环境安装深度清单

基础理解 工程化理解 质量关注点
DevEco Studio 写代码和运行 管 SDK、模拟器、签名 固定团队版本、减少环境漂移
SDK Manager 下载 API 和工具 管多版本 SDK 项目版本和本机版本可追踪
Emulator 模拟设备 覆盖不同尺寸 与真机差异要记录
真机调试 USB 连接运行 开发者模式、授权 权限和硬件能力真机验证
签名 让应用可安装 Debug/Release 差异 发布证书管理和权限隔离
HAP 模块包 多模块拆分 包体、依赖、启动路径治理
AppScope 应用级配置 版本、图标、包名 发布标识不可随意变更
module.json5 模块能力 Ability、权限、设备类型 权限最小化和能力边界
resources 资源管理 多语言、多主题 品牌、无障碍、国际化治理
build-profile 构建配置 SDK、target、product CI 构建一致性

3. 工程目录生产实践解读

AppScope 不是普通资源目录,它表达应用身份。bundleName 一旦用于发布和生态能力绑定,就不应随意改变。versionCode 应按发布流水线单调递增,versionName 面向用户展示,两者职责不同。

entry 是入口模块,但不等于所有代码都要放在入口模块。随着业务增长,可以拆分 feature 模块、common 模块和能力模块。可上线工程会把"可复用代码"和"页面入口代码"分开,防止 entry 成为巨型模块。

resources/base 是应用体验一致性的基础。字符串、颜色、图片如果散落在页面中,会导致后期国际化、深色模式和品牌改版成本成倍增加。

4. 版本和兼容策略

场景 错误做法 正确做法
新项目导入失败 直接改代码 先看 SDK 版本和构建配置
团队多人协作 每个人本机随意升级 SDK 文档中固定可用 SDK 版本
升级 API 一次性改所有模块 先建升级分支和回归清单
支持旧设备 只看编译通过 做真实兼容验证
发布回滚 只保留最新包 保存构建产物、签名和版本记录

5. 运行链路拆解

Index 页面 WindowStage EntryAbility HarmonyOS 用户点击应用 Index 页面 WindowStage EntryAbility HarmonyOS 用户点击应用 创建 UIAbility onCreate 创建窗口舞台 loadContent("pages/Index") 构建 ArkUI 页面 展示首页

启动失败排查顺序:应用配置、模块配置、Ability 路径、页面路径、页面构建错误、资源引用错误、SDK/签名/设备问题。

六、环境与工程 demo 扩展任务

任务 操作 验证 对应能力
修改应用名 string.jsonapp_name 启动后标题变化 资源管理
修改图标 替换 app_icon.svg 桌面图标变化 媒体资源
新增颜色 color.json 添加颜色 页面引用成功 资源引用
新增页面 创建 AboutPage.ets 可跳转显示 页面组织
生命周期日志 EntryAbility 打日志 前后台有日志 Stage 生命周期
模拟器运行 DevEco 启动模拟器 应用可安装 环境
真机运行 USB 连接授权 应用可打开 真机调试
平板预览 切换 tablet 设备 布局不溢出 多设备
签名检查 配置 Debug 签名 可安装运行 签名
构建检查 同步工程后构建 无配置错误 工程构建

七、常见故障与定位

现象 高概率原因 定位方式 修复
DevEco 无法同步 SDK 不匹配 看 Sync 日志 安装对应 SDK 或调整配置
启动白屏 页面路径错 检查 loadContent 修正 pages/Index
图标不显示 media 资源缺失 $media: 名称 补资源或改引用
应用名不变 字符串资源没改对 $string: 改正确资源项
真机装不上 签名或授权问题 看安装日志 重新签名和授权
模拟器卡住 镜像或资源不足 看模拟器状态 换镜像或释放资源
运行按钮灰色 模块配置异常 看 run configuration 重新选择 entry
编译 API 报错 SDK 缺接口 查 API 版本 升级 SDK 或降级接口
权限声明无效 放错配置位置 module.json5 移到正确模块
路径大小写问题 文件名不一致 查真实文件名 保持大小写一致

八、扩展面试题

5. AppScopeentry 的边界是什么?

AppScope 表达应用级身份,例如包名、版本、图标和标签;entry 是具体入口模块,包含 Ability、页面、资源和模块配置。把二者分开可以让应用身份和业务入口解耦。多模块项目中,其他模块可以提供能力,但应用身份仍由 AppScope 管理。

6. 为什么大型鸿蒙项目不能只有一个 entry 模块?

所有代码都放在 entry 会导致编译慢、依赖混乱、模块边界不清、测试困难。大型项目应该按业务域或能力域拆分模块,例如 common、network、account、feature-news。拆分后要控制依赖方向,避免 feature 之间互相引用。

7. 如何设计鸿蒙学习路线最稳?

先跑通空项目,再理解工程结构;再学习 ArkTS 和 ArkUI;随后做 Stage 生命周期、导航、网络、缓存、权限;最后补测试、性能、安全和发布。不要一开始就直接做复杂系统能力,因为环境和基础 UI 都没稳时,排错成本会很高。

8. 导入别人项目失败时你会怎么排查?

先看 DevEco 和 SDK 版本,再看 build-profile.json5,然后看模块配置、依赖、签名和设备。不要先改业务代码。能同步失败通常是环境或构建配置,能编译但启动失败才更可能是 Ability、页面或资源问题。

9. 为什么工程化开发要记录环境版本?

移动端工程高度依赖 IDE、SDK、构建插件和设备环境。版本不记录会导致"我这里能跑,你那里不能跑"。工程团队会在 README、CI 或构建配置中固定关键版本,并在升级时写清楚兼容风险。

10. HAP 和应用安装包是什么关系?

HAP 是鸿蒙能力模块包。简单应用可能只有一个 entry HAP;复杂应用可以有多个 HAP 或模块。发布时要关注模块组合、包体大小、权限声明和入口能力配置。

九、知识点详解库

1. 环境不是一次性工作

很多学习者把环境搭建看成"装好 IDE 就结束",但生产项目中环境是持续治理对象。SDK 升级、DevEco Studio 升级、签名证书更新、模拟器镜像变化、团队成员机器差异都会影响构建和运行。工程团队会把环境版本写进 README,并把升级过程当成一次工程变更。

2. SDK 版本要和项目生命周期绑定

短期 demo 可以使用本机最新 SDK,长期项目要明确当前支持的 SDK 范围。升级 SDK 可能带来 API 行为变化、构建插件变化或设备兼容问题。正确做法是建立升级分支,先跑核心流程,再更新文档和 CI。

3. 模拟器验证不能替代真机验证

模拟器适合快速开发和布局调试,但真机才覆盖真实硬件、传感器、性能、权限弹窗、后台策略和系统版本差异。发布前至少要用目标设备形态做真机核心路径验证。

4. Debug 签名和 Release 签名的风险不同

Debug 签名用于开发调试,Release 签名用于发布。不要把调试证书、调试包、测试接口和日志开关带到生产环境。签名证书要有权限和备份管理,否则证书丢失会影响后续发布。

5. 入口模块不能承担所有职责

entry 模块是应用入口,但随着业务变多,应把公共能力、网络、数据、业务特性拆出去。拆分不是为了形式,而是为了减少耦合、提升构建效率、降低多人协作冲突。

6. 配置文件是运行契约

app.json5module.json5build-profile.json5 不只是构建材料,它们决定应用身份、Ability 声明、权限、设备类型和构建目标。配置和代码不一致时,代码写对也可能运行失败。

7. 资源命名要可维护

资源名应表达用途而不是颜色值本身,例如 color_primaryblue_176b87 更容易维护。后续换品牌色时,语义命名只改资源值,页面代码不需要跟着改。

8. 应用能力要从第一天开始记录

项目即使是 demo,也应该写清楚目标设备、核心功能、权限需求、运行方式和验证路径。这些信息会在后续扩展时成为工程边界,避免"越写越像临时代码"。

9. 工程入口要便于新人接手

一个好的鸿蒙工程入口应该让新人 10 分钟内知道如何打开、如何运行、核心页面在哪里、数据从哪里来、遇到构建失败先看什么。README 和目录命名就是项目可维护性的一部分。

10. 版本号不是随便写的

versionCode 面向系统和发布流水线,应递增;versionName 面向用户,应表达版本含义。生产发布中,版本号会和崩溃、灰度、回滚、用户反馈绑定,不能随意复用。

11. 设备类型声明影响能力边界

deviceTypes 不只是展示信息。声明支持 phone/tablet 后,就要承担对应布局、交互和兼容验证责任。声明越多,测试面越大。

12. 空项目运行成功是最小闭环

空项目运行成功说明 IDE、SDK、构建、签名、模拟器或真机链路基本可用。后续任何业务问题都可以以这个闭环为基准排查。

十、环境实战场景库

场景 目标 操作 验收
新人接手 10 分钟跑通 按 README 打开 demo 首页出现
SDK 缺失 定位环境问题 对照 build-profile.json5 SDK 补齐
页面白屏 定位页面路径 loadContent 页面恢复
图标替换 理解媒体资源 app_icon.svg 图标变化
应用改名 理解字符串资源 app_name 名称变化
平板运行 验证设备类型 选择 tablet 布局可用
真机调试 验证真实设备 USB 运行 安装成功
签名失败 理解签名链路 检查签名配置 可安装
版本升级 理解版本语义 修改版本号 构建记录变化
模块拆分 理解工程演进 新增 common 模块 依赖清晰
资源缺失 理解资源引用 删除再恢复资源 错误可定位
构建失败 建立排错顺序 先环境后代码 修复路径明确

十一、扩展面试题库

11. 为什么 README 是工程质量的一部分?

README 不是装饰文档,而是项目入口。它决定新人能否快速运行、测试人员能否找到验收路径、维护者能否理解目录和构建要求。没有 README 的项目,交接成本会很高。

12. 环境问题和代码问题如何区分?

先运行空项目或已知可用项目。如果空项目也失败,优先查 IDE、SDK、签名和设备;如果空项目成功而当前项目失败,再查项目配置、依赖、页面路径和业务代码。

13. 为什么资源要集中管理?

集中管理能支持多语言、深色模式、品牌改版和统一视觉。硬编码资源会让修改散落在页面中,增加遗漏和不一致风险。

14. 多设备支持为什么要谨慎声明?

声明支持某设备意味着要保证该设备上的布局、交互和能力可用。没有经过验证就声明,会带来用户体验和发布质量风险。

15. 如何规划鸿蒙项目的第一周学习?

第一天跑通环境,第二天读懂目录,第三天写页面和组件,第四天做状态和列表,第五天做 Stage 生命周期,第六天接入服务层和缓存,第七天补测试、排错和总结。

十二、完整知识域补全

官方知识地图按开发者任务旅程组织内容,覆盖准备、体验设计、架构、质量、工具、功能开发、测试、上架与分发。当前文档包按这个旅程重新对齐,避免只停留在页面 demo。

知识域 必须掌握的内容 对应文档 必须产出
开发准备 DevEco Studio、SDK、模拟器、真机、账号、签名、HAP 01 可运行工程
工程结构 AppScope、entry、Feature HAP、resources、build-profile 01 目录说明和构建说明
语言基础 ArkTS 类型、类、接口、泛型、异步、异常、模块 02 类型模型和 Service
UI 框架 ArkUI 组件、布局、状态、导航、动画、手势、绘制 03 页面和组件库
应用模型 Stage、UIAbility、WindowStage、Context、Want、ExtensionAbility 04 生命周期和路由设计
数据能力 Preferences、文件、关系型数据库、缓存、Repository 04 数据访问层
系统能力 权限、网络、通知、媒体、位置、后台任务、卡片 04 能力封装层
多设备 响应式布局、折叠屏、平板、分布式/协同场景 03/04 多端适配方案
质量保障 单测、UI 测试、专项测试、调试、日志、DevEco Testing 05 测试矩阵
性能体验 启动、列表、内存、功耗、包体、弱网、无障碍 05 性能清单
安全合规 权限最小化、隐私说明、日志脱敏、敏感数据保护 05 安全清单
发布运营 签名、版本、AGC、分阶段发布、回滚、监控 05 发布门禁
架构设计 模块边界、依赖方向、状态管理、数据流、可观测性 04/05 架构图和约束

十三、鸿蒙工程能力全景图

鸿蒙应用工程能力
开发环境
语言与编译
声明式 UI
应用模型
数据与系统能力
多端体验
质量与发布
架构治理
DevEco Studio
SDK / Previewer / Emulator
签名 / HAP / AGC
ArkTS 类型系统
模块化与依赖
异步、并发、错误边界
组件与布局
状态管理
导航、动画、手势、绘制
UIAbility
WindowStage
ExtensionAbility
Want / Context
网络与权限
Preferences / 文件 / 数据库
通知 / 媒体 / 位置 / 后台任务
手机 / 平板 / 折叠屏
响应式布局
分布式和协同场景
测试与调试
性能与安全
上架、灰度、回滚
分层架构
模块边界
可观测、可测试、可演进

十四、项目目录应如何演进

简单 demo 可以只有 entry,但业务增长后需要拆分:

text 复制代码
harmony-news/
  AppScope/
  entry/                         # 应用入口、壳工程、首页装配
  feature-news/                  # 新闻列表、详情、搜索、分类
  feature-favorite/              # 收藏、阅读历史
  feature-settings/              # 主题、字号、隐私开关
  common-ui/                     # 通用组件、主题、图标、空状态
  common-model/                  # 领域模型、DTO、错误模型
  common-data/                   # Repository、缓存、数据库、网络
  common-platform/               # 权限、通知、日志、设备能力
  test-fixtures/                 # 测试数据和 mock 服务

拆分原则:

  • entry 只做应用入口和页面装配,不承载全部业务。
  • feature-* 按业务域拆,不互相直接依赖。
  • common-* 放稳定公共能力,不能反向依赖业务模块。
  • 数据层不依赖 UI,UI 层不直接依赖底层系统 API。
  • 每个模块都要有 README,说明职责、依赖和可测试点。

十五、能力验收清单

能力 自测问题 合格表现
环境 换一台机器能否跑起来 README 写清 SDK、打开方式和运行方式
工程 新人能否找到入口 AppScope、module、EntryAbility、pages 职责清楚
配置 权限和设备类型是否准确 module.json5 与实际能力一致
资源 颜色、字符串、图标是否集中 页面没有大量硬编码
构建 是否能区分 debug/release 签名、版本、构建模式有说明
演进 业务变多后是否能拆模块 有模块边界和依赖规则
交付 是否能证明核心流程可用 有 demo、验收路径和错误处理

02 ArkTS 语言与工程规范

02 ArkTS 语言与工程规范
一、详细知识点

  1. 类型系统 2. 接口、类与枚举 3. 模块化 4. 异步与错误边界 5. 工程编码规范 二、本章 demo
    Demo 1:数据模型
    Demo 2:服务层模拟异步请求
    Demo 3:浏览器预览同源逻辑
    三、面试题与详细答案
  2. ArkTS 项目为什么要重视类型? 2. 页面层为什么不建议直接处理复杂业务? 3. async/await 的错误应该在哪里处理? 4. 如何判断一个组件是否拆得合理? 四、五倍扩展知识点矩阵
  3. ArkTS 能力地图 2. 类型设计扩展 3. Result 模式 4. 异步并发与顺序 5. 模块依赖规则 五、ArkTS demo 扩展任务
    扩展示例:请求版本号
    六、常见编码错误
    七、扩展面试题
  4. DTO、Entity、ViewModel 有什么区别? 6. 为什么不建议滥用全局单例 Store? 7. 如何设计一个可测试的 Service? 8. try/catch 为什么不能随便吞错误? 9. 什么时候需要泛型? 10. 如何避免 ArkTS 工程越写越乱? 八、ArkTS 知识点详解库
  5. 类型是架构边界 2. 可空字段必须有业务解释 3. 接口转换是防腐层 4. 不可变更新更适合声明式 UI 5. 异步函数要有完整状态 6. 错误要分类 7. 业务函数不要返回魔法值 8. 命名要表达业务 9. 模块越底层越不能依赖 UI 10. Store 需要生命周期策略 九、ArkTS 场景化实战库
    十、扩展面试题库
  6. ArkTS 中为什么要避免大量 any? 12. 如何处理接口字段新增和删除? 13. 为什么 Service 不应该直接弹 UI 提示? 14. 如何设计错误对象? 15. 什么时候应该抽公共工具函数? 十一、ArkTS 语言体系补全
    十二、ArkTS 工程模板
  7. 统一结果模型 2. DTO 转换模板 3. 请求去重模板 4. 状态机模板 十三、编码规范补强
    十四、ArkTS 练习套件

一、详细知识点

1. 类型系统

ArkTS 开发要尽量避免"随便传对象"。页面、接口、缓存和组件都应该有明确类型。

ts 复制代码
export interface NewsArticle {
  id: string
  title: string
  summary: string
  content: string
  category: string
  publishTime: string
  readMinutes: number
  favorite: boolean
}

工程要求:

  • API DTO 与页面模型分离。
  • 可空字段必须显式处理。
  • 不让页面直接依赖后端原始字段。

2. 接口、类与枚举

接口适合表达数据结构;类适合表达默认值和行为;枚举或字面量联合类型适合表达有限状态。

ts 复制代码
export type PageName = 'home' | 'detail' | 'favorites' | 'settings'

export class UserSetting {
  darkMode: boolean = false
  fontScale: number = 1
}

3. 模块化

ts 复制代码
import { NewsArticle } from '../model/NewsArticle'
import { NewsService } from '../services/NewsService'

规范:

  • model 只放类型和轻量模型。
  • services 放业务动作。
  • pages 不直接写复杂数据转换。
  • components 尽量可复用,依靠入参和回调。

4. 异步与错误边界

ts 复制代码
private async reload(): Promise<void> {
  this.loading = true
  this.errorMessage = ''
  try {
    this.articles = await NewsService.queryArticles()
  } catch (error) {
    this.errorMessage = '加载失败,请重试'
  } finally {
    this.loading = false
  }
}

工程要求:

  • 所有远程、文件、权限和系统能力调用都必须有失败路径。
  • 错误要包含业务上下文,但不能泄露隐私。
  • 页面要有加载中、空状态、失败状态和重试入口。

5. 工程编码规范

规则 原因 示例
类型明确 降低运行时错误 let articles: NewsArticle[] = []
函数单一职责 便于测试 toggleFavorite(id)
页面薄、服务厚 降低 UI 耦合 Page 调用 Service
状态可追踪 避免刷新混乱 页面状态集中定义
错误可恢复 用户体验完整 失败提示 + 重试

二、本章 demo

Demo 1:数据模型

demo/harmony-news-demo/entry/src/main/ets/model/NewsArticle.ets

ts 复制代码
export interface NewsArticle {
  id: string
  title: string
  summary: string
  content: string
  category: string
  publishTime: string
  readMinutes: number
  favorite: boolean
}

Demo 2:服务层模拟异步请求

services/NewsService.ets

ts 复制代码
static async queryArticles(): Promise<NewsArticle[]> {
  await delay(250)
  return MOCK_ARTICLES.map((article) => ({ ...article }))
}

Demo 3:浏览器预览同源逻辑

demo/web-preview/app.js 使用同样的文章模型、收藏状态和设置状态,保证没有 DevEco 命令行时也能验证业务流程。

三、面试题与详细答案

1. ArkTS 项目为什么要重视类型?

类型是鸿蒙工程可维护性的基础。页面、组件、服务和缓存之间如果没有明确类型,字段变更会很难定位,运行时错误也会增多。明确类型还能让 IDE 自动补全、编译检查和重构更可靠。

追问:接口返回字段和页面模型是否应该完全一致?不一定。生产项目建议 DTO 与页面模型分离,中间用转换函数处理默认值、空值和字段命名。

2. 页面层为什么不建议直接处理复杂业务?

页面层主要负责展示和交互。如果网络请求、缓存、数据转换、权限处理都写在页面里,会导致页面难测试、难复用、难排错。更好的方式是 Page 调用 Service,Service 调用 Store 或 Remote API。

3. async/await 的错误应该在哪里处理?

Service 层负责记录技术错误和转换业务错误;Page 层负责展示用户可理解的状态。不能只在底层 catch 后返回空数据,否则页面无法区分"真的为空"和"加载失败"。

4. 如何判断一个组件是否拆得合理?

看三个指标:是否能复用、是否降低父页面复杂度、是否有清晰输入输出。比如 NewsCard 接收 article 和事件回调,自己不关心数据从哪里来,这就是合理拆分。

四、五倍扩展知识点矩阵

1. ArkTS 能力地图

能力 基础要求 工程化要求 工程要求
基础类型 会用 string/number/boolean 能处理联合类型和数组 能设计稳定领域模型
接口 会定义字段 区分 DTO 和 ViewModel 能做版本兼容转换
会写默认值 封装行为 避免把类变成全局状态容器
模块 会 import/export 按目录拆分 控制依赖方向
异步 会 async/await 处理 loading/error 设计取消、重试、超时
集合 会数组 map/filter/find 不直接修改被追踪对象 控制大数据性能
空值 会判断 undefined 路由参数校验 系统性设计边界
异常 会 try/catch 区分技术错误和业务错误 错误可观测、可恢复
泛型 理解通用结构 封装 Result/Repository 保持类型安全和可读性
代码规范 命名清晰 分层清晰 可测试、可审查、可演进

2. 类型设计扩展

ts 复制代码
export interface ApiResponse<T> {
  code: number
  message: string
  data?: T
}

export interface NewsDto {
  article_id: string
  headline: string
  digest?: string
}

export interface NewsArticle {
  id: string
  title: string
  summary: string
}

export function toArticle(dto: NewsDto): NewsArticle {
  return {
    id: dto.article_id,
    title: dto.headline,
    summary: dto.digest ?? '暂无摘要'
  }
}

为什么要做转换:后端字段可能用下划线,页面模型可能用驼峰;后端字段可能为空,页面需要默认值;后端返回可能多字段,页面只需要一部分。转换层能保护 UI 不被接口变化直接冲击。

3. Result 模式

ts 复制代码
export type Result<T> =
  | { success: true; data: T }
  | { success: false; message: string; retryable: boolean }

async function loadNews(): Promise<Result<NewsArticle[]>> {
  try {
    const data = await NewsService.queryArticles()
    return { success: true, data }
  } catch (error) {
    return { success: false, message: '新闻加载失败', retryable: true }
  }
}

Result 模式的价值是让调用方明确处理成功和失败,而不是把异常藏在空数组里。可上线代码不把"没有数据"和"加载失败"混为一谈。

4. 异步并发与顺序

场景 推荐写法 原因
必须按顺序 await step1(); await step2() 保证依赖顺序
可并发 Promise.all 缩短等待时间
任一成功即可 Promise.race 或业务封装 做降级
可重试请求 包装 retry 函数 避免页面重复写逻辑
页面退出 记录请求版本 避免旧请求覆盖新状态

页面常见问题:用户快速切换页面,旧请求回来后覆盖新页面状态。解决方式是维护请求序号,只接受最后一次请求结果。

5. 模块依赖规则

text 复制代码
pages -> components
pages -> services
services -> model
services -> storage/network
components -> model
model -> no dependency

不要让 model 反向依赖 pages,不要让 components 直接调用网络服务,不要让 services 引用具体 UI 组件。依赖方向越稳定,项目越容易维护。

五、ArkTS demo 扩展任务

任务 文件 目标 验证
增加 NewsCategory 类型 model 限制分类取值 错误分类编译失败
增加 DTO 转换 services 模拟接口转换 页面字段不变
增加 Result 返回 NewsService 区分失败和空列表 页面显示错误
增加请求版本号 Index.ets 防旧请求覆盖 快速刷新不乱
增加搜索函数 NewsService 练习 filter 搜索标题成功
增加排序函数 NewsService 练习不可变数组 阅读时长排序
增加设置模型校验 SettingsStore 限制字体范围 不能超出区间
增加收藏统计 FavoriteStore 练习派生数据 显示收藏数量
增加错误日志上下文 services 便于排查 日志含方法名
增加单测伪代码 docs 建立测试意识 每个函数有输入输出

扩展示例:请求版本号

ts 复制代码
private requestVersion: number = 0

private async reload(): Promise<void> {
  const currentVersion = ++this.requestVersion
  this.loading = true
  const articles = await NewsService.queryArticles()
  if (currentVersion !== this.requestVersion) {
    return
  }
  this.articles = articles
  this.loading = false
}

这个写法解决"连续点击刷新,后返回的旧请求覆盖新请求"的问题。生产项目还会配合取消请求、超时和重试。

六、常见编码错误

错误 后果 修复
任意对象到处传 字段变更难定位 定义接口和转换函数
页面直接写 mock 数据 页面不可复用 移到 Service
catch 后返回空数组 无法区分失败和无数据 使用 Result 或错误状态
深层修改对象 UI 可能不刷新 生成新对象或新数组
命名过短 可读性差 使用业务语义命名
Service 引用页面 依赖倒置 Service 只处理业务
Store 无限增长 内存风险 做容量和清理策略
日志输出敏感信息 安全风险 脱敏和分级
异步结果不校验 状态错乱 请求版本或取消机制
类型全写 any 编译保护失效 用接口、泛型、联合类型

七、扩展面试题

5. DTO、Entity、ViewModel 有什么区别?

DTO 面向接口传输,字段由后端或协议决定;Entity 或领域模型面向业务含义;ViewModel 面向页面展示。三者分离可以降低接口变化对 UI 的影响。小 demo 可以合并,但生产项目建议至少区分接口返回和页面模型。

6. 为什么不建议滥用全局单例 Store?

单例 Store 简单,但容易带来隐式依赖、测试困难、生命周期不清和内存长期占用。适合保存轻量、明确、跨页面共享的数据;复杂业务要结合模块边界、持久化和清理策略。

7. 如何设计一个可测试的 Service?

Service 应该输入明确、输出明确,不直接依赖 UI,不直接弹窗,不读取隐式页面状态。网络和存储可以通过接口抽象或可替换函数注入。这样单元测试可以用 mock 数据验证成功、失败和边界。

8. try/catch 为什么不能随便吞错误?

吞错误会让上层无法判断失败原因,用户也看不到正确状态。正确方式是记录必要上下文,把底层错误转换成业务可理解的错误,再由页面展示重试、空状态或降级。

9. 什么时候需要泛型?

当多个结构只有数据类型不同而处理逻辑一致时,例如 ApiResponse<T>Result<T>PageData<T>。泛型可以减少重复,但不要为了炫技过度抽象,影响团队理解。

10. 如何避免 ArkTS 工程越写越乱?

先定目录职责,再定依赖方向,再定命名和错误处理规则。每新增一个功能都要问:类型放哪里、服务放哪里、状态属于谁、失败怎么展示、是否需要测试。长期坚持这些问题,工程复杂度才不会失控。

八、ArkTS 知识点详解库

1. 类型是架构边界

类型不仅是编译工具提示,它定义了模块之间的契约。NewsArticle 一旦成为页面模型,组件、服务和测试都会依赖它。随意改字段会影响所有调用方,因此字段命名、可空性和默认值都要谨慎。

2. 可空字段必须有业务解释

字段可空不是简单加 ?。要说明为什么可空:接口可能缺失、权限未授权、用户未填写,还是缓存版本旧。不同原因对应不同 UI 和错误处理。

3. 接口转换是防腐层

接口字段属于外部系统,页面模型属于本应用。中间转换层可以防止后端字段命名、默认值、枚举变化直接影响 UI。可上线项目会把转换函数单独测试。

4. 不可变更新更适合声明式 UI

在声明式 UI 中,生成新数组和新对象通常比深层原地修改更安全。它让状态变化更明确,也更容易触发刷新和调试。

5. 异步函数要有完整状态

一次异步加载至少对应四种状态:未开始、加载中、成功、失败。很多页面只写成功状态,导致失败时用户看到空白。

6. 错误要分类

网络错误、权限错误、数据格式错误、业务错误、未知错误应分开处理。分类后才能决定是否重试、是否提示用户、是否上报日志。

7. 业务函数不要返回魔法值

例如用空字符串表示失败、用 -1 表示不存在,会让调用方猜语义。更好的方式是返回 undefinedResult<T> 或明确错误对象。

8. 命名要表达业务

handleClickchangeDatadoSomething 不能表达意图。toggleFavoritequeryArticlesupdateFontScale 能直接说明业务行为。

9. 模块越底层越不能依赖 UI

modelservices 应该不知道页面怎么展示。底层依赖 UI 会导致业务逻辑无法复用,也难以测试。

10. Store 需要生命周期策略

内存 Store 简单,但应用重启会丢失;持久化 Store 稳定,但要处理版本迁移、损坏数据和清理。选择 Store 要基于业务数据生命周期。

11. 泛型要服务真实重复

只有当多个函数结构相同、类型不同,才需要泛型。过度泛型会降低可读性,让普通业务开发者难以维护。

12. 代码审查要看边界

ArkTS 代码审查不只看语法,还要看类型是否清晰、异常是否处理、状态是否可追踪、模块依赖是否合理、日志是否安全。

九、ArkTS 场景化实战库

场景 练习点 实现方向 验收标准
新闻搜索 字符串过滤 filter 标题和摘要 输入后列表变化
分类过滤 联合类型 限制分类值 分类不乱写
阅读排序 数组复制排序 不改原数组 排序可恢复
收藏切换 Store 增删 id 计数正确
设置校验 数值边界 限制 0.85-1.25 超界无效
接口转换 DTO Mapper 下划线转驼峰 页面字段稳定
错误显示 Result 成功失败分支 失败可重试
请求防抖 异步控制 延迟执行 连续输入不卡
请求去重 缓存 Promise 同请求复用 不重复加载
旧请求丢弃 版本号 只接受最新 快速刷新不乱
日志脱敏 字符串处理 隐藏敏感值 日志安全
单元测试 纯函数 输入输出断言 可自动验证

十、扩展面试题库

11. ArkTS 中为什么要避免大量 any

any 会绕过类型检查,让编译器失去保护能力。短期写起来快,长期会让字段错误、空值错误和接口变化更晚暴露。生产项目应使用接口、联合类型、泛型或明确转换函数。

12. 如何处理接口字段新增和删除?

新增字段通常不会影响旧页面,但删除或改名会破坏转换层。应把接口 DTO 和页面模型分开,转换函数中处理默认值和兼容逻辑,并给关键转换补测试。

13. 为什么 Service 不应该直接弹 UI 提示?

Service 是业务层,不应该知道页面展示方式。直接弹提示会让 Service 难测试、难复用。正确方式是返回业务结果,由 Page 决定展示 Toast、空状态、弹窗还是重试。

14. 如何设计错误对象?

错误对象至少包含用户文案、技术原因、是否可重试和日志上下文。用户文案给页面展示,技术原因给日志,是否可重试决定按钮,日志上下文帮助定位。

15. 什么时候应该抽公共工具函数?

当同一逻辑出现三次以上,或者逻辑本身有明确业务含义且需要测试时,可以抽。不要把只有一行且语义不稳定的代码过早抽象。

十一、ArkTS 语言体系补全

主题 必须掌握 项目中怎么用 常见错误
基础类型 string、number、boolean、array、object 定义页面状态和模型 any 绕过检查
字面量类型 固定状态集合 `type PageName = 'home' 'detail'`
interface 数据契约 DTO、ViewModel、配置对象 字段可空性不清
class 默认值和行为 UserSetting、错误模型 把 class 当全局变量
enum/联合类型 有限状态 分类、页面名、错误码 状态值散落
泛型 通用响应结构 Result<T>PageData<T> 抽象过度
模块 import/export model/service/component 分层 循环依赖
异步 Promise、async/await 网络、文件、权限 不处理失败
并发 Promise.all、请求版本 并行加载、丢弃旧请求 旧结果覆盖新状态
异常 try/catch、Result 错误映射 catch 后静默
集合 map/filter/find/reduce 列表、搜索、统计 原地修改导致状态不清
函数式转换 DTO -> Model 接口防腐层 页面直接吃接口字段

十二、ArkTS 工程模板

1. 统一结果模型

ts 复制代码
export type AppErrorCode =
  | 'NETWORK_TIMEOUT'
  | 'PERMISSION_DENIED'
  | 'DATA_EMPTY'
  | 'DATA_INVALID'
  | 'UNKNOWN'

export interface AppError {
  code: AppErrorCode
  message: string
  retryable: boolean
  cause?: string
}

export type AppResult<T> =
  | { ok: true; data: T }
  | { ok: false; error: AppError }

这样页面能明确知道:是否成功、失败原因、是否可重试、应该显示什么文案。

2. DTO 转换模板

ts 复制代码
interface NewsDto {
  id?: string
  title?: string
  digest?: string
  content?: string
  tag?: string
}

function normalizeNews(dto: NewsDto): NewsArticle {
  return {
    id: dto.id ?? `local-${Date.now()}`,
    title: dto.title ?? '未命名内容',
    summary: dto.digest ?? '暂无摘要',
    content: dto.content ?? '',
    category: dto.tag ?? 'General',
    publishTime: new Date().toISOString().slice(0, 10),
    readMinutes: Math.max(1, Math.ceil((dto.content?.length ?? 100) / 300)),
    favorite: false
  }
}

3. 请求去重模板

ts 复制代码
class RequestCache<T> {
  private pending?: Promise<T>

  run(task: () => Promise<T>): Promise<T> {
    if (!this.pending) {
      this.pending = task().finally(() => {
        this.pending = undefined
      })
    }
    return this.pending
  }
}

用于首页重复刷新、配置重复拉取、用户信息重复请求。

4. 状态机模板

ts 复制代码
type LoadState<T> =
  | { type: 'idle' }
  | { type: 'loading'; keepOldData: boolean }
  | { type: 'success'; data: T }
  | { type: 'empty'; message: string }
  | { type: 'error'; message: string; retryable: boolean }

页面不要只用 loading: booleanerrorMessage: string 凑合。复杂页面用状态机更清晰。

十三、编码规范补强

规则 原因 检查方式
页面不直接写接口 DTO 防止接口变化冲击 UI 看 Page 是否 import DTO
Service 不引用 UI 组件 保持业务层可测试 看 services 是否 import pages/components
Store 不无限保存数据 防止内存和隐私问题 看是否有清理策略
日志不包含敏感字段 防止隐私泄露 搜索 token、phone、location
错误不静默 用户可恢复 catch 是否返回明确结果
异步有并发策略 防止状态乱序 是否有请求版本/去重/取消
数组更新生成新对象 响应式更稳定 是否大量原地修改
命名带业务含义 提升可读性 禁止 doItdata1

十四、ArkTS 练习套件

练习 输入 输出 要求
DTO 转换 不完整新闻对象 完整 NewsArticle 默认值合理
搜索过滤 keyword + list 过滤列表 大小写和空值处理
分类过滤 category + list 分类列表 未知分类返回空
收藏切换 id + favorites 新 favorites 不原地污染
错误映射 unknown error AppError 文案可展示
请求版本 连续请求 最新结果 旧请求不覆盖
分页合并 old + page merged 去重
设置校验 scale safe scale 范围控制
缓存解析 JSON string model/null 损坏数据不崩
统计派生 list count/map 不重复计算

十五、补充面试题

16. ArkTS 中如何设计页面状态?

页面状态要能表达完整 UI:未加载、加载中、成功、空数据、失败、提交中。简单页面可用多个 @State,复杂页面建议使用状态机结构,避免 boolean 组合出不可能状态。

17. 为什么 DTO 转换函数值得单独测试?

DTO 是外部输入,最容易出现字段缺失、类型变化和版本兼容问题。转换函数如果稳定,页面模型就稳定。测试转换函数能提前发现接口变更影响。

18. 如何防止旧异步请求覆盖新状态?

可以维护请求版本号、使用取消机制或请求去重。每次发起请求记录当前版本,结果回来时只接受最新版本,旧结果直接丢弃。

19. ArkTS 模块拆分的核心原则是什么?

按职责和依赖方向拆分。模型不依赖服务,服务不依赖 UI,组件不直接操作系统能力。依赖方向稳定,项目才能长期维护。

20. 什么时候使用状态机而不是多个布尔值?

当页面有多种互斥状态时使用状态机。例如 loading、empty、error、success 不能随意组合。状态机能让 UI 分支更清楚,也便于测试。

03 ArkUI 组件、状态与多端适配

03 ArkUI 组件、状态与多端适配
一、详细知识点

  1. 声明式 UI 2. 基础组件 3. 状态装饰器 4. 列表性能 5. 多端适配 二、本章 demo
    Demo 1:新闻卡片组件
    Demo 2:设置页状态
    Demo 3:浏览器版验证
    三、面试题与详细答案
  2. ArkUI 的声明式 UI 和传统命令式 UI 有什么区别? 2. @State 适合保存哪些数据? 3. 长列表为什么容易卡顿? 4. 如何做手机和平板适配? 四、五倍扩展知识点矩阵
  3. ArkUI 组件能力地图 2. 状态来源拆解 3. 布局原则 4. 组件拆分标准 5. 多端适配决策 五、ArkUI demo 扩展任务
    扩展示例:空状态组件设计
    六、视觉和交互质量清单
    七、扩展面试题
  4. 如何设计一个可复用 ArkUI 组件? 6. 为什么列表 item 不应写太复杂? 7. 深色模式为什么不能只改背景色? 8. 如何处理字体放大带来的布局问题? 9. @Link 为什么要谨慎使用? 10. 如何判断一个页面达到可上线 UI 质量? 八、ArkUI 知识点详解库
  5. UI 质量首先是状态质量 2. 组件职责要小而完整 3. 列表要按数据量设计 4. 布局要考虑文本增长 5. 空状态是功能的一部分 6. 加载状态要避免误操作 7. 深色模式要成体系 8. 无障碍不是后期补丁 9. 平板不是放大的手机 10. 视觉层级服务任务 九、ArkUI 场景化实战库
    十、扩展面试题库
  6. ArkUI 页面为什么要同时设计 loading、error、empty、data? 12. 如何避免组件过度封装? 13. 如何设计列表卡片的点击区域? 14. 为什么 UI 也需要验收清单? 15. 如何从 demo UI 演进到生产 UI? 十一、ArkUI 知识体系补全
    十二、导航与页面栈设计
    十三、状态管理深入
    十四、动画、手势与绘制

一、详细知识点

1. 声明式 UI

ArkUI 的核心思想是"状态描述界面"。开发者声明当前状态下界面应该是什么样,状态变化后框架更新界面。

ts 复制代码
@State selectedTab: number = 0

selectedTab 改变时,依赖它的 UI 会重新计算。

2. 基础组件

组件 作用 demo 场景
Text 标题、摘要、正文 新闻标题和内容
Button 用户命令 刷新、收藏、返回
List / ListItem 长列表 首页新闻列表
Column / Row 基础布局 页面主体、卡片按钮区
Blank 弹性占位 顶部栏左右分布
Toggle / Slider 设置项 深色模式、字体大小

3. 状态装饰器

装饰器 场景 边界
@State 当前组件内部可变状态 不适合跨页面共享大状态
@Prop 父传子展示数据 子组件不应修改
@Link 父子双向绑定 谨慎使用,避免状态流混乱
@Builder 复用局部 UI 结构 不要写复杂业务逻辑

4. 列表性能

列表是移动应用高频性能点。卡片组件要稳定,避免每个 item 做大量同步计算。数据更新时优先生成新数组,便于框架识别变化。

5. 多端适配

设备 UI 策略 交互策略
手机 单列、底部区域易点击 单手操作
平板 列表 + 详情分栏 鼠标、键盘、触控都可用
折叠屏 根据窗口宽度切换布局 展开不中断状态
车机 大字号、高对比、少输入 降低驾驶干扰
穿戴 卡片化、短信息 极简操作

二、本章 demo

Demo 1:新闻卡片组件

components/NewsCard.ets

ts 复制代码
@Component
export struct NewsCard {
  article: NewsArticle
  onOpen: (id: string) => void = () => {}
  onFavorite: (id: string) => void = () => {}

  build() {
    Column() {
      Text(this.article.title).fontSize(20).fontWeight(FontWeight.Bold)
      Text(this.article.summary).fontSize(14).opacity(0.72)
      Row() {
        Button('查看').onClick(() => this.onOpen(this.article.id))
        Button(this.article.favorite ? '取消收藏' : '收藏')
          .onClick(() => this.onFavorite(this.article.id))
      }
    }
  }
}

Demo 2:设置页状态

pages/SettingsPage.ets

ts 复制代码
Toggle({ type: ToggleType.Switch, isOn: this.setting.darkMode })
  .onChange((isOn: boolean) => {
    this.onDarkModeChange(isOn)
  })

Demo 3:浏览器版验证

运行 demo/web-preview 后,在设置页切换深色模式和字体大小,检查列表和详情的视觉变化。

三、面试题与详细答案

1. ArkUI 的声明式 UI 和传统命令式 UI 有什么区别?

命令式 UI 是找到控件后手动修改,例如设置某个 Text 的内容;声明式 UI 是状态改变后重新描述 UI。ArkUI 中 @State 变化会驱动界面更新,开发者关注状态和 UI 的映射关系。

2. @State 适合保存哪些数据?

适合保存当前组件内部使用、会影响 UI 的数据,如加载状态、当前 tab、输入框内容、列表数据。跨页面长期共享的数据不应散落在多个 @State 中,应该抽到 Store 或 Service。

3. 长列表为什么容易卡顿?

长列表 item 多,任何复杂布局、同步计算、图片解码、频繁状态变更都会放大成本。优化方向包括拆分稳定组件、减少不必要重绘、控制图片尺寸、分页加载和缓存。

4. 如何做手机和平板适配?

不要只按屏幕像素写死布局。手机优先单列,平板可以分栏;文本和卡片高度要能随字体变化;触控区域要足够大;横屏时要检查内容是否过宽或过挤。

四、五倍扩展知识点矩阵

1. ArkUI 组件能力地图

分类 常见组件 解决问题 质量关注点
文本 Text 标题、摘要、正文 字体缩放、截断、无障碍
操作 Button 用户命令 防重复点击、状态反馈
容器 ColumnRow 基础布局 自适应、间距一致
层叠 Stack 浮层、角标 遮挡和点击区域
列表 ListListItem 长数据 性能、复用、分页
表单 TextInputToggleSlider 输入和设置 校验、回显、保存
媒体 Image 图标、封面 尺寸、缓存、占位
导航 Navigation 或页面状态 多页面 参数、返回栈、恢复
反馈 加载、空状态、错误提示 状态表达 可恢复和可解释
主题 颜色、字体、间距 一致体验 深色模式和品牌治理

2. 状态来源拆解

状态 示例 生命周期 应放位置
页面临时状态 当前 tab、loading 页面存在期间 @State
组件展示数据 卡片标题、摘要 父组件传入 @Prop 或普通入参
表单双向编辑 开关、输入框 编辑期间 @Link 或回调
业务共享状态 收藏、登录用户 跨页面 Store/Service
持久化状态 主题、字号 重启后保留 Preferences/Store
远程状态 新闻列表 随接口变化 Repository
派生状态 收藏数量 由基础状态计算 函数或 getter
错误状态 加载失败 一次请求期间 Page
空状态 无收藏 数据结果 Page + Component
权限状态 已授权/拒绝 系统决定 PermissionService

3. 布局原则

不要用固定高度硬压内容。鸿蒙应用要面对字体缩放、横竖屏、平板、折叠屏和多语言。布局应该优先使用内容自适应、百分比宽度、合理间距和可滚动区域。

ts 复制代码
Column() {
  Text(this.article.title)
    .fontSize(20 * this.fontScale)
    .fontWeight(FontWeight.Bold)
  Text(this.article.summary)
    .fontSize(14 * this.fontScale)
    .opacity(0.72)
}
.width('100%')
.padding(16)

4. 组件拆分标准

问题 如果答案是"是" 处理
这块 UI 会重复出现吗 拆组件
这块 UI 有独立输入输出吗 拆组件
父页面已经超过可读范围吗 拆组件
组件需要知道网络吗 只传数据和回调
组件需要知道路由吗 通常否 由页面处理跳转

5. 多端适配决策

手机
平板
折叠展开
获取窗口宽度
宽度是否足够
单列列表
列表 + 详情分栏
保持状态并切换布局
底部或顶部操作
左列表右详情
避免重置 selectedId

五、ArkUI demo 扩展任务

任务 操作 验证
增加搜索框 首页顶部加输入 输入关键字过滤列表
增加分类 tab Stage/ArkUI/Release 点击分类更新列表
增加空状态组件 搜索无结果 显示可恢复提示
增加加载骨架 模拟请求延迟 首屏不突兀
增加错误重试 Service 抛错 页面出现重试按钮
增加分栏布局 平板宽屏 左列表右详情
增加字体缩放 设置页 slider 页面文字同步变化
增加深色模式 设置页 switch 背景和文字变化
增加收藏角标 卡片上显示 收藏状态明显
增加按钮禁用 loading 时禁用刷新 防重复点击
增加列表滚动保持 返回首页 位置不突兀
增加详情字号 详情正文适配 不截断

扩展示例:空状态组件设计

ts 复制代码
@Component
export struct EmptyView {
  message: string
  actionText: string = ''
  onAction: () => void = () => {}

  build() {
    Column() {
      Text(this.message)
      if (this.actionText.length > 0) {
        Button(this.actionText).onClick(() => this.onAction())
      }
    }
  }
}

空状态不是"没有内容就空白",而是告诉用户发生了什么、是否可以恢复、下一步怎么做。

六、视觉和交互质量清单

检查项 标准
字体 标题、正文、辅助信息层级清楚
间距 页面、卡片、按钮间距一致
对比度 深浅模式都能读清
点击区域 按钮不贴边、不太小
滚动 长内容可滚动,不遮挡
状态反馈 点击、加载、失败都有反馈
空状态 用户知道下一步
横屏 内容不挤压
平板 不浪费大屏
字号放大 不溢出、不重叠

七、扩展面试题

5. 如何设计一个可复用 ArkUI 组件?

可复用组件要有明确输入、明确输出和低业务耦合。输入通过属性传入,输出通过回调传出。组件不应直接请求网络、不应直接操作全局路由,也不应知道父页面完整业务流程。

6. 为什么列表 item 不应写太复杂?

列表 item 会大量重复,复杂布局和同步计算会被放大,导致滚动卡顿。应把复杂计算提前到数据层,item 只做展示;图片要限制尺寸并考虑缓存;状态变化要尽量局部化。

7. 深色模式为什么不能只改背景色?

深色模式涉及背景、文字、边框、阴影、图标、状态色和图片适配。如果只改背景,文字可能对比不足,卡片阴影可能不自然,图标可能不可见。颜色应集中管理。

8. 如何处理字体放大带来的布局问题?

避免固定高度,允许文本换行,重要容器可滚动,按钮文案不要过长。测试时要把字体调到较大值,看标题、卡片、详情和设置项是否溢出或遮挡。

@Link 会形成双向绑定,简单表单很方便,但复杂业务中过多双向绑定会让状态变化来源不清。跨页面或业务状态更适合事件回调和 Store 管理。

10. 如何判断一个页面达到可上线 UI 质量?

核心路径可用,加载、失败、空状态完整;不同设备和字号下不溢出;交互有反馈;状态变化可预测;视觉层级清晰;组件可复用;无明显卡顿和遮挡。

八、ArkUI 知识点详解库

1. UI 质量首先是状态质量

页面不好维护,根源通常不是组件太多,而是状态混乱。一个页面要明确数据状态、加载状态、错误状态、空状态、选择状态和编辑状态。状态清楚,UI 才稳定。

2. 组件职责要小而完整

NewsCard 只负责展示一篇文章和暴露点击事件,不负责查询文章、不负责导航、不负责保存收藏。职责越清楚,组件越可复用。

3. 列表要按数据量设计

4 条数据和 4000 条数据的写法不能完全一样。数据少可以简单渲染,数据多要考虑分页、懒加载、缓存、图片尺寸和滚动性能。

4. 布局要考虑文本增长

中文、英文、多语言、字体放大都会让文本长度变化。固定高度和固定宽度容易溢出。可上线 UI 会为最长文案和最大字号留空间。

5. 空状态是功能的一部分

收藏为空、搜索无结果、网络失败、权限拒绝都不应该显示空白。空状态要解释原因,并提供返回、重试或修改条件的入口。

6. 加载状态要避免误操作

加载时按钮是否禁用、是否允许再次刷新、是否保留旧数据,都要按场景设计。无限转圈没有意义,要有超时和失败状态。

7. 深色模式要成体系

深色模式不是反转颜色,而是设计一套背景、文本、边框、状态、阴影和图标规则。局部硬编码颜色会破坏整体一致性。

8. 无障碍不是后期补丁

字体可放大、对比度足够、点击区域足够、信息不只靠颜色表达,这些应从组件设计阶段考虑。

9. 平板不是放大的手机

平板有更多空间,应考虑分栏、侧边栏、详情同屏、键盘鼠标操作。简单把手机页面拉宽会浪费空间。

10. 视觉层级服务任务

标题、摘要、按钮、辅助信息的视觉权重要反映用户任务。不要让所有文字一样大,也不要让次要按钮比主要操作更抢眼。

九、ArkUI 场景化实战库

场景 UI 目标 状态目标 验收
首页首屏 快速看到内容 loading -> data 不白屏
新闻详情 阅读沉浸 selectedId 有效 返回正常
收藏页 展示筛选结果 favorite 派生 数量正确
设置页 即时反馈 setting 更新 主题变化
搜索 快速过滤 keyword 状态 无结果提示
分类 降低信息密度 category 状态 切换稳定
弱网 不阻塞用户 error 状态 可重试
空收藏 引导下一步 empty 状态 可返回首页
字体放大 可读性 fontScale 不溢出
平板横屏 利用空间 layout 状态 不拉伸
快速点击 防误操作 disabled 状态 不重复提交
返回恢复 保持上下文 selected/scroll 不重置体验

十、扩展面试题库

11. ArkUI 页面为什么要同时设计 loading、error、empty、data?

真实应用不会永远成功返回数据。loading 解决等待,error 解决失败,empty 解决成功但无数据,data 解决正常展示。缺任何一个状态,用户都会在某些场景下看到空白或错误体验。

12. 如何避免组件过度封装?

组件抽象要基于复用和复杂度,而不是为了文件数量。只用一次、逻辑很短、未来变化不确定的 UI 可以先留在页面中;重复出现或职责清晰的 UI 再拆。

13. 如何设计列表卡片的点击区域?

主要点击区域要清晰,按钮之间要有足够间距,卡片整体点击和局部按钮点击不要冲突。收藏按钮、查看按钮和卡片进入详情的行为要一致可预期。

14. 为什么 UI 也需要验收清单?

UI 问题很多不是编译错误,而是体验问题。验收清单能覆盖字号、横屏、深色模式、空状态、错误状态、按钮点击和列表滚动,减少人工遗漏。

15. 如何从 demo UI 演进到生产 UI?

先补齐状态,再统一组件,再抽主题变量,再做多端适配,再补无障碍和性能检查。不要一开始只追求视觉复杂度,缺状态和边界的 UI 不能上线。

十一、ArkUI 知识体系补全

领域 必会内容 实战场景 质量要求
基础组件 Text、Button、Image、Blank 标题、操作、图标 对齐、尺寸、可读
容器布局 Column、Row、Stack、Flex、Grid 页面、卡片、面板 自适应、不溢出
列表 List、ListItem、LazyForEach 新闻流、设置项 滚动稳定、分页
表单 TextInput、Toggle、Slider、Checkbox 搜索、设置、筛选 校验、回显、禁用
导航 Navigation、NavDestination、router 首页、详情、设置 参数安全、返回正确
状态管理 @State、@Prop、@Link、@Provide/@Consume、Observed/ObjectLink 父子通信、跨层级共享 来源明确
Builder @Builder、局部 UI 复用 空状态、标题栏、操作区 不塞业务逻辑
动画 属性动画、显隐动画、转场 收藏反馈、页面切换 不影响性能
手势 click、swipe、drag、longPress 卡片操作、滑动删除 防误触
绘制 Canvas、Shape、Path 图表、徽章、进度 性能可控
媒体 Image、Video、Audio 相关能力 封面、播放 占位、错误、缓存
主题 颜色、字体、间距、深浅模式 全局风格 集中管理
无障碍 字号、对比、朗读、触控区域 老年用户、弱视用户 不只靠颜色表达
多端 phone/tablet/foldable 分栏和响应式 状态不中断

十二、导航与页面栈设计

简单项目可以用页面状态模拟,但业务项目需要稳定的导航模型。导航设计要解决:页面路径、参数传递、返回栈、深链、异常参数、状态恢复。

ts 复制代码
interface DetailParams {
  articleId: string
  from: 'home' | 'favorites' | 'search'
}

function validateDetailParams(params?: DetailParams): string | undefined {
  if (!params || params.articleId.length === 0) {
    return undefined
  }
  return params.articleId
}

导航规则:

  • 列表到详情只传 id,不传整个对象。
  • 参数缺失时显示空状态或返回安全页面。
  • 返回逻辑要考虑来源页。
  • 页面恢复后要能重新查数据。
  • 深链进入时要补齐上下文。

十三、状态管理深入

状态模式 适合场景 风险 替代方案
@State 组件内部状态 跨页面复用困难 Store
@Prop 父到子展示 子组件不能改父状态 回调
@Link 表单双向编辑 状态来源不清 明确事件
@Provide/@Consume 跨层级共享 隐式依赖 状态容器
Observed/ObjectLink 对象属性观察 嵌套更新复杂 不可变模型
Store 单例 小型共享状态 生命周期不清 Repository + 持久化

状态设计问题通常比组件 API 更重要。页面越复杂,越要把状态拆成:输入状态、远程数据状态、派生状态、提交状态、错误状态。

十四、动画、手势与绘制

能力 用法 注意
属性动画 收藏、展开收起、按钮反馈 动画时长短,避免拖慢操作
页面转场 详情打开、设置进入 转场不要掩盖加载失败
手势点击 卡片、按钮 防重复点击
长按 菜单、复制 给明显反馈
滑动 删除、切换 tab 防止和列表滚动冲突
拖拽 排序、调整 保持状态一致
Canvas 图表、进度 控制重绘频率
Shape 图标、标记 优先复用组件

十五、多端布局方案




窗口信息
内容宽度
单列:列表 -> 详情
主列表 + 弹出详情
左列表 + 右详情
保留 selectedId
返回栈管理

验收标准:

  • 手机上操作路径短,按钮不贴边。
  • 平板上内容不被拉得过宽。
  • 横屏时卡片、详情、设置项不重叠。
  • 折叠屏展开时不丢失当前阅读文章。
  • 字体放大后仍然可读、可点击、可滚动。

十六、UI 练习套件

练习 目标 验收
搜索页 输入、过滤、空状态 无结果有提示
分类页 tab 状态 切换不丢收藏
分栏详情 平板布局 左右联动
动画收藏 属性动画 收藏反馈明显
滑动操作 手势 不误触列表滚动
深色主题 主题变量 所有页面可读
大字号 无障碍 无重叠
错误页 失败可恢复 有重试
骨架屏 首屏体验 加载不突兀
图片占位 媒体失败 不破坏布局

十七、补充面试题

页面状态切换适合小 demo,逻辑简单;Navigation 或路由能力适合真实页面栈,能处理返回、参数、深链和页面恢复。业务复杂后应使用稳定导航模型。

17. 如何设计 ArkUI 主题系统?

主题系统要集中管理颜色、字体、间距、圆角、阴影和状态色。页面只引用语义变量,例如 primary、surface、textPrimary,而不是硬编码颜色值。

18. 为什么动画也要纳入性能检查?

动画会影响渲染频率和用户操作响应。过长、过多或触发范围过大的动画会导致卡顿。动画应服务反馈和理解,不应干扰任务完成。

19. 如何处理多端状态保持?

布局切换时不要重建业务状态。把 selectedId、搜索词、收藏集合等放在页面或 Store 中,布局只根据窗口宽度选择展示方式。

20. UI 架构如何支持长期迭代?

建立组件库、主题系统、状态规范、导航规范和验收清单。每个页面按同一套模式处理加载、失败、空状态和数据展示,长期迭代成本会明显下降。

04 Stage 模型、系统能力与数据架构

04 Stage 模型、系统能力与数据架构
一、详细知识点

  1. UIAbility 2. WindowStage 3. Context 4. 页面导航 5. 权限与系统能力 6. 数据架构 二、本章 demo
    Demo 1:生命周期日志
    Demo 2:收藏状态封装
    Demo 3:页面只调用服务
    三、面试题与详细答案
  2. UIAbility 和页面是什么关系? 2. 为什么不能在生命周期里做重任务? 3. 权限拒绝时应该怎么处理? 4. Repository / Service 分层解决什么问题? 四、五倍扩展知识点矩阵
  3. Stage 模型对象关系 2. 生命周期实践 3. 权限治理 4. 数据架构扩展 5. 缓存策略 五、系统能力 demo 扩展任务
    扩展示例:Repository 接口
    六、数据流检查
    七、扩展面试题
  4. Stage 模型里为什么要区分 Ability 生命周期和页面生命周期? 6. 权限最小化如何落地? 7. Repository 和 Store 的区别是什么? 8. 如何设计弱网体验? 9. Context 为什么不能随意长期持有? 10. 如何从 demo 架构演进到生产架构? 八、Stage 与数据架构详解库
  5. 生命周期是资源管理边界 2. 首屏初始化要分级 3. Want 参数必须校验 4. 权限申请要绑定用户动作 5. Repository 是数据源防火墙 6. 本地缓存要有失效策略 7. 弱网不是异常边角 8. 日志要串联链路 9. 多设备能力要先抽象 10. 架构演进要小步保持可运行 九、Stage 与系统能力场景库
    十、扩展面试题库
  6. 为什么首屏不应该等待所有接口? 12. 如何设计缓存失效? 13. 弱网下如何避免重复提交? 14. 为什么权限弹窗要延后到具体场景? 15. 如何判断架构是否过度设计? 十一、系统能力知识体系补全
    十二、数据架构分层方案
    十三、持久化选型
    十四、并发与后台任务

一、详细知识点

1. UIAbility

UIAbility 是带 UI 的应用组件,负责生命周期入口。常见回调包括创建、窗口创建、前台、后台和销毁。

ts 复制代码
export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/Index')
  }
}

2. WindowStage

WindowStage 负责窗口管理和页面加载。首页路径错、资源错或页面构建异常,都可能表现为启动失败或白屏。

3. Context

Context 是访问资源、文件、系统能力和运行环境的重要入口。工程化开发要明确 Context 生命周期,不要把短生命周期对象长期持有。

4. 页面导航

简单 demo 可用页面状态切换;生产项目应使用官方推荐导航能力组织页面栈、参数和返回行为。无论哪种方式,都要处理参数缺失和数据不存在。

5. 权限与系统能力

调用网络、位置、媒体、通知等能力时,要先声明权限,再按场景申请或检查。用户拒绝权限是正常路径,必须给替代方案。

6. 数据架构

Page 页面
Component 组件
Service 业务服务
Remote API / Mock API
Local Store / Preferences
Model 类型模型

工程要求:

  • Page 只做展示和交互。
  • Service 负责业务编排。
  • Store 负责本地状态和持久化。
  • Remote API 负责网络请求。
  • Model 做边界转换,避免脏数据进入 UI。

二、本章 demo

Demo 1:生命周期日志

EntryAbility.ets 中记录生命周期:

ts 复制代码
onForeground(): void {
  hilog.info(0x0000, 'HarmonyNews', 'onForeground')
}

onBackground(): void {
  hilog.info(0x0000, 'HarmonyNews', 'onBackground')
}

Demo 2:收藏状态封装

FavoriteStore.ets

ts 复制代码
static toggle(articleId: string): void {
  if (FavoriteStore.favoriteIds.has(articleId)) {
    FavoriteStore.favoriteIds.delete(articleId)
  } else {
    FavoriteStore.favoriteIds.add(articleId)
  }
}

Demo 3:页面只调用服务

Index.ets 不直接维护收藏集合,而是调用 FavoriteStore.toggle()NewsService.markFavorites(),保持页面薄。

三、面试题与详细答案

1. UIAbility 和页面是什么关系?

UIAbility 是应用组件入口,负责生命周期和窗口创建;页面是 ArkUI 渲染内容。UIAbility 通过 WindowStage.loadContent() 加载页面。页面不应该承担应用生命周期管理职责。

2. 为什么不能在生命周期里做重任务?

生命周期回调影响启动和前后台切换,如果做长时间同步任务会造成首屏慢、卡顿甚至 ANR 风险。重任务应拆到异步流程,首屏只做必要初始化。

3. 权限拒绝时应该怎么处理?

权限拒绝是用户选择,不是程序异常。应用应解释原因、提供降级能力、允许稍后再开启,而不是直接崩溃或强制退出。

4. Repository / Service 分层解决什么问题?

它把页面和数据源解耦。页面不关心数据来自网络、缓存还是 mock;测试时可以替换 Service;接口变更时集中修改转换逻辑。这是从 demo 走向生产工程的关键。

四、五倍扩展知识点矩阵

1. Stage 模型对象关系

对象 职责 常见使用 工程风险
UIAbility UI 应用组件入口 生命周期、窗口创建 生命周期阻塞
WindowStage 窗口舞台 加载页面 页面路径和窗口状态错误
Context 上下文 资源、文件、系统能力 错误持有导致泄漏
Want 启动参数 跨 Ability 传参 参数缺失和类型不匹配
AbilityStage HAP 级初始化 模块启动逻辑 初始化过重
ExtensionAbility 扩展能力 卡片、服务等 生命周期和权限差异
module.json5 模块声明 Ability、权限 配置与代码不一致
app.json5 应用身份 包名、版本 发布后变更风险
resources 资源 字符串、颜色、媒体 多语言和主题治理
hilog 日志 生命周期和错误 敏感信息泄露

2. 生命周期实践

回调 适合做 不适合做
onCreate 轻量初始化、日志 网络大请求、重 IO
onWindowStageCreate 加载首页、窗口配置 业务批处理
onForeground 恢复监听、刷新短期状态 重复创建资源
onBackground 保存草稿、暂停任务 开启新长任务
onDestroy 清理资源 发起不可控异步

生产实践理解:生命周期不是业务万能入口。它是应用运行状态变化的边界,业务初始化要分级:首屏必要、首屏后、用户触发、后台可延迟。

3. 权限治理

权限场景 产品问题 技术问题 合规问题
网络 为什么需要联网 失败和超时 数据传输说明
位置 是否必须精准定位 授权拒绝降级 高敏感信息
相机 是否必须拍摄 设备无能力 用户授权说明
相册 是否可替代 文件格式 最小访问范围
通知 是否打扰用户 通知开关 用户可关闭
麦克风 是否必要 录音失败 明确用途
文件 保存在哪里 空间不足 数据删除
后台任务 是否真需要 耗电 用户感知

4. 数据架构扩展

Page / Component
View State
Service / UseCase
Repository
Remote API
Local Store
DTO Mapper
Error Mapping

分层解释:

  • Page 只关心展示状态。
  • View State 组合 loading、error、data。
  • Service 表达业务动作,如刷新、收藏、保存设置。
  • Repository 屏蔽远程和本地数据源。
  • Mapper 处理 DTO 到领域模型。
  • Error Mapping 把底层错误变成用户可理解状态。

5. 缓存策略

策略 适合场景 风险
只读远程 实时性强 弱网体验差
先缓存后网络 新闻、配置 数据可能短暂旧
只本地 设置、草稿 多端同步差
写穿缓存 写后马上读 写失败处理复杂
定时刷新 首页推荐 耗电和流量
用户触发刷新 列表页 用户等待
分页缓存 长列表 缓存清理
版本化缓存 数据结构升级 迁移成本

五、系统能力 demo 扩展任务

任务 目标 验证
增加网络权限说明 学会权限声明 module.json5 有权限
模拟 HTTP 失败 学会错误状态 页面显示重试
增加缓存读取 学会本地优先 首屏先显示旧数据
增加设置持久化 学会 Preferences 思路 重启后保留设置
增加权限拒绝文案 学会降级 用户知道原因
增加详情参数校验 防止空参数 缺 id 显示空状态
增加刷新节流 防重复请求 连点不重复发起
增加 Repository 解耦页面和数据源 Page 不知道 mock
增加错误码映射 技术错误转业务错误 页面文案清晰
增加日志 traceId 排查链路 日志能串起来

扩展示例:Repository 接口

ts 复制代码
export interface NewsRepository {
  queryArticles(): Promise<NewsArticle[]>
  queryArticleById(id: string): Promise<NewsArticle | undefined>
  toggleFavorite(id: string): Promise<void>
}

接口化后,页面可以依赖抽象,测试时使用 FakeRepository,生产时使用 RemoteRepository + LocalStore。

六、数据流检查

检查项 好的表现 坏的表现
数据来源 页面知道状态,不知道接口细节 页面直接拼接口
错误处理 分技术错误和用户文案 catch 后静默
缓存 有版本和失效策略 永久保存不清理
权限 拒绝可降级 拒绝就崩溃
日志 有模块和动作 只有 error
安全 不记录敏感信息 token 写日志
测试 Service 可替换 只能真机点
并发 处理重复请求 状态互相覆盖
恢复 前后台状态合理 返回页面错乱
扩展 新数据源容易接 页面大改

七、扩展面试题

5. Stage 模型里为什么要区分 Ability 生命周期和页面生命周期?

Ability 生命周期描述应用组件的运行状态,页面生命周期描述 UI 组件的出现和消失。二者粒度不同。把页面数据加载都塞进 Ability 会让入口过重;把应用级资源管理放进页面又会导致重复初始化。

6. 权限最小化如何落地?

先从业务需求反推权限,能不用就不用,能低敏就不用高敏。配置文件只声明真实需要的权限,运行时在用户触发相关功能时申请,并提供拒绝后的降级路径。上线前检查权限说明和实际使用是否一致。

7. Repository 和 Store 的区别是什么?

Repository 负责统一数据访问,可以组合远程、本地和转换逻辑;Store 更偏本地状态或持久化状态管理。Repository 可以使用 Store,但页面最好通过 Service 或 Repository 获取业务数据。

8. 如何设计弱网体验?

首屏尽量展示缓存;请求要有超时;失败要有重试;关键操作要有明确状态;不要无限转圈。对于写操作,要说明是否成功、是否可重试、是否会重复提交。

9. Context 为什么不能随意长期持有?

Context 和运行环境、Ability 生命周期有关。随意长期持有可能造成生命周期错乱或资源无法释放。需要系统能力时应在合适作用域获取,并避免把短生命周期对象保存到全局单例中。

10. 如何从 demo 架构演进到生产架构?

先把 mock 数据移入 Service,再抽 Repository,再增加 LocalStore 和 RemoteAPI,再统一错误处理和日志,最后补测试和发布检查。每一步都保持页面调用方式稳定,避免 UI 随数据源变化大改。

相关推荐
大雷神5 小时前
HarmonyOS APP<<古今职鉴定>>开源教程第26篇:【完整案例】职业性格测试开发
harmonyos·arkts·鸿蒙·古今职鉴
ai安歌5 小时前
鸿蒙PC:鸿蒙electron跨端框架PC链接雷达实战:把本地收藏夹升级成可巡检的链接管理面板
华为·electron·harmonyos
ai安歌5 小时前
鸿蒙PC:Qt适配OpenHarmony实战【昼刻】:用 Qt Quick 做一个可运行的鸿蒙时钟应用
qt·华为·harmonyos
想你依然心痛5 小时前
HarmonyOS 6 悬浮导航 + 沉浸光感:打造鸿蒙智能体驱动的沉浸式音乐创作协作工坊
华为·ar·harmonyos·智能体
lqj_本人5 小时前
鸿蒙electron跨端框架PC复盘手账实战:把一天的判断、评分和明日计划收成结构化记录
华为·harmonyos
ai安歌6 小时前
鸿蒙PC:鸿蒙 electron :模板装配台,把可复用内容拆成模块、变量和发布检查
华为·electron·harmonyos
lqj_本人15 小时前
鸿蒙electron跨端框架PC今日打卡实战:频率、连续天数和今日进度怎么放进桌面工具
华为·harmonyos
cookqq18 小时前
Palantir Foundry 核心建模体系:构建企业级智能知识图谱的基石
人工智能·机器学习·知识图谱·ai编程
一个数据大开发19 小时前
本体论与大模型的融合实践:知识图谱的下一个十年
人工智能·知识图谱