【成长纪实】跨越“舒适区”的鸿沟:一个 5 年 Android 开发者的鸿蒙转型“阵痛”与“重生”!
当一个在 Java 和 Kotlin 的“舒适区”里待了五年的 Android 开发者,突然被推到 HarmonyOS NEXT 和 ArkTS 的浪潮面前时,他经历的绝不仅仅是学习一门新语言,而是一场近乎“推倒重建”的思维革命。本文将以第一人称,真实记录我——一个传统 Android 开发者,在近三个月学习鸿蒙开发的心路历程。面对“纯血”鸿蒙的焦虑,以及对“声明式UI”的天然抗拒。详述我在学习
大家好,我是[晚风依旧似温柔],新人一枚,欢迎大家关注~
本文目录:
摘要
当一个在 Java 和 Kotlin 的“舒适区”里待了五年的 Android 开发者,突然被推到 HarmonyOS NEXT 和 ArkTS 的浪潮面前时,他经历的绝不仅仅是学习一门新语言,而是一场近乎“推倒重建”的思维革命。本文将以第一人称,真实记录我——一个传统 Android 开发者,在近三个月学习鸿蒙开发的心路历程。
我将毫无保留地分享我所经历的三个阶段:
- “抵触与迷茫”: 面对“纯血”鸿蒙的焦虑,以及对“声明式UI”的天然抗拒。
- “阵痛与攻坚”: 详述我在学习 ArkTS 时遇到的三大“拦路虎”——从命令式到声明式的“UI思维”转变、全新的状态管理(
@State/@Link)以及对 Ability 生命周期的重新认知。 - “顿悟与新生”: 当我写出第一个“元服务”卡片并实现“跨设备流转”时的“Aha Moment”。
这不是一篇技术教程,而是一份“踩坑日记”和“避坑指南”。我希望用我的真实经历,为那些同样站在转型路口、感到迷茫的 Android/iOS 同行们,点亮一盏“星光”,我们一起在鸿蒙生态中找到新的坐标。
一、 缘起:一个“老”Android 程序员的“中年危机”
大家好,我是一名坐标杭州的开发者。如果从 2018 年研究生毕业算起,我已经在 Android 开发这个岗位上干了快 6 年。
我的日常工作,就是和 Java、Kotlin、XML、Jetpack 全家桶打交道。我熟悉 Activity 的四种启动模式,我能熟练地处理 Fragment 的各种诡异生命周期,我甚至闭着眼睛都能写出一个 RecyclerView 的 ViewHolder。
我以为我能在这条路上一直安稳地走下去。直到 2024 年初,“HarmonyOS NEXT”和“纯血鸿蒙”这些词开始刷屏。
起初,我是不屑一顾的。
“不就是个套壳 Android 吗?换汤不换药。”
“又要造轮子?先把生态做起来再说吧。”
“学不动了,Kotlin 的协程我还没玩明白呢。”
但很快,我发现我错了。当公司宣布成立“鸿蒙先锋团队”,当招聘软件上“鸿蒙/ArkTS”岗位的 JD(职位描述)开始暴增,当技术群里讨论的不再是 Jetpack Compose 而是 ArkTS 时,一种真切的焦虑感袭来。
我意识到,这可能不是一次“小升级”,而是一次“大迁徙”。
我所在的“舒适区”——那个由 Java 和 XML 构建的、我经营了五年的“城堡”——正在变得“摇摇欲坠”。我不是怕被淘汰,我是怕**“错过”**。
怀着这种复杂的心情,我(被迫)成为了团队里第一批“吃螃蟹”的人,开始了我的鸿蒙转型之路。而我遇到的第一个“敌人”,就是 ArkTS。
二、 阵痛期(上):从“命令式”到“声明式”的思维“骨折”
作为 Android 开发者,我们的思维是**“命令式”**的。
- 我想改变一个文?
textView.setText("Hello")。 - 我想隐藏一个按?
button.setVisibility(View.GONE)。 - 我想给列表加数据?
adapter.notifyDataSetChanged()。
我们习惯了“获取控件实例(findViewById)”,然后“调用方法去命令它”。
但 ArkTS 和 ArkUI,是**“声明式”**的。
我至今还记得我写第一个页面时的“抓狂”。
我的需求很简单:点击一个按钮,让底下的文本从“Hello”变成“World”。
在 ArkTS 中,我发现我根本拿不到那个 Text 组件的“实例” 中,我发现我根本拿不到那个 Text 组件的“实例”!
// 我最初的、错误的 Android 思维代码
@Entry
@Component
struct Index {
// 我以为这是我的 TextView
private textComponent: Text = Text('Hello');
build() {
Column() {
Button('Click Me')
.onClick(() => {
// 错误!ArkUI里没有 .setText() 这种东西!
// this.textComponent.setText('World');
// 我该怎么办?我怎么“命令”那个Text组件改变?
})
this.textComponent // 把组件实例放在这里?
}
}
}
我对着模拟器抓耳挠腮了半个小时。我无法理解,没有“实例”,我怎么“控制”UI?
这就是转型的第一个“大坑”:思维模式的“骨折”。
- 命令式(Android): 你(开发者)是“指挥官”,UI(View)是“士兵”。你必须精确地告诉每个士兵(
findViewById)在什么时候(onClick)做什么事(setText)。 - 声明式(ArkUI): 你(开发者)是“状态描述者”,UI是“状态的映射”。
【我的顿悟时刻】
直到我被导师点拨,重写了代码:
@Entry
@Component
struct Index {
// 1. 我不关心“Text组件”本身
// 2. 我只关心“文本内容”这个“状态(State)”
@State private message: string = 'Hello'; // 用 @State 装饰
build() {
Column() {
Button('Click Me')
.onClick(() => {
// 3. 我不“命令”UI,我只“改变”状态
this.message = 'World';
// 4. ArkUI框架会“自动”监听到 message 的变化,
// 并“智能”地重绘(rebuild)Text组件
})
Text(this.message) // 5. UI 永远只是“忠实地”反映“状态”
.fontSize(30)
}
}
}
当我点击按钮,模拟器上的文字真的变了。那一刻,我才真正理解了“声明式”的含义:开发者是“操作工”,而是“数据管理员”。我们只负责管理数据(状态),UI 会自动响应。
这个转变是痛苦的,但一旦转过来,我就感受到了它的“香”——我再也不用写 findViewById 了!我再也不用担心 ViewHolder 的复用了!我再也不用手动管理 UI 的各种状态了!
三、 阵痛期(下):攻坚“状态管理”与bility生命周期”
如果说“声明式UI”是第一道坎,那鸿蒙的“状态管理”和“生命周期”就是第二座大山。
1. “抓狂”的状态管理:@State、@Link、@Prop
刚学会了 @State,我又遇到了新问题。
场景: 我把 Index 页面里的 Text 组件,封装成了一个“子组件” MyText。
// 父组件
@Entry
@Component
struct Index {
@State private message: string = 'Hello';
build() {
Column() {
Button('Click Me').onClick(() => { this.message = 'World'; })
// 我把 Text 封装了
MyText({ content: this.message })
}
}
}
// 子组件
@Component
struct MyText {
// 【坑点1】如果我这里什么都不加
private content: string;
// 【坑点2】如果我这里也用 @State
// @State private content: string; // 这会导致数据“单向”传递
build() {
Text(this.content)
}
}
- 踩坑(一): 我发现,父组件的
message变了,子组件的content不会自动更新! - 踩坑(二): 我又给子组件加上了
@State。这次父组件变了,子组件会跟着变。但如果我在子组件内部(比如MyText自己也有个按钮)改变了content,父组件的message不会变。数据流是的!
我彻底晕了。这和我熟悉的 Java 传参、Kotlin 的 ViewModel 完全不同。
【我的学习(避坑指南)】
我花了整整两天,才彻底搞懂了这几个“装饰器”的真正用途,它们是 ArkUI 数据流的“灵魂”:
@State: “状态机”。用于组件内部的、私有的状态。它是“数据源头”。(比如Index里的message)。@Prop: “单向绑定”。用于父组件向子组件传递数据。父组件的@State变,子组件的@Prop会跟着变。(MyText应该用@Prop content: string)。@Link: “双向绑定”。这是最强大的。如果父组件用@State,子组件用@Link承接,那么无论哪一边改变了数据,另一边都会同步更新。这对于封装“输入框”这类组件(子组件要能修改父组件的状态)至关重要。@Observed/@ectLink: 用于处理复杂的“对象”或“类”的状态传递(代替@Prop/@Link对基础类型的处理)。@Provide/@Consume: “隔代遗传”。用于A组件向C、D、E等深层子孙组件传递状态,避免B组件做无意义的“中间商”传递。
当我把这张“关系网”理清后,我写 UI 的思路瞬间清晰了。我不再是“猜”,而是知道在什么场景下,该用哪种“绑定”策略。
2. “陌生”的生命:再见了 Activity,你好 Ability
作为 Android 开发者,Activity 的 onCreate, onStart, onResume, onPause, onStop, onDestroy` 简直是刻在 DNA 里的。
但 HarmonyOS(特指 Stage 模型)完全变了。Ability 的生命周期变成了:onCreate, onWindowStageCreate, onForeground, onBackground, onDestroy。
-
我踩的坑: 我习惯性地在
Ability的onCreate里初始化我的 UI 逻辑、加载数据。 -
结果: 程序崩溃,或者拿不到
Window实例。 -
原因: 在 Stage 模型中,
onCreate时,“窗口” (Window) 还没有准备好! -
正确做法:
onCreate:只做非 UI 的、最基础的数据初始化(比如数据库、网络引擎的单例)。onWindowStageCreate:这是 UI 的“真正入口”。加载 UI 页面 (loadContent)、设置窗口属性等操作,必须在这里做。3onForeground:相当于onResume,代表页面真正可见、可交互了。onBackground:相当于onPause+onStop,代表页面退到后台了。
这个转变,让我学会了必须把“应用逻辑”和“窗口UI逻辑”解耦得更彻底。
四、 蜕变与新生:当我点亮第一个“元服务”
如果说攻克 ArkTS 和 Ability 只是让我“入门”,那么真正让我感到“兴奋”和“重生”的,是当我开始接触鸿蒙的“灵魂”——**元服务(Atomic Service)**时。
在 Android 上,我们也有“小部件”(App Widgets),但说实话,它更像是一个“带图的快捷方式”,交互弱、更新慢、体验割裂。
但在鸿蒙里,“卡片” (FormExtension) 是元服务的“脸面”,是第一入口。
我的练手项目,是一个“每日待办事项”App。按照“成长纪实”的要求,我决定给它加上“元服务”卡片功能。
我再次经历了“阵痛”:
- 踩坑1: 以为卡片和 FA(主应用)是同一个进程。——错!它们是两个独立进程。FA 里的数据变了,卡片不会自动刷新。
- 踩坑2: 试图在卡片上放一个“输入框”。——错!卡片不支持复杂交互,它只支持“信息展示”和“点击跳转”(
postCardAction)。 - 踩坑3 : 如何更新卡片?——必须在 FA 里,主动调用
formProvider.updateForm(formId, ...)来“命令”系统去更新那张卡片。
当我把这些坑都填平后,我实现了一个 2x4 的卡片,它能清晰地显示“今天最重要的 3 件事”。
然后,我尝试了活动(Codelabs)里提到的**“服务流转”**(AbilityContation)。
场景: 我在“平板”的桌面上,看到了这个“待办事项”卡片,我点击了卡片上的“流转”按钮。
魔法发生了:
我口袋里的“手机”瞬间亮屏、解锁,并自动打开了“待办事项”App 的编辑页面!
那一刻,我汗毛倒竖。
我真切地感受到了“超级终端”的魔力。我不再是“一个App在两个设备上分别运行”,而是“一个服务,在两个设备间自由流淌”。
在 Android 上,要实现这个功能,我需要自己搭建服务器、处理 P2P 发现、管理复杂的 Socket 连接……而在鸿蒙上,我只是调用了系统提供的几个API。
五、 结语:拥抱变化,我们都是“逐光者”
回首这三个月,从最初的“抵触”、“看不懂”,到“阵痛”、“踩坑”,再到最后实现“元服务”时的“兴奋”。我最大的感悟是:
我们(老兵)最大的敌人,不是新技术,而是“旧经验”带来的“惯性”。
我们不能总想在 ArkTS 里找 Java 的“影子”,不能总想把 Ability 当成 Activity 来用。鸿蒙不是 Android 的“替代品”,它是一种全新的“范式”。
现在,我不再焦虑了。因为我发现,鸿蒙的生态还很新,它的“最佳实践”还在探索中,它的“天花板”还远未到来。我们这些最早跨越鸿沟的“转型者”,每踩的一个坑,每写的一个元服务,都是在为这个新生态添砖加瓦。
以“星光”为引!如果你也和我一样,是一个正在观望、犹豫、甚至有点“抵触”的传统开发者,别怕!大胆地迈出第一步,去拥抱 ArkTS 和声明式UI。
相信我,当你点亮第一个“元服务”卡片,当你的服务在多设备间流转时,你感受到的,将是久违的、作为一名“开发者”的纯粹快乐与成就感!
共勉!
如果觉得有帮助,别忘了点个赞+关注支持一下~
喜欢记得关注,别让好内容被埋没~
更多推荐


所有评论(0)