训练营走到第七天,第一阶段正式收尾。按计划今天不塞新内容,只做一件事:把前六天关于开源鸿蒙跨平台开发的知识点全部串一遍。这个复盘动作,我认为比前面任何一天都关键——前六天是往桶里装水,第七天是检查桶底有没有漏,顺便看看哪块木板短了,得赶紧补。很多人觉得"复盘"就是把笔记翻一遍,我的理解不是这样。真正的复盘是把零散的知识点重新组织成一张网,让它们互相挂得上、拽得动。
这篇文字就是我把训练营DAY7复盘的完整过程记录下来,包含了第一阶段的整体设计逻辑、核心知识点拆解、典型踩坑记录和后续学习建议。如果你也在学开源鸿蒙,或者刚接触跨平台开发,这份复盘笔记能帮你少走不少弯路——至少,你不需要等到踩过了才知道坑在哪。
1. 第一阶段学习路径复盘:七天里到底学了什么
1.1 训练营设计逻辑:先工具链,再语言,最后框架
第一阶段七天的安排,表面看是"一天一个主题",实际有一条非常清晰的主线:先把工具链跑通,再把语言基础打牢,最后才接触框架和应用模型。
Day1 做的事情就是环境搭建。当时不少同学不理解,觉得写个 Hello World 用得着花一整天吗?真到上手就明白了,开发环境这一关不过,后面全是空中楼阁。开源鸿蒙开发用的官方 IDE 基于开源工具链改造,需要配置 SDK、模拟器、签名信息等等。这里有一个很实在的经验:SDK 版本必须和 IDE 版本匹配,版本一错,要么编译报一堆看不懂的错误,要么模拟器直接起不来。我那天印象最深的是签名配置——没有配置签名,应用装不上真机,模拟器上也跑不了调试。训练营里有一大半人卡在这里,卡了一个小时以上的大有人在。
Day2 到 Day3 集中搞 ArkTS 语言基础。ArkTS 是 TypeScript 的超集,但又做了严格的裁剪和约束。如果之前写过 TS,上手会快一些,但千万别以为完全一样——后面我会专门讲它的几个容易踩坑的地方。Day4 到 Day5 进入 ArkUI 声明式 UI,这是第一阶段的核心,也是很多人第一次接触"用状态驱动界面"的写法,思维转变需要一点时间。Day6 讲应用模型,理解 Stage 模型和生命周期。到了 Day7,也就是今天,做的事就是把前面这些东西连成一条线。
1.2 学习内容的金字塔结构
复盘的时候我习惯画结构图。第一阶段的知识点其实是一个三层金字塔:
- 底层是语言:ArkTS。所有 UI、逻辑、数据处理都建立在这层上,语言不熟,后面全是空中楼阁。
- 中层是 UI 框架:ArkUI。它决定了你怎么描述界面、怎么处理布局、怎么响应交互。
- 上层是应用模型:Stage 模型。它管的是应用进程怎么启动、页面怎么挂载、任务怎么切换。
用一个类比说:ArkTS 是砖瓦和水泥,ArkUI 是施工图纸,Stage 模型是整个施工队的组织方案。砖瓦质量不过关,图纸画得再好也盖不出好房子;图纸画得再精细,施工队不按工序来,房子照样塌。三层各有分工,但缺一层都不行。
复盘的时候建议也按这个三层结构去整理自己的笔记。如果你自己画不出这张图,说明某些层的知识还是"单点记忆"状态,没有形成体系。这是复盘最重要的产出:不是记住某个函数怎么写,而是能说出这个知识在系统里的位置,以及它上下游分别是谁。
2. ArkTS与ArkUI:第一阶段最核心的两个坎
2.1 ArkTS不是"另一个TypeScript"
训练营里第一天接触 ArkTS 的时候,很多熟悉 TS 的朋友会觉得"这不过就是 TS 换个名字"。实际写起来发现,ArkTS 比 TS 严格不少,这种严格是有意为之的。
首先,ArkTS 禁止了 any 类型。在普通 TS 里,遇到一时定不准的类型,很多人习惯先用 any 顶着,ArkTS 里直接编译报错。一开始会觉得烦,但好处也很明显:类型在编译期就被卡死了,大量运行期崩溃提前暴露。训练营里有个同学写了一个数据处理函数,参数类型用了 any,编译直接不给过,他被迫把接口和联合类型定义清楚,结果这个函数后来在别的地方被调用时一次都没出错过。
另一个 ArkTS 的核心特点是装饰器体系。@Entry、@Component、@State、@Prop、@Link 这些装饰器看着像魔法,本质上是框架层的标记:编译器看到这些标记,就知道哪些类是页面组件、哪些变量是响应式状态、哪些数据需要和父组件同步。理解这一点很重要——装饰器不是语言自己凭空造出来的语义,是框架约定好的规则。
在使用上有几个注意事项:
- @Entry 装饰的组件是页面入口,一个页面文件里只能有一个 @Entry,别手滑写两个。
- @State 装饰的变量必须显式声明类型,不能靠推断,否则可能触发编译约束错误。
- 对象字面量必须对应显式声明的接口或类,不能随手写一个匿名对象传给某个函数。
这些严格限制在学习阶段会让人很不适应,但训练营里反复强调一个观点:宁可编译期多报几个错,也不要在运行期去猜问题。这一点我实际写下来是认同的,尤其在项目规模变大以后,编译期的严格约束能帮你拦下一大批低级错误。
2.2 声明式UI的思维转变:状态驱动视图,而不是人肉操作视图
如果说 ArkTS 是语法门槛,那 ArkUI 的声明式写法就是思维门槛。
传统命令式写界面是这样的:拿到一个文本控件,调用 setText 改内容;拿到一个列表控件,调用 addItem 加一条数据。每次界面要变,你都得找到对应的控件对象,手动调用方法更新。这种方式在小界面里没问题,一旦界面复杂,状态一变,你要手动同步的位置可能十几个,漏掉一个就是 bug。
ArkUI 的声明式写法换了一个思路:你描述"界面长什么样",并且告诉框架"哪些数据是响应式的"。当数据变化时,框架自己找到依赖这些数据的视图,自动局部刷新。你不再手动操作视图对象,只需要管理数据。
我习惯用一个"感应灯"的类比解释这个转变:命令式像是你走到每个开关前手动开灯,声明式像是装了感应器,你走到哪个区域,哪个灯自己亮。你只关心"人在哪"(状态),不用关心"灯怎么亮"(视图更新)。
实操中的关键点是状态粒度。你用 @State 装饰的变量变化了,框架会刷新所有依赖它的组件。如果整个页面只有一个巨大的 @State 对象,任何一个字段变化都会导致大片界面重建,性能自然差。训练营的练习项目里,有人把整个列表数据放在一个 @State 大对象里,每次勾选一条待办,整个列表都闪一下,就是这么来的。
正确做法是把状态拆分到合适的粒度,配合组件化:一个组件管自己的状态,父组件只传它需要的数据。这样更新范围最小、性能最好。这个"状态粒度"的意识,是第一阶段最值得养成的习惯之一。
2.3 组件通信与复用:从单向数据流到跨层状态
组件化之后,紧接着的问题就是组件之间怎么传数据。第一阶段训练营里涉及的主要是三种场景:父子组件通信、兄弟组件通信、跨多层组件共享状态。
父子通信最简单的是 @Prop:父组件传数据给子组件,子组件不能反向修改父组件的数据。这是单向数据流,最容易理解和排查。需要双向同步的场景用 @Link:子组件里修改了变量,父组件里对应数据也会变。不过我的建议是能不用 @Link 就不用,数据流越单向,逻辑越清晰。训练营里有个练习,父子组件共享一个编辑状态,用 @Link 实现了,但后来需求一改,父子之间的联动逻辑变得非常绕。改成统一的父级状态管理后,问题一下就简单了。
跨层共享状态用 @Provide / @Consume,这类装饰器让深层嵌套的组件可以直接消费祖先组件提供的数据,不用一层一层传 props。这有点像依赖注入的思路:某个组件需要什么,直接从上下文里拿,而不是靠上层手动传参。
几个容易踩的点:
- @Link 接收的必须是变量引用,不能传字面量,比如 @Link text: string = 'hello' 这种方式就不对,必须从父组件传入可同步的源。
- 修改对象内部属性不一定触发状态刷新。@State 监听的是变量引用的变化,如果你用 stateObj.name = 'x' 这种方式改对象属性,视图不一定会更新。正确做法是新建一个对象重新赋值,或者使用框架提供的方法触发更新。
- @Provide 和 @Consume 必须成对出现,而且 key 要对得上,否则子组件拿到的是 undefined,排查这类问题最容易忽略的就是 key 拼写不一致。
3. 跨平台开发的底层理解:Stage模型与一次开发多端适配
3.1 Stage模型:应用从启动到页面的完整链路
第一阶段最后两天进入应用模型的内容,这一块抽象程度比 UI 高不少,很多同学学到这里开始掉队。但偏偏这块又是跨平台开发绕不开的基础——不理解应用模型,你就不理解你写的代码到底是怎么跑起来的。
Stage 模型里我梳理下来要掌握的核心概念是这几个:UIAbility 是带界面的能力组件,一个应用可以有一个或多个 UIAbility;WindowStage 是窗口的舞台,负责创建和加载窗口;页面(也就是 @Entry 装饰的组件)最终是挂载在窗口里的。
启动流程顺着时间线走一遍就清楚了:应用进程启动,系统创建 UIAbility 实例,触发 onCreate;然后创建 WindowStage,触发 onWindowStageCreate;窗口创建好之后,再加载页面内容,页面才呈现在屏幕上。之后应用切到后台、回到前台,分别触发 onBackground 和 onForeground。
这些生命周期函数一开始写项目时可能用不太上,但排查问题的时候非常关键。训练营里有个同学做的应用,冷启动偶尔白屏,当时所有人都去查页面代码,查了半天没结果。后来把生命周期日志打出来才知道,问题出在 onWindowStageCreate 里加载了一个占内存很大的资源,导致窗口创建和页面加载之间卡了太久。如果不懂这条启动链路,这种问题基本无从下手。
3.2 跨平台适配的三种思路
"跨平台开发"这个名字很容易让人误解,以为是一套代码通吃所有设备。实际上的跨平台,更多是"一次开发,多端适配"——逻辑代码尽量复用,界面在多端跑起来但表现可能不同。
第一阶段训练营里讲的跨平台适配,核心是三件事:尺寸适配、布局适配、资源差异化。
尺寸适配用的是 vp 单位,它是一种虚拟像素单位,跟屏幕物理像素解耦。类似传统移动开发里的 dp 概念——这样同一套尺寸描述在不同分辨率的屏幕上能得到一致的视觉效果,而不是出现小屏手机上看不清、大屏平板上又过大的问题。
布局适配靠栅格系统和媒体查询。栅格系统把屏幕宽度分成若干列,不同断点下组件占据的列数不同,实现"窄屏堆叠、宽屏分栏"的效果。媒体查询用来感知窗口宽度的变化,横竖屏切换、窗口拉伸时可以让布局做出相应调整。训练营里做了一个示例:同一个页面在手机上是单列列表,在折叠屏展开后自动变成双列网格,用的就是栅格断点,没写任何平台判断代码。
资源差异化相对直接一些:不同设备类型加载不同目录下的同名资源文件,代码里不用判断设备类型,系统自动按设备能力加载合适的那份。
在这一块我强烈的建议是:从第一天写页面开始就保持"逻辑与视图分离"的习惯。把数据处理、状态管理、业务流程写在独立的层里,UI 组件只负责渲染和交互,不要混在一起。哪怕现阶段不跨端,这种分层也能让单端代码更清爽、更好测试。等真需要多端时,你会感谢自己当初分得干净。
4. 实战项目复盘:模拟项目X从零到一的踩坑记录
4.1 一个典型的阶段实战项目是怎么拆解的
训练营第一阶段的实战项目是一个待办事项应用,我们就叫它模拟项目X。功能简单直接:能添加待办、能标记完成、能按状态筛选、能本地保存。项目虽然不大,但把第一阶段的核心知识点全用上了。
拿到需求先别急着写代码,拆解是第一步。这是我反复强调的:需求拆得越清楚,写代码越省事。
模拟项目X拆下来大概是这样的:
- 页面结构:主页面包含列表区、输入区、筛选切换区。
- 数据模型:TodoItem,字段包括 id、title、done。
- 状态管理:用 @State 管理待办数组,筛选状态单独用一个变量控制。
- 本地持久化:简单存储方案,把待办列表序列化后存下来,启动时读取。
- 交互逻辑:添加、切换完成状态、切换筛选条件。
每个模块都能对应到前面章节的知识点。数据模型对应 ArkTS 的接口和类定义,状态管理对应 @State 和数组更新方法,页面结构对应 ArkUI 的组件和布局,持久化对应框架自带的存储能力。
拆解完之后,我才开始按模块逐个实现。这个过程中的每一步,都在验证前面学的东西是不是真会了——写不出来,那就是知识有缺口,正好补上。
4.2 复盘时整理的典型报错与排查思路
模拟项目X做完之后,我没有急着做下一个功能,而是把整个过程中遇到的所有报错和问题全部翻出来,重新整理了一遍。这一步价值极大。
下面是我复盘时列出的几个典型案例:
| 问题现象 | 根本原因 | 解决方式 |
|---|---|---|
| 编译报错,对象字面量不符合类型要求 | ArkTS 要求对象字面量必须对应显式的接口或类 | 给数据显式声明 interface 或 class,不要靠推断 |
| 修改数组里某一项的 done 值,界面没刷新 | 直接改了对象属性,@State 监听的是数组引用变化 | 用新数组替换旧数组,例如先拷贝再修改后整体赋值 |
| 模拟器上应用启动白屏 | 启动阶段加载了过重资源,阻塞了窗口创建和页面挂载 | 把资源加载放到页面级别异步处理,减少 onWindowStageCreate 里的同步操作 |
| 真机调试一直装不上应用 | 签名配置不正确 | 检查设备管理、签名证书与项目配置的匹配关系 |
| 路由跳转找不到目标页面 | 页面没有按规范声明相关配置 | 检查页面配置信息,确认路由路径一致 |
这些问题的共同特点就是:报错信息给得很明确,但如果不理解底层机制,看到了也反应不过来。比如数组更新那个问题,如果你不知道 @State 监听的是引用地址,看到"数据变了界面不刷新"就只能瞎猜。理解状态管理的原理之后,这个问题的答案几乎就是透明的。
4.3 复盘的一个独门技巧:错题本思维
给训练营做复盘时我把一个自己的习惯拿出来分享:给每个报错建立一个条目,记录四件事——报错信息是什么、触发场景是什么、根本原因是什么、怎么解决的。
刚开始有人觉得这太费时间,但实际用下来,这个"错题本"的价值在第二阶段会成倍放大。因为很多报错不会只出现一次。比如"数据变了界面不刷新"这类问题,几乎每个做 UI 开发的人两周内都会再遇到一次。有文字记录,翻一眼就能定位;没有记录,又得从头排查一遍。
做错题本还有另一个隐藏好处:记录本身会强迫你真正搞懂问题的原因。因为你不可能在纸上写清楚一个你自己都没理解透的问题。这是个良性循环。
5. 第一阶段复盘后的方向:下一阶段往哪走
5.1 从"会用"到"理解":深入组件机制与状态管理
第一阶段的目标是能独立写出一个页面、管理好状态、把应用跑起来。达成这个目标之后,第二阶段建议往"理解机制"的方向走,不要停留在"能跑就行"的层面。
具体可以做的事情有几个方向:深入看 ArkUI 渲染流程,理解状态变更到界面刷新的内部过程;研究自定义封装的正确姿势,把重复出现的 UI 抽成可复用组件;把复杂状态管理方案跟目前的 @State 体系做对比,判断各自适合什么规模的项目。
我比较推荐的方式是给自己设定一个小目标:把一个常用组件用自己的理解重新封装一遍,再去对照框架自带实现的思路。这个过程会逼你从使用者变成设计者。
5.2 学习复盘中最实用的一招:费曼学习法
说到复盘,最朴素也最有效的方法不是我前面说的错题本,而是"讲给别人听"。训练营第七天下午安排了分组答疑,每人轮流把自己理解的 Stage 模型讲给小组其他人听。这个环节看着简单,实际效果极其惊人——有人觉得自己懂了,一开口发现连 UIAbility 和 WindowStage 的关系都说不利索。
这就是费曼学习法:如果你不能用通俗的话把某个知识讲清楚,那就是没真懂。复盘的产出不应该是漂亮的笔记,而应该是"我能讲清楚几件事"。
所以我给训练营同学的课后建议是:找个人,或者对着空气,把这周学到的东西从头讲一遍。卡住的地方就是知识体系里的漏洞,记录下来,它就是下一阶段的第一批学习任务。
个人体会是,训练营前六天大家学的都是同样的内容,真正拉开差距的就是第七天这类复盘日:有人只是跟着节奏走了一遍,有人借复盘把零散的知识织成了网。网织好了,后面的路才会越走越顺。