鸿蒙UIAbility组件进阶

news2024/11/13 12:08:32

鸿蒙UIAbility组件进阶

  • AbilityStage
    • 基本概念
    • 生命周期
    • 使用方式
  • UIAbility组件间交互
    • 启动应用内的UIAbility
    • 启动应用内的UIAbility并获取返回结果
    • 启动UIAbility的指定页面
      • 调用方
      • 目标UIAbility冷启动
      • 目标UIAbility热启动

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时:

  1. 如果该UIAbility所在的HAP还没有加载到进程中,那么系统会将HAP加载到进程中,创建一个AbilityStage实例。创建成功后,执行AbilityStage的onCreate生命周期函数,可以在该方法中进行一些module级别的资源初始化。
  2. 创建UIAbility实例,创建成功后,回调UIAbility的onCreate生命周期函数,可以在该回调函数中初始化一些业务逻辑。
  3. 系统为该UIAbility实例创建一个WindowStage实例,创建完成后,会回调UIAbility的onWindowStageCreate生命周期回调函数,可以在该回调函数中获取主窗口信息,设置UI界面以及监听WindowStage的生命周期变化。

如下图所示:
在这里插入图片描述

在鸿蒙中,应用组件和UI之间的生命周期是松耦合的,在这种设计模式下,有几个好处

  • 业务逻辑与UI分离,我们可以在UIAbility中处理一些与UI无关的业务逻辑,如打开蓝牙,连接数据库等。而在WindowStage持有的窗口上去处理界面相关的业务逻辑。

  • 便于系统对应用组件进行裁剪。比如无屏设备,系统在创建时不会创建窗口模块,可以减少运行内存占用。

  • 在多设备上,应用组件可以使用同一套生命周期。

    单窗口模式:
    在这里插入图片描述
    这个流程会触发App1中WindowStage的hiddeninActive生命周期,触发UIAbility中的background生命周期;同时触发App2中WindowStage的shownactive生命周期,触发UIAbility中的foreground生命周期。

    多窗口模式:
    在这里插入图片描述
    这个流程只会触发App1中WindowStage的inActive生命周期函数,同时触发App2中WindowStage的active生命周期函数。而不会触发两个app中各自UIAbility中的生命周期函数。

生命周期

AbilityStage共有四个生命周期函数

  • onCreate:AbilityStage实例创建完成后回调的生命周期函数,可以在这里进行Module的初始化操作。
  • onAcceptWant:UIAbility指定实例模式启动时,会触发该回调,在该回调中,我们需要返回一个唯一的key值,系统用于判断指定的实例是否已经存在。
  • onConfigurationUpdated:系统全局配置发生改变时触发的回调函数,如系统语言,深浅色等。可以在该函数中接收到系统最新的配置信息。
  • onMemoryLevel:系统调整内存时触发的函数。

使用方式

  1. 在工程Module对应的ets目录下,右键选择“New > Directory”,新建一个目录并命名为myabilitystage。

  2. 在myabilitystage目录,右键选择“New > ArkTS File”,新建一个文件并命名为MyAbilityStage.ts。

  3. 打开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';
      }
    }
    
  4. 在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。

  1. 在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.');
                });
              })
            }
            //...
          }
          //...
        }
        //...
      }
    }
    
  2. 在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;
      }
      //...
    }
    
  3. 在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。

  1. 如需要关闭应用所有的UIAbility实例,可以调用ApplicationContext的killAllProcesses()方法实现关闭应用所有的进程。

启动应用内的UIAbility并获取返回结果

在一个EntryAbility启动另外一个FuncAbility时,希望在被启动的FuncAbility完成相关业务后,能将结果返回给调用方。例如在应用中将入口功能和账号登录功能分别设计为两个独立的UIAbility,在账号登录UIAbility中完成登录操作后,需要将登录的结果返回给入口UIAbility。

  1. 在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}`);
                });
              })
            }
            //...
          }
          //...
        }
        //...
      }
    }
    
  2. 在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;
                  }
                });
              })
            }
            //...
          }
          //...
        }
        //...
      }
    }
    
  3. 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()中解析参数进行处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2094919.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Promise 工具箱:手写实现静态方法的完全指南

前言 📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步! 🍅 个人主页:南木元元 Promise有很多静态方法,本文就来分享下如何实现这些静态方法。 目录 …

Markdown语法与Latex公式汇总

1 基本语法 1.1 标题 语法如下: 效果如下: 1.2 字体样式 语法效果普通正文字体普通正文字体*倾斜字体*倾斜字体**加粗字体**加粗字体***倾斜加粗字体***倾斜字体~~划线字体~~倾斜字体 1.3 分割线 语法如下: 效果如下: …

【C++11及其特性】C++类型转换

C类型转换目录 一.C语言的强制类型转换二.static_cast1.父类子类之间指针或引用的转换2.基本数据类型的转换3.空指针转换其他类型指针4.其他类型指针转换为空指针5.static_cast特点6.完整代码 三.reinterpret_cast1.数值与指针之间的转换2.不同类型指针和引用之间的转换3.reint…

【网络安全】重置邮件逻辑漏洞导致账户接管

未经许可,不得转载。 文章目录 正文 正文 目标:xxx.com 点击重置密码,系统会发送一封链接至邮箱。响应如下: 从上图中可以看到,validationSession对象中有一个sessionID 而收到的链接中的token和sessionID的值是一样…

总结之Coze 是一站式 AI Bot 开发平台——使用coze(一)

Coze 是什么? Coze 是新一代一站式 AI Bot 开发平台。无论你是否有编程基础,都可以在 Coze 平台上快速搭建基于 AI 模型的各类问答 Bot,从解决简单的问答到处理复杂逻辑的对话。并且,你可以将搭建的 Bot 发布到各类社交平台和通讯…

[Leetcode 51][Hard]-n皇后问题-回溯

目录 一、题目描述 二、整体思路 三、代码 一、题目描述 原题地址 二、整体思路 这种可以算是组合问题的变种,在回溯函数中我们要保存当前已放置皇后的所有位置,同时递归调用时要进行寻找下一个皇后的放置位置。那么我们可以逐行遍历棋盘并作为递归调…

STM32学习记录-10-2-SPI通信(硬件)

1 SPI外设简介 STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担 可配置8位/16位数据帧、高位先行/低位先行 时钟频率: fPCLK / (2, 4, 8, 16, 32, 64, 128, 256) 支持多主机模型、主或从操作 可精简为半双工/单工通信 支持…

python源码 PBOCMaster MAC的计算函数及计算过程 2des

注意最后一步要用整个key加密 计算过程: MAC: PBOC-MAC DES算法 密钥 长度16(0x10)字节 57 75 20 4D 69 61 6F 6A 75 6E 40 47 26 44 43 11 初始向量 长度8(0x08)字节 00 00 00 00 00 00 00 00 数据 长度74(0x4A)字节 43 48 45 4E 48 41 4F 2D 50 43 7…

如何成为一个飞控算法工程师?

兄弟,这个问题问得好,但也别想着靠看几本书就能一步登天。飞控算法这玩意儿,真要干好了,不是简简单单几个公式几个库就能搞定的。你本科电子专业有点基础,玩过四轴飞行器也算是入门了,但要搞真算法&#xf…

做克隆虚拟机的basic

新建一台虚拟机(之前写的有这一步) 虚拟机里操作 vi /etc/hostname 改称basic (可改可不改) vi /etc/sysconfig/network-scripts/ifcfg-ens33 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic DEFROUTEyes IPV4_FAILURE_FATALno IP…

★ 算法OJ题 ★ 力扣 LCR179 - 和为 s 的两个数字

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;小诗歌剧将和大家一起做一道双指针算法题--和为 s 的两个数字~ 目录 一 题目 二 算法解析 三 编写算法 一 题目 LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 二 算法解析 …

静态工厂模式(简单工厂模式)与动态工厂模式(工厂方法模式)

1. 简单工厂模式 核心是定义一个创建对象的接口&#xff0c;将对象的创建和本身的业务逻辑分离&#xff0c;降低系统的耦合度&#xff0c;使得两个修改起来相对容易些&#xff0c;当以后实现改变时&#xff0c;只需要修改工厂类即可。该模式对对象创建管理方式最为简单&#x…

list的使用与迭代器的模拟实现

前面学习了string&#xff0c;vector类的使用及模拟&#xff0c;但是它们有一个统一的特点就是底层的内存是连续的&#xff0c;因此迭代器的实现也很简单。现在我们开始学习list类的使用&#xff0c;模拟实现&#xff0c;来看看这个底层内存不是连续的有什么特别之处&#xff0…

2024 SEKAI-CTF(nolibc speedpwn life_simulator_2)

文章目录 nolibcexp speedpwnexp life_simulator_2委托构造函数委托构造函数的语法解释 std:remove和std:erase代码解释原理内存管理注意事项 思路1. 背景2. 示例代码3. 解释 vector插入逻辑1. 函数参数2. 本地变量3. 逻辑分析4. 扩容逻辑5. 直接插入逻辑6. 返回结果 exp nolib…

集成电路学习:什么是FPGA现场可编程门阵列

一、FPGA&#xff1a;现场可编程门阵列 FPGA&#xff0c;全称Field Programmable Gate Array&#xff0c;即现场可编程门阵列&#xff0c;是一种超大规模可编程逻辑器件。它由可编程逻辑资源、可编程互连资源和可编程输入输出资源组成&#xff0c;主要用于实现以状态机为主要特…

【计算机组成原理】七、输入/输出系统:2.I/O接口、I/O控制方式

I/O接口、I/O控制方式 2. I/O接口 文章目录 I/O接口、I/O控制方式2. I/O接口2.1 I/O接口的作用2.2 结构2.3 工作原理2.4 I/O端口2.5 分类 3. I/O控制方式3.1程序查询方式3.2程序中断方式3.2.1中断系统3.2.2工作流程3.2.3多重中断与中断屏蔽技术3.2.4程序中断方式 3.3DMA控制方…

Excel技巧(二)

函数 SUMIFS函数 用于计算其满足多个条件的全部参数的总量 语法&#xff1a;SUMIFS(sum_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...) COUNTIFS函数 计算多个区域中满足给定条件的单元格的个数 语法&#xff1a;countifs(criteria_range1,crit…

【Python报错已解决】`ModuleNotFoundError: No module named ‘graphviz‘`

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言&#xff1a; 在开发过程中&#xff0c;你是否遇到过尝试导入graphviz模块时遇到了ModuleNotFoundError: No module named …

突发:Runway删库跑路,备受瞩目的Stable Diffusion v1.5不见了!

Runway AI, Inc.创立于2018年&#xff0c;总部位于美国纽约州New York&#xff0c;Runway 是一家应用人工智能研究公司。Runway在谷歌领投的D轮融资中募集到约一亿美元。Runway不仅是投资界的新星&#xff0c;其产品Runway ML参与制作的《瞬息全宇宙》更是斩获了奥斯卡最佳女主…

Mysql基础练习题 1084.销售分析 (力扣)

编写解决方案&#xff0c;报告 2019年春季 才售出的产品。即 仅 在 2019-01-01 &#xff08;含&#xff09;至 2019-03-31 &#xff08;含&#xff09;之间出售的商品 题目链接&#xff1a; https://leetcode.cn/problems/sales-analysis-iii/description/ 建表插入数据&…