手戳一个HarmonyOS (鸿蒙)移动应用

⼀、移动应⽤开发的介绍

移动应⽤开发:

Android

IOS

HarmonyOS (鸿蒙)

⼆、HarmonyOS介绍

文档概览-HarmonyOS应用开发官网

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开发者

安装

运行安装包

点击Next

选择安装目录

创建桌面快捷方式

开始安装

运行DevEco Studio

第一次启动开发环境会下载鸿蒙开发所需要的SDK

双击桌⾯快捷⽅式,打开DevEco Studio

开始使⽤

选择SDK⽬录

点击Next进⼊下⼀步

选择Accept,点击Next开始下载SDK

点击Finish完成下载,开始使⽤

3.1.2 注册华为帐号

注册_华为帐号 (huawei.com)

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 配置加载启动应⽤的主界⾯

"mainAbility": "com.example.myapplication.demo01.MainAbility"

执⾏MainAbility的 onStart ⽅法

MainAbility是⼀个显示界⾯的容器,在onStart⽅法中通过调⽤ setMainRoute ⽅法来指 定当前界⾯容器中显示的视图界⾯

// 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 类

public class MainAbilitySlice2 extends AbilitySlice {

}

在 resources/base/layout ⽬录下创建布局⽂件
<?xml version="1.0" encoding="utf-8"?>

在创建的 AbilitySlice 类中重写 onStart ⽅法,调⽤setUIContent⽅法加载布局⽂件

通过 ResourceTable 加载resouces⽬录下的资源

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状态是一种短暂存在的状态,可理解为"激活中"。

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 version="1.0" encoding="utf-8"?>

复制代码
<Text
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:text="这是测试文本"
    ohos:text_color="#ff0000"
    ohos:text_size="40vp"></Text>

在Slice的onStart⽅法中加载布局⽂件:

每创建一个布局文件(或者说每个资源都会创建一个ID)都会生成一个ID,所以布局文件调用的是setUIContext(int)方法

@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中

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 version="1.0" encoding="utf-8"?>

复制代码
<!-- 将图片文件存到resource/base/media目录 PS:文件的名字不要用数字开头,因为名字会作为变量名 -->
<Image
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:image_src="$media:cat">
</Image>

public class SecondAbilitySlice extends AbilitySlice {

复制代码
@Override
protected void onStart(Intent intent) {
    super.onStart(intent);
    this.setUIContent(ResourceTable.Layout_ability_second);
}

}

在MainAbilitySlice中监听按钮的点击事件,导航到SecondAbilitySlice

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);

}

}

简化版本

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

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

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 version="1.0" encoding="utf-8"?>

复制代码
<Image
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:image_src="$media:icon">
</Image>

<Text
    ohos:id="$+id:text_helloworld"
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:background_element="$graphic:background_ability_main"
    ohos:layout_alignment="horizontal_center"
    ohos:text="$string:mainability_HelloWorld"
    ohos:text_size="40vp"/>
<Button
    ohos:id="$+id:btn1"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:padding="5vp"
    ohos:text="点我试试!"
    ohos:text_size="40vp"
    ohos:background_element="#a0b0c0"></Button>

当我们在Button使用$+id:btn1时,这个组件就会在ResourceTable中产生一个唯一标识

4.3.2 监听按钮的点击事件

在加载布局文件的Slice类中,获取按钮组件,设置点击事件的监听器

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);
}

}

可以使用同一个监听器监听多个组件的事件,如果点击不同的组件执行的业务不同,则可以通过组件判断来执行不同的业务

// 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

相关推荐
嗝o゚17 小时前
鱼与熊掌可兼得?用Flutter+鸿蒙的混合架构破解性能与UI的世纪难题
flutter·架构·harmonyos
遇到困难睡大觉哈哈20 小时前
HarmonyOS 应用数据持久化概述:Preferences、KV-Store、RelationalStore 到底怎么选?
笔记·华为·harmonyos
宇擎智脑科技20 小时前
Flutter 对接高德地图 SDK 适配鸿蒙踩坑记录与通信架构解析
flutter·架构·harmonyos
嗝o゚21 小时前
鸿蒙智慧屏与Flutter适配:无硬件功能的兼容处理
flutter·华为·开源·harmonyos
luxy200421 小时前
HarmonyOS简易时钟应用
华为·harmonyos
俩毛豆1 天前
基于HarmonyOS(NEXT)的超级App中的搜索架构实现(直播文字干货版)
成长·架构·app·harmonyos·搜索
嗝o゚1 天前
Flutter 无障碍功能开发最佳实践
python·flutter·华为
嗝o゚1 天前
开源鸿蒙 Flutter 应用包瘦身实战
flutter·华为·开源·harmonyos
云和数据.ChenGuang1 天前
鸿蒙负一屏的技术定位与核心价值
华为·wpf·harmonyos
遇到困难睡大觉哈哈1 天前
HarmonyOS 关系型数据库 RDB 数据持久化(ArkTS)实战:建库建表、CRUD、事务、FTS、性能优化,一篇搞懂
笔记·华为·harmonyos