本篇看点
- 适合读者:准备系统学习 HarmonyOS 的移动端开发者;有 iOS / Flutter 经验会更容易形成对照。
- 核心问题:从状态、生命周期和系统能力边界入手,建立 ArkUI 自己的开发思路。
- 学习目标:先建立三端迁移心智,后面的文章再逐步进入示例工程和完整实战。
前言
如果你已经写过移动端,再来学 HarmonyOS,语法通常不是第一道坎。真正影响上手速度的,是能不能快速建立一套新的开发心智。
我一开始也会下意识把 ArkUI 里的组件理解成 UIKit 里的控件实例,或者把 ArkTS 装饰器简单类比成 Flutter 的 setState。类比能帮我们快速找到入口,但写到状态、生命周期和刷新边界时,就需要看清 ArkUI 自己的表达方式。
所以这个系列的第一篇不急着写 Text()、Button(),而是先回答一个问题:有其他移动端背景的人,怎样重新理解 HarmonyOS 应用开发。
一. 先从 UI 心智开始
Flutter 的核心心智是 Widget Tree。状态变化以后,框架重新执行 build(),再通过 Element / RenderObject 做 diff 和布局渲染。
UIKit 的核心心智更偏对象和命令。你拿到 UILabel、UIButton、UITableView,然后修改属性、调用 reloadData()、pushViewController()。
ArkUI 则更接近声明式 UI,但它把状态关系写得更显式。你不是随便一个变量变了 UI 都会动,而是要通过 @State、@Prop、@Link、@Observed 这类装饰器表达数据所有权和刷新关系。
ts
@State count: number = 0;
build() {
Column() {
Text(`count = ${this.count}`)
Button('加一')
.onClick(() => {
this.count += 1;
})
}
}
这段代码看起来像 Flutter 的 setState,但关键差异是:ArkUI 不是让你手动调用一个刷新函数,而是通过状态装饰器把"谁变化会触发 UI 更新"声明出来。
二. 三个平台的第一层对照
| 问题 | HarmonyOS ArkUI | iOS UIKit / SwiftUI | Flutter |
|---|---|---|---|
| 页面怎么描述 | build() 中声明组件树 |
UIKit 手动创建 View,SwiftUI 声明 View | build() 返回 Widget |
| 局部状态 | @State |
UIKit property + reload,SwiftUI @State |
StatefulWidget + setState |
| 父传子 | @Prop |
初始化参数 / 属性注入 | 构造函数参数 |
| 子传父 | callback | delegate / closure | callback |
| 双向绑定 | @Link |
SwiftUI @Binding |
状态上提 + callback / ValueNotifier |
| 跨层传值 | @Provide/@Consume |
Environment / 单例 / DI | InheritedWidget / Provider |
| 路由栈 | NavPathStack |
UINavigationController stack |
Navigator stack |
这张表的作用,是先把熟悉概念和 ArkUI 概念放到同一张地图上。后面真正写代码时,我们会继续沿着"状态归谁、谁触发刷新、刷新到哪里"这条线往下拆。
三. 第一个习惯:少想控件实例,多想状态描述
UIKit 里我们经常这样想:
swift
titleLabel.text = "加载完成"
tableView.reloadRows(at: [indexPath], with: .automatic)
到 ArkUI 里,更自然的问题会变成:
- 这段 UI 由哪个状态描述?
- 状态归谁持有?
- 状态变化会影响多大范围?
- 这个变化要不要持久化?
比如一个列表 item 的点赞状态,如果放在页面的普通数组里整体替换,可能会导致整段列表参与刷新;如果 item 是对象并通过 @Observed/@ObjectLink 建模,就可以把刷新边界压到 item 自己。
四. 第二个习惯:状态放在合适的位置
Flutter 里我们常说"状态上提"。这个原则没错,但在 ArkUI 里要更细,因为装饰器本身就在表达所有权。
简单输入框里的聚焦态、按钮 loading、展开收起状态,通常应该留在小组件内部。专辑详情、播放队列、用户设置这类被多个页面共享的状态,才应该进入 Store 或应用级控制器。
后面的状态管理案例里,我会把同一个收藏列表拆成两种写法:一种是页面持有数组整体刷新,另一种是 item 对象自己刷新。这样比单纯背 @State 和 @ObjectLink 更容易理解。
五. 第三个习惯:页面和系统能力之间留一层
HarmonyOS 的系统能力很多,比如网络、Preferences、RDB、通知、文件、WebView、AVPlayer。初学时直接在页面里调用当然最快,但真实项目会很快失控。
更稳的分层是:
txt
View
-> Store / Controller
-> Repository
-> SystemAdapter
-> HarmonyOS API
这和 iOS 里的 ViewController -> ViewModel -> Repository -> Service,或者 Flutter 里的 Widget -> Bloc/Cubit -> Repository 很像。差异在于 HarmonyOS 还要考虑 Context、UIAbility、WindowStage 这些系统入口,不同 API 需要的上下文并不一样。
六. 这个系列会怎么写
我不会按"组件 API 手册"的方式写。每篇文章都会尽量保持这个结构:
- 这个知识点解决什么真实问题。
- 先用一个最小案例跑通概念。
- 拆解 ArkUI / ArkTS 背后的机制。
- 和 iOS / Flutter 做对比。
- 再给出它在真实业务里的落点。
- 总结迁移时容易遇到的问题。
对有经验的开发者来说,学习一门新平台不只是"知道 API 名字",而是建立一套新判断:什么时候拆组件,什么时候建 Store,什么时候用缓存,什么时候要节流,什么时候要让系统能力从 UI 里抽出来。
小结
HarmonyOS 对移动端开发者并不陌生。旧经验能帮你快速建立映射,而真正写顺手以后,你会逐渐把判断落到 ArkTS 类型系统、ArkUI 状态装饰器、Stage 模型和系统能力边界上。
下一篇我们从项目结构开始,看一个 HarmonyOS 工程里哪些文件是真正重要的,哪些只是构建配置,以及 UIAbility 为什么不是一个普通页面。
今日练习
- 凭自己的经验写一张三端对照表,先列出页面、状态、路由、系统能力分别由谁负责。
- 画一张最小数据流:用户点击按钮后,状态从哪里变化,UI 又由谁刷新。
- 选一个你熟悉的 Flutter 页面或 iOS 页面,尝试用 ArkUI 的状态所有权重新描述它。