在这里插入图片描述

缘起:一次偶然的相遇

大三上学期开学的那个晚上,我在宿舍刷B站,一条关于HarmonyOS开发的视频推送吸引了我。视频里,UP主演示了一个跨手机和平板无缝流转的应用,那种丝滑的体验让我眼前一亮。评论区有人提到"仓颉语言",我当时还以为是造字的那个仓颉,搜索后才发现是华为推出的全新编程语言。

说实话,作为一个学了两年C++和Java的计算机专业学生,我对新语言既好奇又犹豫。好奇的是,这门语言到底有什么特别之处?犹豫的是,我已经在准备秋招实习,还有精力学新东西吗?但年轻人嘛,总是按捺不住折腾的心。第二天早上,我就在实验室电脑上装好了DevEco Studio,开始了我的仓颉学习之旅。

第一个月:环境搭建的"血泪史"

九月的前两周,我几乎都在和开发环境作斗争。第一次安装DevEco Studio时,因为网络问题SDK下载了一整夜。好不容易装好,创建第一个项目又遇到Gradle同步失败。我在GitHub Issues、技术论坛、QQ群里到处求助,终于发现是JDK版本不匹配的问题。

那段时间,舍友都笑我是"环境配置工程师"。但这个过程让我学会了看官方文档、查日志、提问题。我开始明白,编程不只是写代码,环境配置、依赖管理、问题排查同样重要。

// 当终端里终于打印出这行文字时,我激动得想发朋友圈
main() {
    println("你好,仓颉!")
}

虽然只是Hello World,但这行简单的代码背后,是我两周的坚持和十几次重装IDE的经历。

第二个月:语法学习的"啊哈时刻"

十月,我开始系统学习仓颉语法。最开始学类型系统时,可空类型把我搞懵了。为什么要这么麻烦地标注可能为空的变量?我甚至在笔记本上写下"这不是脱裤子放屁吗?"

直到有一天,我在写课程项目时遇到了NullPointerException,程序直接崩了。调试了一个小时才发现是忘记判空。那一刻我突然理解了仓颉的设计哲学——与其运行时崩溃,不如编译期就强制处理。

// 之前的我会这样写(Java风格)
var name: String = getUserName()
println(name.length) // 如果name为null就崩了

// 现在我会这样写
var name: String? = getUserName()
if (let safeName = name) {
    println("名字长度: \(safeName.length)")
} else {
    println("用户未登录")
}

这种"啊哈时刻"在学习过程中反复出现。函数式编程的map、filter最开始看得我云里雾里,但当我用几行代码就实现了之前要写两层循环的功能时,那种简洁优雅的感觉让我爱上了这种范式。

实战项目:从零构建校园待办清单

十月中旬,光看教程已经满足不了我了。我决定做个实际项目——一个校园待办清单应用。功能很简单:添加任务、设置分类、打卡提醒。

第一周:UI搭建的痛苦

我花了整整三天时间才搞定基本UI。Column、Row这些布局容器看起来简单,但真正用起来各种细节问题层出不穷:为什么Text不能换行?为什么Button点击没反应?为什么List滚动会卡顿?

Column(spacing: 16) {
    // 这个TopBar最开始没加maxWidth,在平板上显示巨丑
    TopBar()
        .maxWidth(600)
        .padding(horizontal: 20)
    
    // List组件要用LazyColumn才能流畅滚动
    LazyColumn {
        items(taskList) { task in
            TaskCard(task: task)
        }
    }
}

每解决一个问题,我都会在代码注释里记录原因。这些注释现在看起来很幼稚,但它们记录了我成长的轨迹。

第二周:状态管理的顿悟

做到任务编辑功能时,我遇到了大麻烦。当我在编辑页修改任务后返回列表,列表居然没更新!我检查了三遍代码,数据明明改了,为什么UI不刷新?

凌晨两点,我在宿舍翻官方文档,终于找到了答案——我没有用@State装饰器。

@Component
struct TaskListView {
    // 错误写法:普通变量不会触发UI更新
    // var taskList: Array<Task> = []
    
    // 正确写法:@State装饰器让变量具有响应式
    @State var taskList: Array<Task> = []
    
    func addTask(task: Task) {
        // 状态变化会自动触发UI重渲染
        taskList.append(task)
    }
}

那一刻我理解了什么叫"响应式编程"——不需要手动调用刷新方法,数据变化自动驱动UI更新。这种声明式的思维方式,和我之前学的命令式编程完全不同。

第三周:数据持久化的坑

任务添加后一关闭应用就没了,我需要做数据持久化。最开始我想用文件存储,写了一堆序列化反序列化的代码。后来发现仓颉有内置的数据库支持,改用数据库后代码简洁了好多。

但新的问题来了——数据库操作是异步的,我不知道该在哪个生命周期钩子里加载数据。尝试了aboutToAppear、onPageShow,甚至试过在build里加载(这当然是错的)。

@Component
struct TaskListView {
    @State var taskList: Array<Task> = []
    @State var isLoading: Bool = true
    
    func aboutToAppear() {
        // 在这里异步加载数据
        Task {
            let tasks = await DatabaseManager.loadAllTasks()
            taskList = tasks
            isLoading = false
        }
    }
    
    func build() -> View {
        if (isLoading) {
            LoadingView()
        } else {
            TaskList(tasks: taskList)
        }
    }
}

为了搞懂异步加载,我专门去学了协程和async/await。虽然耽误了几天进度,但收获巨大——我不仅理解了异步编程,还学会了如何处理加载状态、错误处理、用户体验优化。

第三个月:性能优化与思维转变

十一月,应用基本功能都实现了,但测试时发现任务多了会卡。我开始学习性能优化,用DevEco Studio的性能分析工具找瓶颈。

最大的问题是列表渲染。我之前用Column包裹所有任务卡片,当任务超过50个时滚动就会掉帧。改用LazyColumn实现虚拟滚动后,性能瓶颈解决了。

// 改进前:一次性渲染所有任务,内存占用大
Column {
    for (task in taskList) {
        TaskCard(task: task)
    }
}

// 改进后:只渲染可视区域,滑动流畅
LazyColumn {
    items(taskList) { task in
        TaskCard(task: task)
            .onAppear {
                // 可以在这里预加载下一页数据
            }
    }
}

这个优化过程让我意识到,写代码不能只考虑功能实现,还要考虑性能、用户体验、可维护性。我开始养成写代码前先思考架构、写完代码后做性能测试的习惯。

收获与反思

三个月过去了,我的待办清单应用从一个简陋的Demo变成了一个基本可用的产品。更重要的是,我的编程思维发生了转变:

从命令式到声明式。我不再纠结于"怎么更新UI",而是思考"UI应该呈现什么状态"。

从功能导向到工程思维。我开始关注代码的可维护性、可扩展性、性能表现,而不只是实现功能。

从独自摸索到社区协作。我在GitHub上提交了第一个PR,在论坛回答了几个新手问题,甚至写了两篇学习笔记。帮助别人的过程也加深了自己的理解。

从害怕出错到拥抱失败。我的代码仓库里有个"失败实验"文件夹,记录了那些走过的弯路。每次翻看时,都会庆幸自己当时没有放弃。

写在最后

现在回头看,三个月前那个对着环境配置焦头烂额的我,和现在能独立开发应用的我,完全是两个人。这段经历让我明白,学习新技术不是一蹴而就的,需要耐心、坚持和正确的方法。

下学期我打算深入学习仓颉的分布式能力,尝试做跨设备协同的项目。秋招马上就要来了,掌握仓颉让我在HarmonyOS方向多了一个选择。但更重要的是,这段学习经历培养了我自主学习、解决问题、持续成长的能力,这些能力将伴随我整个职业生涯。

如果你也在考虑学习仓颉,我想说:别犹豫,从Hello World开始,每天进步一点点,三个月后你会感谢现在的自己。 💪✨

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐