#星光不负 码向未来#从安卓到鸿蒙:一个开发者的“破茧”与重生 原创

八门遁甲七巧板
发布于 2025-10-18 23:42
浏览
1收藏

@[toc]

引言:我的鸿蒙“初印象”

作为一名浸淫安卓开发8年的“老炮儿”,我对鸿蒙的最初认知,停留在2021年朋友圈里的一句调侃——“这不是安卓套壳吗?”。彼时我正为安卓的多设备协同头疼:客户要做一个“手机控制智能家电”的功能,我得用Socket写跨设备通信,还要处理不同设备的兼容性,折腾了一个月才勉强跑通。当领导扔来“调研鸿蒙”的任务时,我心里直犯嘀咕:“国产系统能比安卓强?无非是借‘国产’噱头割韭菜罢了。”

直到2024年3月的一个深夜,我抱着“应付任务”的心态打开DevEco Studio,写下第一行鸿蒙代码:

@Entry
@Component
struct HelloHarmony {
  @State message: string = 'Hello HarmonyOS'
  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
      }
    }
  }
}

编译运行后,屏幕上弹出一行清晰的文字——没有XML布局,没有findViewById,甚至没有Activity!我突然意识到:鸿蒙不是安卓的“换皮”,而是一套全新的声明式UI框架。那个深夜,我对着屏幕坐了很久,第一次对“鸿蒙”这两个字产生了好奇。

破冰之旅:从“抵触”到“沉迷”的认知转折

真正让我“入坑”的,是一次分布式购物车的Demo演示。2023年5月,我参加鸿蒙开发者社区的线上沙龙,讲师用三行代码实现了“手机加商品、平板同步购物车、手表显示数量”的功能——没有复杂的Socket通信,没有繁琐的跨设备适配,只需要调用鸿蒙的@DistributedData装饰器:

@DistributedData
@State cart: Array<Goods> = []

当讲师点击手机上的“添加商品”,平板和手表的购物车实时更新时,我彻底坐不住了。我突然想起客户的“智能家电控制”需求——如果用鸿蒙的分布式能力,我根本不用写那些绕人的通信代码!

那天晚上,我熬夜看了鸿蒙的《分布式能力开发指南》,凌晨三点给领导发了条消息:“这个项目,我想用鸿蒙做。”

第一章:系统性学习之路——从0到1的“爬坡”

学习路径:用“三步法”搞定鸿蒙入门

我把学习鸿蒙的过程总结为“概念扫盲→Demo练手→项目实战”:

  1. 基础概念关:先啃官方文档的《鸿蒙操作系统核心概念》,重点理解“分布式软总线”(多设备通信的底层协议)、“声明式UI”(用代码描述UI状态)、“ArkTS”(TypeScript的鸿蒙扩展)三个核心概念;
  2. Demo练手关:跟着鸿蒙开发者学院的《ArkUI实战》视频,每节课写一个小Demo——从“登录页面”到“列表组件”,再到“弹窗交互”,逐个攻克UI开发的基础;
  3. 项目实战关:用鸿蒙做了一个“待办事项App”,覆盖“添加/删除/标记完成”三个核心功能,重点练习状态管理数据驱动视图

攻克“拦路虎”:状态管理的“血泪史”

我学习时遇到的第一个“大坑”,是状态变量的传递逻辑。一开始,我完全搞不懂@State@Link@Provide的区别。比如我写了一个“待办项子组件”,想让子组件修改父组件的待办列表,结果用@State传递变量后,父组件的状态根本没变化!

后来我写了5个测试Demo,终于理清了规则:

  • @State:组件内部的状态,修改会触发自身UI更新;
  • @Link:子组件引用父组件的@State变量,实现双向绑定
  • @Provide/@Consume:跨多层组件的状态传递,类似“上下文”。

比如下面这个Demo,子组件修改count,父组件的count会同步更新:

// 父组件
@Entry
@Component
struct Parent {
  @State count: number = 0
  build() {
    Column() {
      Text(`父组件Count:${this.count}`)
      Child({ count: $count }) // 用$符号传递@State变量
    }
  }
}

// 子组件
@Component
struct Child {
  @Link count: number // 引用父组件的@State变量
  build() {
    Button('子组件+1')
      .onClick(() => this.count++)
  }
}

当我点击子组件的按钮,父组件的count从0变成1——那一刻,我终于懂了:状态管理的核心是“数据的流向”,而不是“变量的类型”。

AHA时刻:原来声明式UI是“懒人的福音”

我对声明式UI的“顿悟”,来自一个“动态列表”的需求。用安卓写动态列表,我需要:

  1. 写XML布局(ListView);
  2. 写Adapter(处理数据和视图的绑定);
  3. 在Java里请求网络数据;
  4. 数据回来后调用notifyDataSetChanged()更新列表;
  5. 处理“加载中/成功/失败”三种状态的视图切换。

但用鸿蒙的ArkUI,代码是这样的:

@Entry
@Component
struct DynamicList {
  @State data: Array<string> = []
  @State loading: boolean = false
  @State error: string = ''

  build() {
    Column() {
      // 根据状态显示不同视图
      if (this.loading) Progress()
      else if (this.error) Text(this.error)
      else List() {
        ForEach(this.data, (item) => ListItem() { Text(item) })
      }
    }
    .onAppear(() => {
      this.loading = true
      // 网络请求
      fetch('https://api.example.com/data')
        .then(res => res.json())
        .then(data => { this.data = data; this.loading = false })
        .catch(err => { this.error = err.message; this.loading = false })
    })
  }
}

没有XML,没有Adapter,甚至没有notifyDataSetChanged()——我只需要维护loadingerrordata三个状态,UI会自动根据状态变化更新。那一刻,我突然明白:声明式UI的本质,是“让开发者只关心数据,不关心视图”。这对安卓开发者来说,简直是“解放双手”的福音!

第二章:技术干货沉淀——深入解析ArkUI声明式UI范式

作为安卓开发者,我对UI开发的痛点太清楚:XML繁琐、数据绑定麻烦、跨设备适配难。而ArkUI声明式UI,正好解决了这些痛点。接下来,我从“是什么、为什么、怎么用、常见坑”四个维度,彻底讲透ArkUI。

1. 它是什么:声明式UI的“鸿蒙表达”

ArkUI是鸿蒙的UI开发框架,基于声明式语法TypeScript扩展(ArkTS),核心思想是:描述UI的最终状态,由框架处理中间过程

简单来说,你要写一个按钮,只需要告诉框架:“这个按钮的文字是‘点击我’,点击后执行onClick函数”,不需要关心按钮的绘制、触摸事件的处理——这些都由ArkUI框架完成。

2. 为什么需要它:对比安卓的“命令式UI”

我用“登录页面”的例子,对比ArkUI和安卓的写法:

安卓(命令式)

  • 写XML布局(login.xml);
  • findViewById绑定视图;
  • 手动处理输入框的文本变化。
<!-- login.xml -->
<LinearLayout>
  <EditText id="@+id/et_username" hint="用户名"/>
  <EditText id="@+id/et_password" hint="密码" inputType="password"/>
  <Button id="@+id/btn_login" text="登录"/>
</LinearLayout>
// LoginActivity.java
public class LoginActivity extends AppCompatActivity {
  private EditText etUsername;
  private EditText etPassword;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.login);
    etUsername = findViewById(R.id.et_username);
    etPassword = findViewById(R.id.et_password);
    Button btnLogin = findViewById(R.id.btn_login);
    btnLogin.setOnClickListener(v -> {
      String username = etUsername.getText().toString();
      String password = etPassword.getText().toString();
      // 处理登录
    });
  }
}

鸿蒙(声明式)

  • 用ArkTS写UI,数据和视图直接绑定;
  • 输入框的文本变化自动同步到变量;
  • 不需要findViewById
@Entry
@Component
struct LoginPage {
  @State username: string = ''
  @State password: string = ''

  build() {
    Column({ space: 16, padding: 16 }) {
      TextInput({ placeholder: '用户名' })
        .onChange(value => this.username = value)
      TextInput({ placeholder: '密码', type: InputType.Password })
        .onChange(value => this.password = value)
      Button('登录')
        .width('100%')
        .onClick(() => console.log(`用户名:${this.username},密码:${this.password}`))
    }
  }
}

对比结论
ArkUI的优势在于“简洁、高效、数据驱动”——你不需要写冗余的XML和绑定代码,只需要维护数据状态,UI会自动更新。

3. 怎么用:从“基础组件”到“复杂交互”

接下来,我用一个“带筛选的商品列表”,演示ArkUI的核心用法。

需求说明

  • 顶部有“筛选”按钮,点击弹出筛选面板;
  • 筛选面板有“价格升序”“销量降序”两个选项;
  • 选择筛选条件后,商品列表自动排序。

核心代码解析

// 商品类型定义
interface Goods { name: string; price: number; sales: number }

@Entry
@Component
struct FilteredList {
  // 商品数据
  @State goods: Goods[] = [
    { name: '手机', price: 2999, sales: 1000 },
    { name: '平板', price: 1999, sales: 500 },
    { name: '手表', price: 999, sales: 2000 }
  ]
  // 筛选类型:0-默认,1-价格升序,2-销量降序
  @State filterType: number = 0
  // 是否显示筛选面板
  @State showFilter: boolean = false

  build() {
    Column() {
      // 筛选按钮栏
      Row({ justifyContent: FlexAlign.End, padding: 16 }) {
        Button('筛选')
          .onClick(() => this.showFilter = !this.showFilter)
      }

      // 筛选面板(弹出层)
      if (this.showFilter) {
        Panel({ type: PanelType.Foldable, title: '筛选条件' }) {
          Column({ space: 12, padding: 16 }) {
            // 价格升序选项
            Radio({ value: 'price', group: 'filter' })
              .checked(this.filterType === 1)
              .onChange(checked => checked && (this.filterType = 1))
            Text('价格升序')
            // 销量降序选项
            Radio({ value: 'sales', group: 'filter' })
              .checked(this.filterType === 2)
              .onChange(checked => checked && (this.filterType = 2))
            Text('销量降序')
          }
        }
        .width('80%')
        .onDismiss(() => this.showFilter = false)
      }

      // 商品列表(根据筛选条件排序)
      List({ space: 10, padding: 16 }) {
        ForEach(this.getFilteredGoods(), item => {
          ListItem() {
            Column({ space: 8 }) {
              Text(item.name).fontSize(18)
              Text(`价格:${item.price}元`).color('#999')
              Text(`销量:${item.sales}件`).color('#999')
            }
            .padding(12)
            .backgroundColor('#f5f5f5')
          }
        })
      }
    }
  }

  // 根据筛选类型排序商品
  getFilteredGoods(): Goods[] {
    switch (this.filterType) {
      case 1: return [...this.goods].sort((a, b) => a.price - b.price)
      case 2: return [...this.goods].sort((a, b) => b.sales - a.sales)
      default: return this.goods
    }
  }
}

代码逻辑拆解

  1. 状态定义:用@State定义goods(商品数据)、filterType(筛选类型)、showFilter(是否显示筛选面板)三个状态变量;
  2. UI结构
    • 顶部筛选按钮:点击切换showFilter状态;
    • 筛选面板:用Panel组件实现弹出层,里面用Radio组件选择筛选类型;
    • 商品列表:用List组件渲染商品,ForEach循环遍历排序后的商品数据;
  3. 数据处理getFilteredGoods方法根据filterType对商品排序,返回新数组;
  4. 交互逻辑:选择筛选类型→filterType变化→getFilteredGoods重新计算→商品列表自动更新。

运行效果

  • 初始状态:显示默认排序的商品列表;
  • 点击“筛选”:弹出筛选面板;
  • 选择“价格升序”:商品按价格从低到高排序;
  • 选择“销量降序”:商品按销量从高到低排序。

4. 常见“坑”点与最佳实践

我在写ArkUI时踩过很多坑,总结了以下几点:

  • 坑1:忘记写build()方法:ArkUI组件必须有build()方法,否则编译报错;
  • 坑2:@State变量赋值错误@State变量不能直接赋值为“对象属性”(比如@State price: number = goods[0].price),要在onAppear里赋值;
  • 坑3:@Link引用错误@Link必须引用父组件的@State变量,不能引用普通变量;

最佳实践

  1. interface定义数据类型,让数据结构更清晰;
  2. 将复杂逻辑封装成方法(比如getFilteredGoods),避免build()方法过于臃肿;
  3. 测试状态变化:每写一个状态变量,都要测试修改后UI是否更新。

第三章:社区温度——一群人的“鸿蒙之路”

2023年10月,我参加了**鸿蒙开发者大会(HDC)**的线下活动。那是我第一次见到这么多鸿蒙开发者:有刚毕业的大学生,有从iOS转型的工程师,还有做智能硬件的创业者。我们围坐在一起,讨论ArkUI的状态管理、分布式能力的应用场景,甚至一起解决某个开发者遇到的“跨设备通信失败”问题。

最让我感动的是一个大三学生的分享:他用鸿蒙做了一个“老人智能助手”——老人在手表上按紧急按钮,手机会自动拨打子女电话并发送位置。他说:“鸿蒙的分布式能力让我不用写复杂的通信代码,就能实现多设备联动,这是安卓做不到的。”

那次活动后,我加入了鸿蒙开发者社区的“北京群”。群里每天都有开发者问问题,比如“ArkUI的List怎么加分割线?”“分布式数据管理怎么用?”,总有热心人解答,甚至直接贴代码示例。我也开始分享自己的经验,比如“状态管理的常见问题”“ArkUI的最佳实践”——我突然意识到,鸿蒙的社区不是“冷清的论坛”,而是“温暖的大家庭”。

结语:从“安卓开发者”到“鸿蒙开发者”的成长

从2023年春天到2024年春天,我用了一年时间,完成了从“安卓老炮”到“鸿蒙开发者”的转型。这一年里,我学会了ArkTS语法,掌握了ArkUI声明式UI,用鸿蒙做了3个项目——其中一个“全屋智能控制App”,帮客户节省了50%的开发时间,还获得了公司的“技术创新奖”。

现在,我对鸿蒙的认知早已不是“套壳系统”,而是“面向未来的分布式操作系统”。它解决了安卓和iOS无法解决的问题:多设备联动、跨平台适配、简洁的UI开发。我相信,随着鸿蒙生态的发展,会有越来越多的开发者加入,一起构建“万物互联”的未来。

下一步,我的计划是:

  1. 学习鸿蒙的分布式软总线技术,做一个“多设备协同办公”App;
  2. 参与鸿蒙开源项目,为社区贡献代码;
  3. 写一本《ArkUI开发实战》的书,帮助更多开发者入门鸿蒙。

最后,我想对犹豫是否学习鸿蒙的开发者说:“不要用旧眼光看新事物。鸿蒙不是安卓的对手,而是未来的方向——越早加入,越能占得先机。”

愿我们都能在鸿蒙的世界里,找到属于自己的“破茧”与重生。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
1
收藏 1
回复
举报
1条回复
按时间正序
/
按时间倒序
八荒六合唯我独秀
八荒六合唯我独秀

不容易啊兄弟。。。还好你这都过来了。

回复
2025-10-18 23:46:45
回复
    相关推荐