为有牺牲多壮志,敢教日月换新天。

HarmonyOS:UIAbility进阶

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤博客园地址:为敢技术(https://www.cnblogs.com/strengthen/ 
➤GitHub地址:https://github.com/strengthen
➤原文地址:https://www.cnblogs.com/strengthen/p/18487373
➤如果链接不是为敢技术的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

一、基本概念
1、UIAbility组件:一种包含UI的应用组件,主要用于和用户交互。在开发态新建一个项目时,IDE默认生成一个持有UIAbility组件的model作为应用的主模块。该模块用于实现应用的入口界面和主特性功能。系统默认的EntryAbility类继承了UIAbility类。

2、ExtensionAblility组件:定义见下图。各类型的ExtensionAbility组件均由相应的系统服务统一管理。例如InputMethodExtensionAbility组件由输入法管理服务统一管理。目前ExtensionAbility组件类型有:

(1)、用于输入法场景的InputMethodExtensionAbility。

(2)、用于闲时任务场景的WorkSchedulerExtensionAbility。在IDE中支持选中Module后创建不同类型的ExtensionAbility组件文件。如下图所示:

3、HAP:定义见下图。一个APP可以包含一个或多个HAP。当HAP中的代码首次被加载到进程中时,也就是Module初始化时,系统会首先创建一个AbilityStage实例。包含UIAbility组件或者ExtensionAbility组件的Module可以单独运行,该类型Module运行时会编译生成一个.hap文件,即:HAP。

4、AbilityStage:定义见下图。AbilityStage是一个Module级别的组件容器,可以管理Module中的UIAbility组件和ExtensionAbility组件。AbilityStage与编译期的HAP是一一对应关系。

 5、上述四个概念在运行期和编译期的关系。

在开发时,一个项目可能需要包含一个或多个可以单独运行的Module,对应到运行期,一个应用即一个Application,就可能包含1个或多个AbilityStage。对应到编译期,一个App可能包含一个或多个HAP。 在运行期, 每个AbilityStage持有Module上定义的UIAbility组件和ExtensionAbility组件。当UIAbility组件首次启动时,系统会为UIAbility组件创建实例,并将该实例与持有它的AbilityStage实例关联,开发者可以通过AbilityStage获取该UIAbility实例的运行时信息。UIAbility实例创建后,系统为该实例创建一个WindowStage实例,并一对一绑定,WindowStage提供了应用进程类窗口管理器的作用,它持有一个主窗口,该主窗口为ArkUI提供了绘制区域,并管理多个ArkUI页面,在运行期系统为Application、AbilityStage、UIAbility组件和ExtensionAbility组件分别提供了对应的上下文环境,分别是ApplicationContext、AbilityStageContext、UIAbilityContext组件和ExtensionAbilityContext,开发者可以通过上下文环境调用各种资源和能力。运行期和编译期的基本概念中最重要的就是UIAbility组件,UIAbility组件的核心是生命周期,当用户启动、使用和退出应用时,应用的UIAbility实例会在其生命周期的不同状态之间转换。

 UIAbility组件、AbilityStage、WindowStage间的生命周期的关系。

 UIAbility组件和WindowStage各自拥有一套生命周期,在设备上首次启动某个UIAbility组件时,UIAbility组件、AbilityStage、WindowStage的生命周期执行顺序如下图所示:系统首先创建持有该UIAbility组件的AbilityStage实例,创建成功后,执行其onCreate生命周期回调函数,开发者可以通过重写该函数,再进行一些Module级别的资源初始化,或临时全局共享数据的设置工作,接下来,系统会为该UIAbility组件创建实例,创建成功后绘制执行其onCreate生命周期回调函数,可以在该函数中初始化业务逻辑,例如变量定义、资源加载等,用于后续的UI展示,onCreate函数执行完成后,系统将为UIAbility实例创建一个WindowStage实例,创建成功后实行UIAbility实例的onWindowStageCreate回调函数,可以通过该函数,获取主窗口信息、设置UI加载界面,以及监听WindowStage的生命周期变化,相应的,在UIAbility实例销毁之前,将先进入onWindowStageDestroy回调函数,开发者可以在该函数中释放UI界面资源,例如:在onWindowStageDestroy函数中注销WindowStage的事件,可以看到应用组件和窗口的生命周期是松耦合的。这种设计模式有如下好处:

(1)、业务逻辑和UI逻辑分离。开发者可以在UIAbility组件中处理与页面无关的业务逻辑,如打开蓝牙,连接数据库等,在WindowStage持有的窗口上,通过ArkUI处理界面相关的业务逻辑。

(2)、便于系统对应用组件进行裁剪。例如:对无屏设备,系统在运行应用时,不会创建窗口模块,有利于减少系统ROM空间占用。

(3)、 在多设备(桌面设备和移动设备上),应用组件可使用同一套生命周期,应用运行时,系统会自动判断设备,并根据不同设备的窗口形态变换,执行不同的生命周期变化流程。

以在单窗口形态上和多窗口形态上任务切换的场景为例,在设备上一个UIAbility实例对应于任务视图的一个任务,在单窗口形态如移动设备上,当用户从任务一切换到任务二时,对于任务一,会触发其WindowStage的InActive失焦和Hidden隐藏生命周期,继而触发其UIAbility实例的Background生命周期。对于任务二,会触发其WindowStage的Shown显式和Active聚集生命周期,继而触发其UIAbility实例的Foreground生命周期。同理,多窗口形态(如2in1)见下图: 

二、AbilityStage组件容器
需要学习持有UIAbility组件的AbilityStage组件容器,以及在使用IDE开发过程中如何使用它的能力。
1、AbilityStage是Module级别的组件容器,是HAP的运行期类,AbilityStage最主要的能力是初始化模块,以及对以指定实例模式启动的UIAbility组件进行匹配处理,目前系统提供了4个回调函数供开发者使用其能力。如下图:
(1)、onCreate:是AbilityStage实例创建完成之后触发的回调函数,开发者可以在此函数中进行模块初始化操作,如:资源预加载、线程创建等。
(2)、onAcceptWant:是制定实例模式等UIAbility组件启动时触发的回调函数,开发者可以在此函数中,对指定实例模式启动的UIAbility实例返回其唯一key值,用于系统判断该实例是否已经存在。
(3)、onConfigurationUpdated:系统全局配置发生变化时触发的函数,开发者可以在此函数中,接收到系统最新的全局配置信息,并按需进行业务逻辑处理。例如:可以在该函数中获取系统最新的深浅色模式,并根据当前深浅色模式对界面进行主体化定制,并根据当前深浅色模式对界面进行主体化定制。
(4)、onMemoryLevel:是系统调整内存时触发的函数。应用被切换到后台时,系统会将后台的应用保留在缓存中,即使应用处于缓存中也会影响系统整体的性能。当系统资源不足时,系统会通过多种方式从应用中回收内存,必要时会完全停止应用,从而释放内存用于执行关键任务。为了进一步保持系统内存的平衡,避免系统停止用户的应用进程,可以在onMemoryLevel数中订阅系统内存的变化情况。释放不必要的资源。

2、AbilityStage的创建与使用。DevEco默认工程中未自动生成AbilityStage,如需要使用AbilityStage的能力,需要手动新建一个AbilityStage文件。

(1)、新建AbilityStage目录:首先创建AbilityStage目录,如下图,在需要创建AbilityStage的Module的ets目录下,鼠标右键选择:【New-Directory】,创建一个目录并命名为myabilitystage,创建完成后,工程目录结构如下图所示。

(2)、新建AbilityStage文件:如下图所示,选中刚才新建的myabilitystage目录,鼠标右键选择:【New-ArkTS File】,新建一个ArkTS文件,并命名为MyAbilityStage,创建成功后,工程目录结构如下图所示:

(3)、自定义继承AbilityStage的类:打开刚才创建成功的MyAbilityStage.ets文件,在该文件中采用面向对象的方式,自定义MyAbilityStage类继承AbilityStage类,在MyAbilityStage类中,可以根据需要重写MyAbilityStage的四个回调函数。可以重写onCreate生命周期回调函数,并运行模块初始化操作。如:可以在该函数中设置全局的深浅色模式变量,用于主题定制化需求,也可以重写onAcceptWant事件回调函数,在该函数中,对指定实例模式启动的UIAbility实例。返回指定的字符串,用于标识该实例。

(4)、配置HAP加载入口:在Module的module.json5文件中,将刚才创建的MyAbilityStage.ets文件路径,配置到模块加载时到入口路径字段srcEntry上,如下图所示。配置完成后,当启动UIAbility组件时,系统将根据srcEntry字段的值找到AbilityStage所在的文件,并根据文件内容,创建相应的AbilityStage实例。

三、UIAbility组件的启动模式
1、UIAbility组件的启动模式,概念:是指UIAbility实例在启动时的不同呈现状态,针对不同的业务场景,在使用startAbility方法启动UIAbility组件时,系统提供了三种启动模式:
(1)、单实例启动模式(singlton):默认的启动模式,系统每次启动UIAbility组件时,如果应用进程中该类型的的UIAbility实例已经存在,则复用系统中的UIAbility实例,同一UIAbility组件在系统中只存在唯一一个UIAbility实例,即在任务视图中只存在一个该类型的任务。
(2)、多实例启动模式(multiton):系统每次启动UIAbility组件时,系统都会在应用进程中创建一个新的该类型的UIAbility实例,即在任务视图中可以看到有多个该类型的任务,如在2in1设备上的浏览器应用,每次打开浏览器都会创建一个浏览器任务窗口。
(3)、指定实例启动模式(speicfied):指定实例启动模式时针对一些特殊场景使用的。系统每次启动UIAbility组件时,会根据指定的key值匹配对应的UIAbility实例,若key值存在,则拉起对应的UIAbility实例,若key值不存在,则新建一个该类型的UIAbility实例。例如文档应用,每次新建文档时,需要新建一个UIAbility实例,每次打开一个已保存的文档时,需要拉起同一个UIAbility实例。

 2、三种启动模式的开发和执行过程。

(1)、单实例启动模式(singlton):设置方法,在该UIAbility组件所在模块的module.json5配置文件中,找到该UIAbility的配置信息,并设置其launchType字段为:singleton。

当UIAbility组件被设置为单实例启动模式后,它的执行过程如下图。当调用方通过startAbility函数启动UIAbility组件时,系统启动被调用的UIAbility组件,此时系统判断被调用的UIAbility组件是否为冷启动,通常将首次启动称为冷启动,非首次启动为热启动。若调用的UIAbility组件时冷启动,系统将新建该UIAbility组件的实例,并执行其onCreate生命周期回调函数。之后,系统将创建一个与该UIAbility实例一一对应的WinddowStage实例,创建成功后,执行该UIAbility实例的onWindowStageCreate函数,接着UIAbility实例将进入前台生命周期,并执行其onForeground生命周期回调函数,若被调用的UIAbility组件不是冷启动,系统将执行已经存在的该类型UIAbility实例的onNewWant回调函数,可以在该函数中解析从调用方传递过来的Want参数,并进行业务逻辑处理。Want参数的详细使用,可以参看下文:四、UIAbility组件间的交互。之后UIAbility实例进入前台生命周期,并执行其onForeground生命周期回调函数,以上就是配置了单实例启动模式的UIAbility组件在启动的整个执行过程。

(2)、多实例启动模式(multiton):在该UIAbility组件所在模块的module.json5配置文件中,找到该UIAbility的配置信息,并设置其launchType字段为:multiton。

当UIAbility组件被设置为多实例启动模式后,它的执行过程如下图。当调用方通过startAbility函数启动多实例启动模式的UIAbility组件时,系统启动被调用的UIAbility组件,此时系统每次都会新建一个该UIAbility组件的实例,并执行其onCreate生命周期回调函数,之后,系统将创建一个与该UIAbility实例一一对应的WindowStage实例,创建成功后执行该UIAbility实例的onWindowStageCreate函数,之后UIAbility实例进入前台生命周期,并执行其onForeground生命周期回调函数。

(3)、指定实例启动模式(speicfied):

模拟一个文档类应用,当点击【新建一个文档】按钮时,会新建一个UIAbility实例,并在任务视图中展示,当再次点击【新建一个文档】按钮时,系统会再次新建一个UIAbility实例,并在任务视图中展示,此时,在任务视图中看到刚才新建的两个UIAbility实例,将两个UIAbility实例对应的任务从任务视图中移除,此时点击【打开已保存文档】按钮,系统会新建相应的UIAbility实例,并在任务视图中展示,将任务切换回主界面,再次点击【打开已保存文档】按钮时,系统会拉起已经存在的文档实例,并在任务视图中展示,假设在该应用中,EntryAbility是调用方,负责加载应用的主界面,SpecifiedAbility是被调用方。实现代码的三步骤:
第一步:设置被调用的UIAbility组件的启动模式为指定实例启动模式,在该场景中,找到被调用的SpecifiedAbility所在的模块的module.json5文件,并在该文件中设置SpecifiedAbility的launchType字段为:specified。

第二步:在调用方的页面上开发启动UIAbility组件的逻辑函数,在该逻辑函数中包含三个步骤:

(a)、获取调用方的UIAbilityContext。以此获得启动UIAbility组件的能力。

(b)、创建want,在want中指定需要启动的UIAbility 组件名为:SpecifiedAbility,并自定义一个唯一参数,用于标识每个UIAbility实例。如:此处自定义参数名为instanceKey,该参数值通过自定义函数getInstanceKey获取,在点击打开文档的操作时,可以将文档路径和文档名拼接的字符串,作为入参传入getInstanceKey函数,在getInstanceKey函数中进行逻辑处理并返回唯一key值。

(c)、调用UIAbilityContext的startAbility函数,并将Want函数传入。

第三步:在被调用的UIAbility组件所在的AbilityStage中,重写onAcceptWant回调函数,在模拟文档的场景中,重写被调用方SpecifiedAbility所在的MyAbility.ets文件的onAcceptWant函数,在该函数中,判断启动的UIAbility组件名为:SpecifiedAbility时,返回Want中设置的唯一key值,系统将根据该函数返回的唯一key值,判断当前进程中对应的UIAbility实例是否存在。

指定实例启动模式的执行过程:

当调用方通过startAbility函数启动UIAbility组件时,系统启动被调用的UIAbility组件,在启动被调用的UIAbility组件之前,系统先触发持有被调用的UIAbility组件的AbilityStage的onAcceptWant回调函数,该函数会解析调用方传递的want信息,并返回被调用的UIAbility实例的唯一key值。系统根据返回的唯一key值,判断当前进程中该key值对应的UIAbility实例释放已经存在,若存在,则系统执行该UIAbility实例的onNewWant回调函数,之后UIAbility实例进入Foreground生命周期,并执行其onForeground回调函数,若不存在,则系统新建被调用的UIAbility组件实例,并执行其onCreate生命周期回调函数,随后创建对应的WindowStage实例,并执行UIAbility实例的onWindowStageCreate回调函数,最后UIAbility实例进入Foreground生命周期,并执行其onForeground回调函数。以上就是UIAbility组件指定实例启动模式的全部执行过程。

四、UIAbility组件间的交互
1、Want是对象间信息传递的载体,用于在应用组件之间传递信息,其使用场景之一是作为startAbility的参数,当UIAbilityA需要启动并需要传递一些数据给UIAbilityB时,Want可以作为一个载体将数据传递给UIAbilityB,Want中可以包含指定的启动目标以及启动时需要携带的相关数据,如:
bundleName字段:目标Ability所在应用的包名。
abilityName字段:Ability名。

2、使用Want启动UIAbility组件有两种形式,显式Want启动和隐式Want启动。

(1)、显式Want启动:是指在启动UIAbility组件时,在Want参数中指定了UIAbility组件名:abilityName,和应用包名:bundleName,这种形式用于启动某个明确UIAbility组件的场景。

(2)、隐式Want启动:是指在启动UIAbility组件时,在Want参数中不指定UIAbility组件名:abilityName,而是设置被启动应用具备的能力和类型等筛选条件。系统再根据筛选条件匹配支持该条件的所有应用。这种启动形式用于希望使用某个应用的能力,而不关心提供该能力的具体应用的场景。

 3、显式Want启动UIAbility组件的开发过程,包含3个步骤:

(1)、获取调用方的上下文信息UIAbilityContext。以此获取启动UIAbility组件的能力。

(2)、创建显式Want。在Want中明确指定要启动的应用包名:bundleName,和UIAbility组件名:abilityName。在Want的parameters字段中,可以自定义传递给要启动的UIAbility组件的信息,如此处自定义了参数:info。该参数值为:来自EntryAbility Index页面。在Want中还可以配置很多其他参数,如:deviceId表示启动的应用所在的设备,当deviceId为空或者不设置该字段时表示本设备。更多参数的详细使用可以参看官网指南。

(3)、调用UIAbilityContext的startAbility函数,并将刚创建的Want对象作为参数传入,系统启动调用的UIAbility组件时,对于被调用的UIAbility组件,可以通过启动时的回调函数,获取到调用方传递的Want对象,在回调函数中,通过解析Want对象可以获取调用方传递的信息,如调用方的PID,应用名和自定义传递的信息等。若被调用的UIAbility组件时冷启动,可以通过onCreate函数接收Want对象,若被调用的UIAbility组件是热启动,可以通过onNewWant函数接收Want对象。

调用方页面:

被调用方UIAbility文件:通过onCreate函数的入参获取调用方传递的Want对象,通过解析Want对象获取调用方传递的自定义信息:info

 3、隐式Want启动UIAbility组件的开发过程。

启动浏览器:

上面展示了隐式启动浏览器并打开网址的过程,在页面上点击【拉起浏览器类型应用并打开华为官方网址】时,系统将拉起应用中的浏览器类型应用,并自动打开华为官方网址。具体代码实现:

(1)、需要知道被调用的应用所支持的能力。

在被调用方的module.json5配置文件中,找到需要调用的UIAbility组件的相关配置信息,其中"skills"字段表示该UIAbility组件所支持的能力集,主要包含两个维度:

entities:表示UIAbility组件额外的类别信息,如:浏览器、视频播放器。

actions:表示UIAbility组件支持的通用操作,如:查看、分享数据。

假设浏览器应用在entities字段中添加了“entity.system.browsable”表明其为浏览器类型,在actions字段中添加了“ohos.want.action.viewData”表明应用支持查看数据。

(2)、在知道了被调用方的应用能力配置信息后,在调用方启动UIAbility组件时,需要做如下开发:

第一步:获取被调用方的UIAbilityContext,以此获取启动UIAbility组件的能力,

第二步:创建隐式Want。在Want中不指定abilityName字段,而是指定一系筛选条件。根据前面获得的浏览器应用配置信息,下图示例代码在want中设置筛选条件,entities字段为[entity.system.browsable],action字段为:ohos.want.action.viewData,为了浏览器应用启动后能够自动打开华为官网,在Want中指定跳转的网址信息,即设置uri字段值为:"https://www.huawei.com/cn"。

第三步:调用UIAbilityContext的startAbility方法,并将刚创建的Want作为参数传入,隐式启动UIAbility组件。

(3)、使用隐式Want启动UIAbility组件时,系统将根据Want对象中的筛选条件匹配符合条件的应用,有以下三种匹配结果:

  (a)、未匹配到满足条件的UIAbility组件时,启动失败。

  (b)、匹配到一个满足条件的UIAbility组件时,直接启动该UIAbility组件。

  (c)、匹配到多个满足条件的UIAbility组件时,系统弹出选择框,提供所有满足条件的应用供用户选择。

匹配完成后,可以在startAbility方法的.then()方法和.catch()方法中,分别处理启动成功的业务逻辑和启动失败的业务逻辑。以上就完成了隐式Want启动浏览器类型的应用开发。

posted @ 2024-10-20 15:38  为敢技术  阅读(10)  评论(0编辑  收藏  举报