# 鸿蒙学习历程
**Repository Path**: packagejava/harmonyos-study
## Basic Information
- **Project Name**: 鸿蒙学习历程
- **Description**: 学习B站全网首套鸿蒙HarmonyOS 2.0应用开发实战教程 的笔记
https://www.bilibili.com/video/BV1DM4y1G7MN
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 4
- **Created**: 2025-06-17
- **Last Updated**: 2025-06-17
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
---
---
# 《锋迷商城》HarmonyOS应⽤开发
## ⼀、移动应⽤开发的介绍
移动应⽤开发:
- Android
- IOS
- HarmonyOS (鸿蒙)

## ⼆、HarmonyOS介绍
[文档概览-HarmonyOS应用开发官网](https://developer.harmonyos.com/cn/documentation)
### 2.1 系统的定义
#### 2.1.1 系统的定位
HarmonyOS有三⼤特征:
- 搭载该操作系统的设备在系统层⾯融为⼀体、形成超级终端,让设备的硬件能⼒可以弹性 扩展,实现设备之间 硬件互助,资源共享。 对消费者⽽⾔,HarmonyOS能够将⽣活场景中的各类终端进⾏能⼒整合,实现不同终端 设备之间的快速连接、能⼒互助、资源共享,匹配合适的设备、提供流畅的全场景体验。
- ⾯向开发者,实现⼀次开发,多端部署。 对应⽤开发者⽽⾔,HarmonyOS采⽤了多种分布式技术,使应⽤开发与不同终端设备的 形态差异⽆关,从⽽让开发者能够聚焦上层业务逻辑,更加便捷、⾼效地开发应⽤。
- ⼀套操作系统可以满⾜不同能⼒的设备需求,实现统⼀OS,弹性部署。 对设备开发者⽽⾔,HarmonyOS采⽤了组件化的设计⽅案,可根据设备的资源能⼒和业 务特征灵活裁剪,满⾜不同形态终端设备对操作系统的要求。
#### 2.1.2 系统架构

- 内核层:提供⼿机操作系统的基础能⼒。HarmonyOS采⽤多内核的系统设计,基于 Linux内核、LiteOS,使⽤了Linux的微内核(使⽤了Linux的最简功 能)
- Linux内核: ⼿机操作系统的内核
- LiteOS内核:智能硬件的内核
- 系统服务层:HarmonyOS的核⼼能⼒集合,这些能⼒是有系统本身决定的,为我们应⽤ 开发提供了服务调⽤功能。系统服务层提供的能⼒是可以被我们开发的应⽤进⾏调⽤的。
- 框架层:为HarmonyOS的应⽤开发提供了不同语⾔程序调⽤的接⼝
### 2.2 鸿蒙发展史
#### 2.2.1 “鸿蒙”
盘古开天辟地——⼀⽚混沌(鸿蒙时代) ⽴志要在⼿机系统的国产化道路上开天辟地
#### 2.2.2 发展史
- 2012年,华为开始规划智能操作系统“鸿蒙”
- 2019年5⽉,华为申请“鸿蒙”商标
- 2019年5⽉17⽇,发布鸿蒙系统
- 2019年8⽉,鸿蒙正式版发布,实⾏开源
- 2020年9⽉,鸿蒙2.0(beta)
- 2021年6⽉2⽇晚上,华为线上发布HarmonyOS 2.0---⼿机
### 2.3 鸿蒙与安卓的区别
#### 2.3.1 内核
- 安卓:基于Linux的内核设计,对Linux的依赖很⼤(也就是说Android操作系统⼤多数功能都 是依赖Linux)
- 鸿蒙:采⽤了多内核设计,Linux内核+LiteOS内核,操作系统最⼩限度的依赖Linux内核
#### 2.3.2 运⾏效率
- 安卓:应⽤的运⾏是基于虚拟机的 (Java---JDK编译器---字节码---虚拟机---操作系统)
- 鸿蒙:⽅⾈编译器 (Java----⽅⾈编译器---机器码---操作系统)
据说, 鸿蒙系统运⾏效率相较于安卓提升了50%+
### 2.4 技术特性 与 系统安全
#### 2.4.1 技术特性
- 硬件互助,资源共享
- ⼀次开发,多端部署
- 统⼀OS,弹性部署
#### 2.4.2 系统安全
- 正确的⼈:⾼效安全的⽤户身份识别
- 正确的设备:设备的识别
- 正确的使⽤数据:数据的安全
## 三、第⼀个鸿蒙应⽤
### 3.1 开发准备
#### 3.1.1 开发环境搭建(Java)
- 安装JDK、配置环境变量
- 下载安装DevEco Studio集成开发环境(基于Idea开发的专⻔⽤于鸿蒙应⽤开发的IDE)
**下载地址**
[华为操作系统DevEco Studio和SDK下载与升级 | HarmonyOS开发者](https://developer.harmonyos.com/cn/develop/deveco-studio#download)
安装
- 运行安装包
- 点击Next
- 选择安装目录
- 创建桌面快捷方式
- 开始安装
运行DevEco Studio
```
第一次启动开发环境会下载鸿蒙开发所需要的SDK
```
- 双击桌⾯快捷⽅式,打开DevEco Studio
- 开始使⽤
- 选择SDK⽬录
- 点击Next进⼊下⼀步
- 选择Accept,点击Next开始下载SDK
- 点击Finish完成下载,开始使⽤
#### 3.1.2 注册华为帐号
[注册_华为帐号 (huawei.com)](https://id1.cloud.huawei.com/CAS/portal/userRegister/regbyphone.html)
### 3.2 创建鸿蒙应⽤



### 3.3 鸿蒙应⽤⽬录结构

### 3.4 运⾏项⽬
#### 3.4.1 启动鸿蒙模拟器
- Tools—Device Manager
- 在弹出的窗⼝装点击 Login 按钮,登录华为帐号
- 启动⼀个模拟器

### 3.5 鸿蒙应⽤的启动流程
#### 3.5.1 config.json
> config.json 是鸿蒙应⽤的主配置⽂件
- app 配置 :定义当前应⽤的唯⼀标识
- bundleName应用的唯一标识(一般包名用公司名+应用名称)
- version 应⽤的版本
- module 配置: ⽤于声明当前应⽤的信息(包、主类、主界⾯、功能模块声明、适配设 备类型等等)
- mainAbility声明当前应用启动时默认加载的Ability
- deviceType声明当前应用适配的设备类型
- abilities 声明当前应⽤中每个ability的配置信息
- 创建一个ability那么在config.json中会自动生成对应的ability的配置信息。


#### 3.5.2 应⽤启动流程
- 启动鸿蒙应⽤加载config.json⽂件,根据 `mainAbility `配置加载启动应⽤的主界⾯
```json
"mainAbility": "com.example.myapplication.demo01.MainAbility"
```
- 执⾏MainAbility的 onStart ⽅法
MainAbility是⼀个显示界⾯的容器,在`onStart`⽅法中通过调⽤ setMainRoute ⽅法来指 定当前界⾯容器中显示的视图界⾯
```json
// ability相当于一个容器(或者说是浏览器窗口),
// 在容器里面通过填充一个视图slice(html中的body)来展示。
// MainAbilitySlice就是⼀个界⾯
super.setMainRoute(MainAbilitySlice.class.getName());
```
- 执⾏MainAbilitySlice中的 `onStart` 完成界⾯的渲染
slice是⼀个界⾯,界⾯中显示什么视图,就是通过onstart⽅法来加载渲染的


#### 3.5.3 你好,世界哪里来的

$string : 表示引用的一sing,表示要去string文件中寻找键值对,如图寻找key为:mainability_HelloWorld 的值。
## 四、Ability框架
### 4.1 Ability介绍
Ability是应⽤所具备能⼒的抽象,也是应⽤程序的重要组成部分。⼀个应⽤可以具备多种能⼒
(即可以包含多个Ability),HarmonyOS⽀持应⽤以Ability为单位进⾏部署。
Ability可以分为` FA(Feature Ability)` 和`PA (Particle Ability)` 两种类型,每种类型为
开发者提供了不同的模板,以便实现不同的业务功能。
- FA⽀持Page Ability:
Page模板是FA唯⼀⽀持的模板,⽤于提供与⽤户交互的能⼒。⼀个Page实例可以包含⼀
组相关⻚⾯,每个⻚⾯⽤⼀个AbilitySlice实例表示。

- PA⽀持Service Ability和Data Ability:
- Service模板:⽤于提供后台运⾏任务的能⼒。
- Data模板:⽤于对外部提供统⼀的数据访问抽象。

### 4.2 PageAbility
#### 4.2.1PageAbility简介
> ⼀个PageAbility相当于⼀个⻚⾯的容器(浏览器窗⼝),⼀个AbilitySlice相当于显示在容器
>
> 中的⼀个⻚⾯(HTML)
Page模板(以下简称“Page”)是FA唯⼀⽀持的模板,⽤于提供与⽤户交互的能⼒。⼀个Page可以由⼀个或多个AbilitySlice构成,AbilitySlice是指应⽤的单个⻚⾯及其控制逻辑的总和(相当于⼀个HTML⽂件)。在⼀个Abiliy种可以包含多个Slice
```
商品管理: ProductAbility(PageAbility):
goods-list.html ProductListSlice
goods-detail.html ProductDetailSlice
```
#### 4.2.2 创建AbilitySlice
- AbilitySlice创建slice包中
- 创建步骤:
- 创建⼀个类继承 ohos.aafwk.ability.AbilitySlice 类
```java
public class MainAbilitySlice2 extends AbilitySlice {
}
```
- 在 `resources/base/layout` ⽬录下创建布局⽂件
```xml
```
- 在创建的 AbilitySlice 类中重写 onStart ⽅法,调⽤setUIContent⽅法加载布局⽂件
通过 ResourceTable 加载resouces⽬录下的资源
```java
public class MainAbilitySlice2 extends AbilitySlice {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
//定义slice视图组件(Java,XML)
//setUIContent(int); 加载应⽤的 布局⽂件(xml) 作为当前slice的视图
setUIContent(ResourceTable.Layout_ability_main_slice2);
}
}
```
#### 4.2.3 PageAbility⽣命周期
> ⼀个Page中可以包含多个Slice,但是只能同时显示⼀个slice,如何设置PageAbility默认
>
> 显示的slice?
>
> 在⼀个Page Ability中提供了多个声明周期⽅法,这些⽅法在当前PageAbility加载的不同
>
> 阶段会⾃定调⽤

> 说明
>
> INACTIVE状态是一种短暂存在的状态,可理解为“激活中”。
```java
public class MainAbility extends Ability {
/**
* 当系统⾸次创建当前PageAbility实例时,⾃动调⽤onstart⽅法。也就是说对于⼀个Page⽽⾔,onStart⽅法只会执⾏⼀次
*/
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice2.class.getName());
System.out.println("--------------onStart");
}
/**
* 当前Page进⼊active状态进⼊到⼿机前台获取焦点时,会触发onActive⽅法的执⾏
*/
protected void onActive() {
super.onActive();
System.out.println("--------------onActive");
}
/**
* 当前PageAbility失去焦点(⻚⾯切⼊到后台、切换到其他Page),触发onInactive⽅法的执⾏
*/
protected void onInactive() {
super.onInactive();
System.out.println("--------------onInactive");
}
/**
* 当前PageAbility切换到后台,不可⻅时,触发onBackground执⾏
*/
protected void onBackground() {
super.onBackground();
System.out.println("--------------onBackground");
}
/**
* 当PageAbility从后台不可⻅状态(⻚⾯在后台、但是没销毁)切换到前台可⻅状态时触发 onForeground执⾏
*/
protected void onForeground(Intent intent) {
super.onForeground(intent);
System.out.println("--------------onForeground");
}
/**
* 当前Page销毁时,触发onStop的执⾏
*/
protected void onStop() {
super.onStop();
System.out.println("--------------onStop");
}
}
```
#### 4.2.4 Slice的两种渲染方式
> Slice相当于一个网页,Slice中显示的视图是通过组件来声明的,Slice中的组件加载支持两种方式:
>
> - Java代码
> - xml布局文件
`onStart`方法:在Slice实例创建时执行,用于载入当前Slice的视图组件,在onStart方法中通过调用`setUIContext`来加载视图组件
> setUIContext方法提供了2个重载:
>
> setUIContext(int):通过布局⽂件的ID,加载resources/base/layout⽬录下的布局⽂件
>
> 完成⻚⾯的渲染
>
> setUIContext(ComponentContainer) :通过加载⼀个使⽤Java代码创建的组件完成⻚⾯
>
> 的渲染
##### **XML****⽅式渲染**
- 创建布局⽂件:ability_main_slice2.xml
```xml
```
- 在Slice的onStart⽅法中加载布局⽂件:
每创建一个布局文件(或者说每个资源都会创建一个ID)都会生成一个ID,所以布局文件调用的是setUIContext(int)方法

```java
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
// 定义slice视图组件(java,xml)
// setUIContent(int); 加载应用的 布局文件(xml)作为当前slice的试图
super.setUIContent(ResourceTable.Layout_ability_main_slice2);
}
```
##### **Java⽅式渲染**
- 使⽤Java代码创建组件,渲染到slice中
```java
public class MainAbilitySlice2 extends AbilitySlice {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
// 定义slice视图组件(java,xml)
// setUIContent(int); 加载应用的 布局文件(xml)作为当前slice的试图
// super.setUIContent(ResourceTable.Layout_ability_main_slice2);
// ComponentContainer(组件容器)
DirectionalLayout directionalLayout = new DirectionalLayout(this);
directionalLayout.setOrientation(Component.DRAG_VERTICAL);
// Component(组件)
Text text = new Text(this);
text.setText("Hello Boys");
text.setHeight(40);
text.setTextSize(40);
// 将组件放到组件容器中
directionalLayout.addComponent(text);
// 将组件容器渲染到slice中
setUIContent(directionalLayout);
}
}
```
#### 4.2.5 AbilitySlice间导航
>⼀个PageAbility可以包含多个Slice,同⼀时刻只能显示⼀个Slice,但是可以在不同的
>
>Slice之间进⾏跳转——AbilitySlice间的导航

- 在MainAbilitySlice中添加按钮,并监听按钮的点击事件(略 参考4.3)
- 创建SecondAbilitySlice(略)
```xml
```
~~~java
public class SecondAbilitySlice extends AbilitySlice {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
this.setUIContent(ResourceTable.Layout_ability_second);
}
}
~~~
- 在MainAbilitySlice中监听按钮的点击事件,导航到SecondAbilitySlice
~~~java
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
// 在当前slice中渲染试图组件有2中方式:
// 1. 基于Java代码的渲染
// 2. 基于xml标签渲染,例如: super.setUIContent(ResourceTable.Layout_ability_main);
super.setUIContent(ResourceTable.Layout_ability_main);
// 1. 获取id=btn1的按钮组件
Button btn1 = (Button) this.findComponentById(ResourceTable.Id_btn1);
// 2.设置按钮事件监听
MainAbilitySlice _this = this;
// a.创建事件监听器
Component.ClickedListener clickedListener = new Component.ClickedListener() {
@Override
public void onClick(Component component) {
//挑转到SecondAbilitySlice
// 从this指代的当前slice跳转到new的slice中
_this.present(new SecondAbilitySlice(), new Intent());
}
};
// b.设置组件的事件监听
btn1.setClickedListener(clickedListener);
}
}
~~~
**简化版本**
~~~java
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
// 在当前slice中渲染试图组件有2中方式:
// 1. 基于Java代码的渲染
// 2. 基于xml标签渲染,例如: super.setUIContent(ResourceTable.Layout_ability_main);
super.setUIContent(ResourceTable.Layout_ability_main);
// 1. 获取id=btn1的按钮组件
Button btn1 = (Button) this.findComponentById(ResourceTable.Id_btn1);
// //b.设置组件的事件监听 PS:简化成lambda表达示
// PS:简化成lambda表达式 因为listener要实现onclick方法
// btn1.setClickedListener(clickedListener->{
// present(new SecondAbilitySlice(), new Intent() );
// });
// b.设置组件的事件监听 因为只有一个方法,可以省略大括号
btn1.setClickedListener(clickedListener -> present(new SecondAbilitySlice(), new Intent()));
}
}
~~~
#### 4.2.6 Slice之间的传值问题
> 使⽤Intent对象实现slice间的传值

- MainAbilitySlice
~~~java
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
// 1. 获取id=btn1的按钮组件
Button btn1 = (Button) this.findComponentById(ResourceTable.Id_btn1);
// b.设置组件的事件监听
btn1.setClickedListener(clickedListener -> {
// 在跳转之前的slice将需要传递的数据设置到Intent对象中
Intent intent1 = new Intent();
intent1.setParam("productId", "101");
present(new SecondAbilitySlice(), intent1);
});
}
}
~~~
- SecondAbilitySlice
~~~java
public class SecondAbilitySlice extends AbilitySlice {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
this.setUIContent(ResourceTable.Layout_ability_second);
// 在跳转后的slice的onStart方法中,从intent对象中获取数据
if (intent != null) {
// 因为intent.getParam()返回的是IntentParams, 所以先获取IntentParams然后再获取值
IntentParams params = intent.getParams();
String productId = (String) params.getParam("productId");
// 获取到id=text1的文本组件
Text text = (Text) findComponentById(ResourceTable.Id_text1);
// 将获取到的商品ID设置到text文本组件
text.setText(productId);
}
}
}
~~~
### 4.3 组件的事件监听
#### 4.3.1 在MainAbilitySlice布局文件添加按钮
```xml
```
当我们在Button使用`$+id:btn1`时,这个组件就会在ResourceTable中产生一个唯一标识

#### 4.3.2 监听按钮的点击事件
- 在加载布局文件的Slice类中,获取按钮组件,设置点击事件的监听器
```java
package com.example.myapplicationdemo01.slice;
import com.example.myapplicationdemo01.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
// 在当前slice中渲染试图组件有2中方式:
// 1. 基于Java代码的渲染
// 2. 基于xml标签渲染,例如: super.setUIContent(ResourceTable.Layout_ability_main);
super.setUIContent(ResourceTable.Layout_ability_main);
// 1. 获取id=btn1的按钮组件
Button btn = (Button) this.findComponentById(ResourceTable.Id_btn1);
// 2.设置按钮事件监听
// a.创建事件监听器
Component.ClickedListener clickedListener = new Component.ClickedListener(){
@Override
public void onClick(Component component) {
System.out.println("--------触发了点击事件");
}
};
// b.设置组件的事件监听
btn.setClickedListener(clickedListener);
}
}
```
- 可以使用同一个监听器监听多个组件的事件,如果点击不同的组件执行的业务不同,则可以通过组件判断来执行不同的业务
~~~java
// 1. 获取id=btn1的按钮组件
Button btn1 = (Button) this.findComponentById(ResourceTable.Id_btn1);
Button btn2 = (Button) this.findComponentById(ResourceTable.Id_btn2);
// 2.设置按钮事件监听
// a.创建事件监听器
Component.ClickedListener clickedListener = new Component.ClickedListener(){
@Override
public void onClick(Component component) {
// Component参数 表示监听的组件
if (component == btn1) {
System.out.println("--------aaa");
} else if (component == btn2) {
System.out.println("~~~~~~~~bbb");
}
}
};
// b.设置组件的事件监听
btn1.setClickedListener(clickedListener);// 输出aaa
btn2.setClickedListener(clickedListener);// 输出bbb
~~~