UIAbility
UIAbility 组件是一种包含UI的应用组件,主要用于和用户交互
设计理念:原生支持应用组件的跨端迁移和多端协同、支持多设备和多窗口的形态
UIAbility组件是系统调度的基本单位,为应用提供绘制界面的窗口。
typescript
/**
为使应用能够正常使用UIAbility,
需要在module.json5配置文件的abilities标签中声明UIAbility
的名称、入口、标签等相关信息。
*/
{
"module": {
// ...
"abilities": [
{
"name": "EntryAbility", // UIAbility组件的名称
"srcEntry": "./ets/entryability/EntryAbility.ets", // UIAbility组件的代码路径
"description": "$string:EntryAbility_desc", // UIAbility组件的描述信息
"icon": "$media:icon", // UIAbility组件的图标
"label": "$string:EntryAbility_label", // UIAbility组件的标签
"startWindowIcon": "$media:icon", // UIAbility组件启动页面图标资源文件的索引
"startWindowBackground": "$color:start_window_background", // UIAbility组件启动页面背景颜色资源文件的索引
// ...
}
]
}
}
生命周期
Create状态
Create状态为在应用加载过程中,UIAbility实例创建完成时触发,系统会调用onCreate()回调。可以在该回调中进行页面初始化操作,例如变量定义资源加载等,用于后续的UI展示。
typescript
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 页面初始化
// Want是对象间信息传递的载体,可以用于应用组件间的信息传递
}
// ...
}
WindowStageCreate和WindowStageDestroy状态
UIAbility实例创建完成之后,在进入Foreground之前,系统会创建一个WindowStage。WindowStage创建完成后会进入onWindowStageCreate()回调,可以在该回调中设置UI加载、设置WindowStage的事件订阅。
在UIAbility实例销毁之前,则会先进入onWindowStageDestroy()回调,可以在该回调中释放UI资源。
typescript
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';
const TAG: string = '[EntryAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
export default class EntryAbility extends UIAbility {
// ...
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index', (err, data) => {
// 应用中的UIAbility在启动过程中,需要指定启动页面,
// 否则应用启动后会因为没有默认加载页面而导致白屏。
});
// 设置WindowStage的事件订阅(
// 获焦/失焦、切到前台/切到后台、前台可交互/前台不可交互)
try {
windowStage.on('windowStageEvent', (data) => {
let stageEventType: window.WindowStageEventType = data;
switch (stageEventType) {
case window.WindowStageEventType.SHOWN: // 切到前台
hilog.info(DOMAIN_NUMBER, TAG, `windowStage foreground.`);
break;
case window.WindowStageEventType.ACTIVE: // 获焦状态
hilog.info(DOMAIN_NUMBER, TAG, `windowStage active.`);
break;
case window.WindowStageEventType.INACTIVE: // 失焦状态
hilog.info(DOMAIN_NUMBER, TAG, `windowStage inactive.`);
break;
case window.WindowStageEventType.HIDDEN: // 切到后台
hilog.info(DOMAIN_NUMBER, TAG, `windowStage background.`);
break;
case window.WindowStageEventType.RESUMED: // 前台可交互状态
hilog.info(DOMAIN_NUMBER, TAG, `windowStage resumed.`);
break;
case window.WindowStageEventType.PAUSED: // 前台不可交互状态
hilog.info(DOMAIN_NUMBER, TAG, `windowStage paused.`);
break;
default:
break;
}
});
} catch (exception) {
hilog.error(DOMAIN_NUMBER, TAG,
`Failed to enable the listener for window stage event changes. Cause: ${JSON.stringify(exception)}`);
}
hilog.info(DOMAIN_NUMBER, TAG, `%{public}s`, `Ability onWindowStageCreate`);
// 设置UI加载
windowStage.loadContent('pages/Index', (err, data) => {
// ...
});
}
onWindowStageDestroy() {
// 释放UI资源
}
}
Foreground和Background状态
Foreground和Background状态分别在UIAbility实例切换至前台和切换至后台时触发,对应于onForeground()回调和onBackground()回调。
onForeground()回调,在UIAbility的UI可见之前,如UIAbility切换至前台时触发。可以在onForeground()回调中申请系统需要的资源,或者重新申请在onBackground()中释放的资源。
onBackground()回调,在UIAbility的UI完全不可见之后,如UIAbility切换至后台时候触发。可以在onBackground()回调中释放UI不可见时无用的资源,或者在此回调中执行较为耗时的操作,例如状态保存等。
typescript
import { UIAbility } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
// ...
onForeground(): void {
// 申请系统需要的资源,或者重新申请在onBackground()中释放的资源
}
onBackground(): void {
// 释放UI不可见时无用的资源,或者在此回调中执行较为耗时的操作
// 例如状态保存等
}
}
当应用的UIAbility实例已创建,且UIAbility配置为singleton启动模式时,再次调用startAbility()方法启动该UIAbility实例时,只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。应用可以在该回调中更新要加载的资源和数据等,用于后续的UI展示。
typescript
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
// ...
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
// 更新资源、数据
}
}
Destroy状态
Destroy状态在UIAbility实例销毁时触发。可以在onDestroy()回调中进行系统资源的释放、数据的保存等操作。
UIAbility组件启动模式
-
singleton(单实例模式)
每次调用startAbility()方法时,如果应用进程中该类型的UIAbility实例已经存在,则复用系统中的UIAbility实例。系统中只存在唯一一个该UIAbility实例,即在最近任务列表中只存在一个该类型的UIAbility实例(由于启动的还是原来的UIAbility实例,并未重新创建一个新的UIAbility实例,此时只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调)。
-
multiton(多实例模式)
multiton启动模式为多实例模式,每次调用startAbility()方法时,都会在应用进程中创建一个新的该类型UIAbility实例。即在最近任务列表中可以看到有多个该类型的UIAbility实例。这种情况下可以将UIAbility配置为multiton(多实例模式)。
-
specified(指定实例模式)
specified启动模式为指定实例模式,针对一些特殊场景使用(例如文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例)。
UIAbility组件与UI的数据同步
- 使用EventHub进行数据通信:在基类Context中提供了EventHub对象,可以通过发布订阅方式来实现事件的传递。在事件传递前,订阅者需要先进行订阅,当发布者发布事件时,订阅者将接收到事件并进行相应处理。
typescript
// UIAbility
import { hilog } from '@kit.PerformanceAnalysisKit';
import { UIAbility, Context, Want, AbilityConstant } from '@kit.AbilityKit';
const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[EventAbility]';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 获取eventHub
let eventhub = this.context.eventHub;
// 执行订阅操作
eventhub.on('event1', this.eventFunc);
eventhub.on('event1', (data: string) => {
// 触发事件,完成相应的业务操作
});
hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onCreate');
}
// ...
eventFunc(argOne: Context, argTwo: Context): void {
hilog.info(DOMAIN_NUMBER, TAG, '1. ' + `${argOne}, ${argTwo}`);
return;
}
}
// UI
import { common } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct Page_EventHub {
private context = getContext(this) as common.UIAbilityContext;
eventHubFunc(): void {
// 不带参数触发自定义"event1"事件
this.context.eventHub.emit('event1');
// 带1个参数触发自定义"event1"事件
this.context.eventHub.emit('event1', 1);
// 带2个参数触发自定义"event1"事件
this.context.eventHub.emit('event1', 2, 'test');
// 开发者可以根据实际的业务场景设计事件传递的参数
}
build() {
Column() {
// ...
List({ initialIndex: 0 }) {
ListItem() {
Row() {
// ...
}
.onClick(() => {
this.eventHubFunc();
promptAction.showToast({
message: 'EventHubFuncA'
});
})
}
// ...
ListItem() {
Row() {
// ...
}
.onClick(() => {
this.context.eventHub.off('event1');
promptAction.showToast({
message: 'EventHubFuncB'
});
})
}
// ...
}
// ...
}
// ...
}
}
- 使用AppStorage/LocalStorage进行数据同步:ArkUI提供了AppStorage和LocalStorage两种应用级别的状态管理方案,可用于实现应用级别和UIAbility级别的数据同步。
AbilityStage组件容器
AbilityStage是一个Module级别的组件容器,应用的HAP在首次加载时会创建一个AbilityStage实例,可以对该Module进行初始化等操作。
AbilityStage与Module一一对应,即一个Module拥有一个AbilityStage。
DevEco Studio默认工程中未自动生成AbilityStage,如需要使用AbilityStage的能力,可以手动新建一个AbilityStage文件,具体步骤如下。
-
在工程Module对应的ets目录下,右键选择"New > Directory",新建一个目录并命名为myabilitystage。
-
在myabilitystage目录,右键选择"New > ArkTS File",新建一个文件并命名为MyAbilityStage.ets。
-
打开MyAbilityStage.ets文件,导入AbilityStage的依赖包,自定义类继承AbilityStage并加上需要的生命周期回调,示例中增加了一个onCreate()生命周期回调。
typescript
import { AbilityStage, Want } from '@kit.AbilityKit';
export default class MyAbilityStage extends AbilityStage {
onCreate(): void {
// 应用HAP首次加载时触发,可以在此执行该Module的初始化操作(例如资源预加载、线程创建等)。
}
onAcceptWant(): void {
// UIAbility指定实例模式(specified)启动时候触发的事件回调
}
onAcceptWant(want: Want): string {
// 当系统调整内存时触发的事件
// 仅specified模式下触发
return 'MyAbilityStage';
}
}
typescript
// 在module.json5配置文件中,
// 通过配置 srcEntry 参数来指定模块对应的代码路径,以作为HAP加载的入口。
{
"module": {
"name": "entry",
"type": "entry",
"srcEntry": "./ets/myabilitystage/MyAbilityStage.ets",
// ...
}
}
UIAbility组件间的交互
假设应用中有两个UIAbility:EntryAbility和FuncAbility(可以在同一个Module中,也可以在不同的Module中),需要从EntryAbility的页面中启动FuncAbility。
typescript
// EntryAbility
import { common, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;
@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
private context = getContext(this) as common.UIAbilityContext;
build() {
Column() {
//...
List({ initialIndex: 0 }) {
ListItem() {
Row() {
//...
}
.onClick(() => {
// context为Ability对象的成员,在非Ability对象内部调用需要
// 将Context对象传递过去
let wantInfo: Want = {
deviceId: '', // deviceId为空表示本设备
bundleName: 'com.samples.stagemodelabilitydevelop',
moduleName: 'entry', // moduleName非必选
abilityName: 'FuncAbilityA',
parameters: {
// 自定义信息
info: '来自EntryAbility Page_UIAbilityComponentsInteractive页面'
},
};
// context为调用方UIAbility的UIAbilityContext
this.context.startAbility(wantInfo).then(() => {
hilog.info(DOMAIN_NUMBER, TAG, 'startAbility success.');
}).catch((error: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, 'startAbility failed.');
});
})
}
//...
}
//...
}
//...
}
}
typescript
// FuncAbility UIAbility
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
export default class FuncAbilityA extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 可以通过获取传递过来的want参数的parameters来获取拉起方UIAbility的PID、Bundle Name等信息。
// 接收调用方UIAbility传过来的参数
let funcAbilityWant = want;
let info = funcAbilityWant?.parameters?.info;
}
//...
}
// FuncAbility UI
// 在FuncAbility业务完成之后,如需要停止当前UIAbility实例,
// 在FuncAbility中通过调用terminateSelf()方法实现。
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
const TAG: string = '[Page_FromStageModel]';
const DOMAIN_NUMBER: number = 0xFF00;
@Entry
@Component
struct Page_FromStageModel {
build() {
Column() {
//...
Button('FuncAbilityB')
.onClick(() => {
// UIAbilityContext
let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
// context为需要停止的UIAbility实例的AbilityContext
context.terminateSelf((err) => {
if (err.code) {
hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self. Code is ${err.code}, message is ${err.message}`);
return;
}
});
})
}
//...
}
}