AbilityStage
基本概念
在了解AbilityStage之前,我们需要先了解和回顾几个概念,UIAbility、ExtensionAbility、HAP。
- UIAbility:前边的文章中我们讲过,UIAbility是包罗UI的应用组件,主要用于和用户交互。
- ExtensionAbility:是一种面向特定场景的应用组件,如输入法、桌面卡片、闲时任务、数据备份等,每一个具体场景对应一种ExtensionAbilityType,只能只用系统已经定义的场景。所有的ExtensionAbility组件均不能被应用直接启动,而是由相应的系统管理服务拉起,以确保其生命周期受系统管控。
- HAP:应用安装的基本单位,一个应用会包罗一个或者多个.hap文件,.hap是由项目工程中的module编译而成的。
回顾了几个概念之后,我们来说本日的AbilityStage。
AbilityState是Module级别的容器组件,与HAP是一一对应的关系。
当HAP中的代码初次被加载到应用进程中时,也就是Module初始化的时候,系统首先会创建一个AbilityState实例,AbilityStage可以管理Module中的Ability组件和ExtensionAbility组件。
关系图如下:
一个应用,也就是application,可以包罗一个或者多个HAP,每个HAP对应一个AbilityStage,每个AlibityStage可以管理一个或者多个UIAbility,每个UIAbility中包罗一个WindowStage,用于管理Window,每个Window中,可以管理一个或者多个UI页面。
当我们需要打开某一个UIAbility时:
- 如果该UIAbility所在的HAP还没有加载到进程中,那么系统会将HAP加载到进程中,创建一个AbilityStage实例。创建成功后,实行AbilityStage的onCreate生命周期函数,可以在该方法中进行一些module级别的资源初始化。
- 创建UIAbility实例,创建成功后,回调UIAbility的onCreate生命周期函数,可以在该回调函数中初始化一些业务逻辑。
- 系统为该UIAbility实例创建一个WindowStage实例,创建完成后,会回调UIAbility的onWindowStageCreate生命周期回调函数,可以在该回调函数中获取主窗口信息,设置UI界面以及监听WindowStage的生命周期变化。
如下图所示:
在鸿蒙中,应用组件和UI之间的生命周期是松耦合的,在这种筹划模式下,有几个好处
- 业务逻辑与UI分离,我们可以在UIAbility中处理一些与UI无关的业务逻辑,如打开蓝牙,连接数据库等。而在WindowStage持有的窗口上去处理界面相关的业务逻辑。
- 便于系统对应用组件进行裁剪。比如无屏设备,系统在创建时不会创建窗口模块,可以减少运行内存占用。
- 在多设备上,应用组件可以利用同一套生命周期。
单窗口模式:
这个流程会触发App1中WindowStage的hidden和inActive生命周期,触发UIAbility中的background生命周期;同时触发App2中WindowStage的shown和active生命周期,触发UIAbility中的foreground生命周期。
多窗口模式:
这个流程只会触发App1中WindowStage的inActive生命周期函数,同时触发App2中WindowStage的active生命周期函数。而不会触发两个app中各自UIAbility中的生命周期函数。
生命周期
AbilityStage共有四个生命周期函数
- onCreate:AbilityStage实例创建完成后回调的生命周期函数,可以在这里进行Module的初始化利用。
- onAcceptWant:UIAbility指定实例模式启动时,会触发该回调,在该回调中,我们需要返回一个唯一的key值,系统用于判断指定的实例是否已经存在。
- onConfigurationUpdated:系统全局设置发生改变时触发的回调函数,如系统语言,深淡色等。可以在该函数中吸取到系统最新的设置信息。
- onMemoryLevel:系统调整内存时触发的函数。
利用方式
- 在工程Module对应的ets目次下,右键选择“New > Directory”,新建一个目次并定名为myabilitystage。
- 在myabilitystage目次,右键选择“New > ArkTS File”,新建一个文件并定名为MyAbilityStage.ts。
- 打开MyAbilityStage.ts文件,导入AbilityStage的依靠包,自定义类继续AbilityStage并加上需要的生命周期回调,示例中增加了一个onCreate()生命周期回调。
- import { AbilityStage, Want } from '@kit.AbilityKit';
- export default class MyAbilityStage extends AbilityStage {
- onCreate(): void {
- // 应用的HAP在首次加载的时,为该Module初始化操作
- }
- onAcceptWant(want: Want): string {
- // 仅specified模式下触发
- return 'MyAbilityStage';
- }
- }
复制代码 - 在module.json5设置文件中,通过设置 srcEntry 参数来指定模块对应的代码路径,以作为HAP加载的入口。
- {
- "module": {
- "name": "entry",
- "type": "entry",
- "srcEntry": "./ets/myabilitystage/MyAbilityStage.ts",
- // ...
- }
- }
复制代码 UIAbility组件间交互
UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时,会涉及到启动特定的UIAbility,包罗应用内的其他UIAbility、或者其他应用的UIAbility(例如启动三方支付UIAbility)。
启动应用内的UIAbility
假设应用中有两个UIAbility:EntryAbility和FuncAbility(可以在同一个Module中,也可以在差别的Module中),需要从EntryAbility的页面中启动FuncAbility。
- 在EntryAbility中,通过调用startAbility()方法启动UIAbility,want为UIAbility实例启动的入口参数,此中bundleName为待启动应用的Bundle名称,abilityName为待启动的Ability名称,moduleName在待启动的UIAbility属于差别的Module时添加,parameters为自定义信息参数。
- 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.');
- });
- })
- }
- //...
- }
- //...
- }
- //...
- }
- }
复制代码 - 在FuncAbility的onCreate()或者onNewWant()生命周期回调文件中吸取EntryAbility传递过来的参数。
- import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
- export default class FuncAbilityA extends UIAbility {
- onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
- // 接收调用方UIAbility传过来的参数
- let funcAbilityWant = want;
- let info = funcAbilityWant?.parameters?.info;
- }
- //...
- }
复制代码 - 在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(() => {
- let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // 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;
- }
- });
- })
- }
- //...
- }
- }
复制代码 调用terminateSelf()方法停止当前UIAbility实例时,默认会保留该实例的快照(Snapshot),即在最近任务列表中仍旧能检察到该实例对应的任务。如不需要保留该实例的快照,可以在其对应UIAbility的module.json5设置文件中,将abilities标签的removeMissionAfterTerminate字段设置为true。
- 如需要关闭应用所有的UIAbility实例,可以调用ApplicationContext的killAllProcesses()方法实现关闭应用所有的进程。
启动应用内的UIAbility并获取返回结果
在一个EntryAbility启动另外一个FuncAbility时,希望在被启动的FuncAbility完成相关业务后,能将结果返回给调用方。例如在应用中将入口功能和账号登录功能分别筹划为两个独立的UIAbility,在账号登录UIAbility中完成登录利用后,需要将登录的结果返回给入口UIAbility。
- 在EntryAbility中,调用startAbilityForResult()接口启动FuncAbility,异步回调中的data用于吸取FuncAbility停止自身后返回给EntryAbility的信息。
- import { common, Want } from '@kit.AbilityKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- import { promptAction } from '@kit.ArkUI';
- import { BusinessError } from '@kit.BasicServicesKit';
- const TAG: string = '[Page_UIAbilityComponentsInteractive]';
- const DOMAIN_NUMBER: number = 0xFF00;
- @Entry
- @Component
- struct Page_UIAbilityComponentsInteractive {
- build() {
- Column() {
- //...
- List({ initialIndex: 0 }) {
- ListItem() {
- Row() {
- //...
- }
- .onClick(() => {
- let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
- const RESULT_CODE: number = 1001;
- let want: Want = {
- deviceId: '', // deviceId为空表示本设备
- bundleName: 'com.samples.stagemodelabilitydevelop',
- moduleName: 'entry', // moduleName非必选
- abilityName: 'FuncAbilityA',
- parameters: {
- // 自定义信息
- info: '来自EntryAbility UIAbilityComponentsInteractive页面'
- }
- };
- context.startAbilityForResult(want).then((data) => {
- if (data?.resultCode === RESULT_CODE) {
- // 解析被调用方UIAbility返回的信息
- let info = data.want?.parameters?.info;
- hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? '');
- if (info !== null) {
- promptAction.showToast({
- message: JSON.stringify(info)
- });
- }
- }
- hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? '');
- }).catch((err: BusinessError) => {
- hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
- });
- })
- }
- //...
- }
- //...
- }
- //...
- }
- }
复制代码 - 在FuncAbility停止自身时,需要调用terminateSelfWithResult()方法,入参abilityResult为FuncAbility需要返回给EntryAbility的信息。
- import { common } from '@kit.AbilityKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- const TAG: string = '[Page_FuncAbilityA]';
- const DOMAIN_NUMBER: number = 0xFF00;
- @Entry
- @Component
- struct Page_FuncAbilityA {
- build() {
- Column() {
- //...
- List({ initialIndex: 0 }) {
- ListItem() {
- Row() {
- //...
- }
- .onClick(() => {
- let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
- const RESULT_CODE: number = 1001;
- let abilityResult: common.AbilityResult = {
- resultCode: RESULT_CODE,
- want: {
- bundleName: 'com.samples.stagemodelabilitydevelop',
- moduleName: 'entry', // moduleName非必选
- abilityName: 'FuncAbilityB',
- parameters: {
- info: '来自FuncAbility Index页面'
- },
- },
- };
- context.terminateSelfWithResult(abilityResult, (err) => {
- if (err.code) {
- hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self with result. Code is ${err.code}, message is ${err.message}`);
- return;
- }
- });
- })
- }
- //...
- }
- //...
- }
- //...
- }
- }
复制代码 - FuncAbility停止自身后,EntryAbility通过startAbilityForResult()方法回调吸取被FuncAbility返回的信息,RESULT_CODE需要与前面的数值保持一致。
- import { common, Want } from '@kit.AbilityKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- import { promptAction } from '@kit.ArkUI';
- import { BusinessError } from '@kit.BasicServicesKit';
- const TAG: string = '[Page_UIAbilityComponentsInteractive]';
- const DOMAIN_NUMBER: number = 0xFF00;
- @Entry
- @Component
- struct Page_UIAbilityComponentsInteractive {
- build() {
- Column() {
- //...
- List({ initialIndex: 0 }) {
- ListItem() {
- Row() {
- //...
- }
- .onClick(() => {
- let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
- const RESULT_CODE: number = 1001;
- let want: Want = {
- deviceId: '', // deviceId为空表示本设备
- bundleName: 'com.samples.stagemodelabilitydevelop',
- moduleName: 'entry', // moduleName非必选
- abilityName: 'FuncAbilityA',
- parameters: {
- // 自定义信息
- info: '来自EntryAbility UIAbilityComponentsInteractive页面'
- }
- };
- context.startAbilityForResult(want).then((data) => {
- if (data?.resultCode === RESULT_CODE) {
- // 解析被调用方UIAbility返回的信息
- let info = data.want?.parameters?.info;
- hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? '');
- if (info !== null) {
- promptAction.showToast({
- message: JSON.stringify(info)
- });
- }
- }
- hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? '');
- }).catch((err: BusinessError) => {
- hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
- });
- })
- }
- //...
- }
- //...
- }
- //...
- }
- }
复制代码 启动UIAbility的指定页面
一个UIAbility可以对应多个页面,在差别的场景下启动该UIAbility时需要展示差别的页面,可以通过如下方式进行。
调用方
调用方UIAbility启动另外一个UIAbility时,通常需要跳转到指定的页面。此时需要在传入的want参数中设置指定的页面路径信息,可以通过want中的parameters参数增加一个自定义参数传递页面跳转信息。
目标UIAbility冷启动
目标UIAbility冷启动时,在目标UIAbility的onCreate()生命周期回调中,吸取调用方传过来的参数。然后在目标UIAbility的onWindowStageCreate()生命周期回调中,解析EntryAbility传递过来的want参数,获取到需要加载的页面信息url,传入windowStage.loadContent()方法。
目标UIAbility热启动
在应用开发中,会遇到目标UIAbility实例之前已经启动过的场景,这时再次启动目标UIAbility时,不会重新走初始化逻辑,只会直接触发onNewWant()生命周期方法。为了实现跳转到指定页面,需要在onNewWant()中解析参数进行处理。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |