一、UIAbility概述

UIAbility是一种蕴含用户界面的利用组件,次要用于和用户进行交互。UIAbility也是系统调度的单元,为利用提供窗口在其中绘制界面。每一个UIAbility实例,都对应于一个最近工作列表中的工作。一个利用能够有一个UIAbility,也能够有多个UIAbility,如下图所示。

例如浏览器利用能够通过一个UIAbility联合多页面的模式让用户进行的搜寻和浏览内容;而聊天利用减少一个“外卖性能”的场景,则能够将聊天利用中“外卖性能”的内容独立为一个UIAbility,当用户关上聊天利用的“外卖性能”,查看外卖订单详情,此时有新的聊天音讯,即能够通过最近工作列表切换回到聊天窗口持续进行聊天对话。

一个UIAbility能够对应于多个页面,倡议将一个独立的功能模块放到一个UIAbility中,以多页面的模式出现。例如新闻利用在浏览内容的时候,能够进行多页面的跳转应用。

二、UIAbility页面跳转和数据传递

UIAbility的数据传递包含有UIAbility内页面的跳转和数据传递、UIAbility间的数据跳转和数据传递,本章节次要解说UIAbility内页面的跳转和数据传递。

在一个利用蕴含一个UIAbility的场景下,能够通过新建多个页面来实现和丰盛利用的内容。这会波及到UIAbility内页面的新建以及UIAbility内页面的跳转和数据传递。

关上DevEco Studio,抉择一个Empty Ability工程模板,创立一个工程,例如命名为MyApplication。

  1. 在src/main/ets/entryability目录下,初始会生成一个UIAbility文件EntryAbility.ts。能够在EntryAbility.ts文件中依据业务须要实现UIAbility的生命周期回调内容。
  2. 在src/main/ets/pages目录下,会生成一个Index页面。这也是基于UIAbility实现的利用的入口页面。能够在Index页面中依据业务须要实现入口页面的性能。
  3. 在src/main/ets/pages目录下,右键,新建一个Second页面,用于实现页面间的跳转和数据传递。 

为了实现页面的跳转和数据传递,须要新建一个页面。在原有Index页面的根底上,新建一个页面,例如命名为Second.ets。

页面间的导航能够通过页面路由router模块来实现。页面路由模块依据页面url找到指标页面,从而实现跳转。通过页面路由模块,能够应用不同的url拜访不同的页面,包含跳转到UIAbility内的指定页面、用UIAbility内的某个页面替换以后页面、返回上一页面或指定的页面等。

2.1 页面跳转和参数传递

router模块的页面跳转的几种形式,依据须要抉择一种形式跳转即可。

形式一

实用于API 9及以上,router.pushUrl()办法新增了mode参数,能够将mode参数配置为router.RouterMode.Single单实例模式和router.RouterMode.Standard多实例模式。

在单实例模式下,如果指标页面的url在页面栈中曾经存在同url页面,离栈顶最近同url页面会被挪动到栈顶,挪动后的页面为新建页,原来的页面依然存在栈中,页面栈的元素数量不变;如果指标页面的url在页面栈中不存在同url页面,按多实例模式跳转,页面栈的元素数量会加1。

router.pushUrl({  url: 'pages/Second',  params: {    src: 'Index页面传来的数据',  }}, router.RouterMode.Single)
形式二

实用于API 9及以上,router.replaceUrl()办法新增了mode参数,能够将mode参数配置为router.RouterMode.Single单实例模式和router.RouterMode.Standard多实例模式。

在单实例模式下,如果指标页面的url在页面栈中曾经存在同url页面,离栈顶最近同url页面会被挪动到栈顶,替换以后页面,并销毁被替换的以后页面,挪动后的页面为新建页,页面栈的元素数量会减1;如果指标页面的url在页面栈中不存在同url页面,按多实例模式跳转,页面栈的元素数量不变。

router.replaceUrl({  url: 'pages/Second',  params: {    src: 'Index页面传来的数据',  }}, router.RouterMode.Single)

接下来,咱们看一下如何在Second页面中接管自定义参数。很简略,通过调用router.getParams()办法即可获取Index页面传递过去的自定义参数。

import router from '@ohos.router';@Entry@Componentstruct Second {  @State src: string = router.getParams()?.['src'];  // 页面刷新展现  ...}

运行下面的代码,成果示意如下图所示。

除此之外,咱们常常还会遇到一个场景,在Second页面中,实现了一些性能操作之后,心愿能返回到Index页面,那咱们要如何实现呢?

在Second页面中,能够通过调用router.back()办法实现返回到上一个页面,或者在调用router.back()办法时减少可选的options参数(减少url参数)返回到指定页面。

router.back();router.back({ url: 'pages/Index' });

成果示意如下图所示。在Second页面中,点击“Back”后,即可从Second页面返回到Index页面。

当然,页面返回能够依据业务须要减少一个询问对话框。即在调用router.back()办法之前,能够先调用router.enableBackPageAlert()办法开启页面返回询问对话框性能。

router.enableBackPageAlert({  message: 'Message Info'});router.back();

在Second页面中,调用router.back()办法返回上一个页面或者返回指定页面时,依据须要持续减少自定义参数,例如在返回时减少一个自定义参数src。

router.back({  url: 'pages/Index',  params: {    src: 'Second页面传来的数据',  }})

接着,从Second页面返回到Index页面。在Index页面通过调用router.getParams()办法,获取Second页面传递过去的自定义参数。同时,能够放在业务须要的地位进行参数解析。示例代码在Index页面中的onPageShow()生命周期回调中进行参数的解析。

import router from '@ohos.router';@Entry@Componentstruct Index {  @State src: string = '';  onPageShow() {    this.src = router.getParams()?.['src'];  }  ...   // 页面刷新展现}

在Second页面中,点击“Back”后,即可从Second页面返回到Index页面,并在Index页面中接管参数和进行页面刷新展现。成果如下图所示。

三、UIAbility的生命周期

当用户浏览、切换和返回到对应利用的时候,利用中的UIAbility实例会在其生命周期的不同状态之间转换。

UIAbility类提供了很多回调,通过这些回调能够通晓以后UIAbility的某个状态曾经产生扭转:例如UIAbility的创立和销毁,或者UIAbility产生了前后台的状态切换。例如从桌面点击图库利用图标,到启动图库利用,利用的状态通过了从创立到前台展现的状态变动。如下图所示。

回到桌面,从最近工作列表,切换回到图库利用,利用的状态通过了从后盾到前台展现的状态变动,如下图所示。

在UIAbility的应用过程中,会有多种生命周期状态。把握UIAbility的生命周期,对于利用的开发十分重要。

为了实现多设施状态上的裁剪和多窗口的可扩展性,系统对组件治理和窗口治理进行理解耦。UIAbility的生命周期包含Create、Foreground、Background、Destroy四个状态,WindowStageCreate和WindowStageDestroy为窗口管理器(WindowStage)在UIAbility中治理UI界面性能的两个生命周期回调,从而实现UIAbility与窗口之间的弱耦合,如下图所示。

上面咱们就来看一下这些生命前期状态:

Create

在UIAbility实例创立时触发,零碎会调用onCreate回调,能够在onCreate回调中进行相干初始化操作。例如用户关上电池治理利用,在利用加载过程中,在UI页面可见之前,能够在onCreate回调中读取以后零碎的电量状况,用于后续的UI页面展现。

import UIAbility from '@ohos.app.ability.UIAbility';import window from '@ohos.window';export default class EntryAbility extends UIAbility {    onCreate(want, launchParam) {        // 利用初始化        ...    }    }
onWindowStageCreate

UIAbility实例创立实现之后,在进入Foreground之前,零碎会创立一个WindowStage。每一个UIAbility实例都对应持有一个WindowStage实例。 

WindowStage为本地窗口管理器,用于治理窗口相干的内容,例如与界面相干的获焦/失焦、可见/不可见。能够在onWindowStageCreate回调中,设置UI页面加载、设置WindowStage的事件订阅。

在onWindowStageCreate(windowStage)中通过loadContent接口设置利用要加载的页面,Window接口的应用详见窗口开发领导。

import UIAbility from '@ohos.app.ability.UIAbility';import window from '@ohos.window';export default class EntryAbility extends UIAbility {    ...    onWindowStageCreate(windowStage: window.WindowStage) {        // 设置UI页面加载        // 设置WindowStage的事件订阅(获焦/失焦、可见/不可见)        ...        windowStage.loadContent('pages/Index', (err, data) => {            ...        });    }    ...}

例如,用户关上游戏利用,正在打游戏的时候,有一个音讯告诉,关上音讯,音讯会以弹窗的模式弹出在游戏利用的上方,此时,游戏利用就从获焦切换到了失焦状态,音讯利用切换到了获焦状态。对于音讯利用,在onWindowStageCreate回调中,会触发获焦的事件回调,能够进行设置音讯利用的背景色彩、高亮等操作。

 

Foreground和Background

Foreground和Background状态,别离在UIAbility切换至前台或者切换至后盾时触发。

别离对应于onForeground回调和onBackground回调。

onForeground回调,在UIAbility的UI页面可见之前,即UIAbility切换至前台时触发。能够在onForeground回调中申请零碎须要的资源,或者从新申请在onBackground中开释的资源。

onBackground回调,在UIAbility的UI页面齐全不可见之后,即UIAbility切换至后盾时候触发。能够在onBackground回调中开释UI页面不可见时无用的资源,或者在此回调中执行较为耗时的操作,例如状态保留等,如下所示。

import UIAbility from '@ohos.app.ability.UIAbility';import window from '@ohos.window';export default class EntryAbility extends UIAbility {    ...    onForeground() {        // 申请零碎须要的资源,或者从新申请在onBackground中开释的资源        ...    }    onBackground() {        // 开释UI页面不可见时无用的资源,或者在此回调中执行较为耗时的操作                ...        // 例如状态保留等    }}

例如用户关上地图利用查看以后地理位置的时候,假如地图利用已取得用户的定位权限受权。在UI页面显示之前,能够在onForeground回调中关上定位性能,从而获取到以后的地位信息。当地图利用切换到后盾状态,能够在onBackground回调中进行定位性能,以节俭零碎的资源耗费。

onWindowStageDestroy

在UIAbility实例销毁之前,则会先进入onWindowStageDestroy回调,咱们能够在该回调中开释UI页面资源。例如,在onWindowStageCreate中设置的获焦/失焦等WindowStage订阅事件。

import UIAbility from '@ohos.app.ability.UIAbility';import window from '@ohos.window';export default class EntryAbility extends UIAbility {    ...    onWindowStageDestroy() {        // 开释UI页面资源        ...    }}
Destroy

Destroy状态,在UIAbility销毁时触发。能够在onDestroy回调中进行系统资源的开释、数据的保留等操作。

import UIAbility from '@ohos.app.ability.UIAbility';import window from '@ohos.window';export default class EntryAbility extends UIAbility {    ...    onDestroy() {        // 系统资源的开释、数据的保留等        ...    }}

例如,用户应用利用的程序退出性能,会调用UIAbilityContext的terminalSelf()办法,从而实现UIAbility销毁。或者用户应用最近工作列表敞开该UIAbility实例时,也会实现UIAbility的销毁。

四、UIAbility的启动模式

搞过Android开发的同学都晓得,Android的Activity是有本人的启动模式的。同样,UIAbility也有本人的启动模式来适配不同的应用场景,UIAbility以后反对singleton(单实例模式)、multiton(多实例模式)和specified(指定实例模式)3种启动模式。

以下是对启动模式的具体阐明:

  • singleton(单实例模式)

当用户关上浏览器或者新闻等利用,并浏览拜访相干内容后,回到桌面,再次关上该利用,显示的依然是用户以后拜访的界面。这种状况下能够将UIAbility配置为singleton(单实例模式)。每次调用startAbility()办法时,如果利用过程中该类型的UIAbility实例曾经存在,则复用零碎中的UIAbility实例,零碎中只存在惟一一个该UIAbility实例。即在最近工作列表中只存在一个该类型的UIAbility实例。

  • multiton(多实例模式)

用户在应用分屏性能时,心愿同时应用两个不同利用(例如备忘录利用和图库利用)之间进行分屏,也心愿能应用同一个利用(例如备忘录利用本身)进行分屏。这种状况下能够将UIAbility配置为multiton(多实例模式),每次调用startAbility()办法时,都会在利用过程中创立一个该类型的UIAbility实例。即在最近工作列表中能够看到有多个该类型的UIAbility实例。

  • specified(指定实例模式)

用户打开文档利用,从文档利用中关上一个文档内容,回到文档利用,持续关上同一个文档,心愿关上的还是同一个文档内容;以及在文档利用中新建一个新的文档,每次新建文档,心愿关上的都是一个新的空白文档内容。

这种状况下能够将UIAbility配置为specified(指定实例模式)。在UIAbility实例新创建之前,容许开发者为该实例创立一个字符串Key,新创建的UIAbility实例绑定Key之后,后续每次调用startAbility办法时,都会询问利用应用哪个Key对应的UIAbility实例来响应startAbility申请。如果匹配有该UIAbility实例的Key,则间接拉起与之绑定的UIAbility实例,否则创立一个新的UIAbility实例。运行时由UIAbility外部业务决定是否创立多实例。

 

singleton启动模式

singleton启动模式,也是默认状况下的启动模式。singleton启动模式,每次调用startAbility()启动UIAbility时,如果利用过程中该类型的UIAbility实例曾经存在,则复用零碎中的UIAbility实例,零碎中只存在惟一一个该UIAbility实例。

singleton启动模式的开发应用,在module.json5文件中的“launchType”字段配置为“singleton”即可,如下所示。

{   "module": {     ...     "abilities": [       {         "launchType": "singleton",         ...       }     ]  }}
multiton启动模式

multiton启动模式,每次调用startAbility()办法时,都会在利用过程中创立一个该类型的UIAbility实例。multiton启动模式的开发应用,在module.json5文件中的“launchType”字段配置为“multiton”即可。

{   "module": {     ...     "abilities": [       {         "launchType": "multiton",         ...       }     ]  }}

 

specified启动模式

specified启动模式,依据业务须要是否创立一个新的UIAbility实例。在UIAbility实例创立之前,会先进入AbilityStage的onAcceptWant回调,在onAcceptWant回调中为每一个UIAbility实例创立一个Key,后续每次调用startAbility()办法创立该类型的UIAbility实例都会询问应用哪个Key对应的UIAbility实例来响应startAbility()申请。 

specified启动模式的开发应用的步骤如下所示。

1,首先,在module.json5文件中的“launchType”字段配置为“specified”。

{   "module": {     ...     "abilities": [       {         "launchType": "specified",         ...       }     ]  }}

2,在调用startAbility()办法的want参数中,减少一个自定义参数来区别UIAbility实例,例如减少一个“instanceKey”自定义参数。

// 在启动指定实例模式的UIAbility时,给每一个UIAbility实例配置一个独立的Key标识function getInstance() {    ...}let want = {    deviceId: "", // deviceId为空示意本设施    bundleName: "com.example.myapplication",    abilityName: "MainAbility",    moduleName: "device", // moduleName非必选,默认为以后UIAbility所在的Module    parameters: { // 自定义信息        instanceKey: getInstance(),    },}// context为启动方UIAbility的AbilityContextcontext.startAbility(want).then(() => {    ...}).catch((err) => {    ...})

3,在被拉起方UIAbility对应的AbilityStage的onAcceptWant生命周期回调中,解析传入的want参数,获取“instanceKey”自定义参数。依据业务须要返回一个该UIAbility实例的字符串Key标识。如果之前启动过此Key标识的UIAbility,则会将之前的UIAbility拉回前台并获焦,而不创立新的实例,否则创立新的实例并启动。

onAcceptWant(want): string {    // 在被启动方的AbilityStage中,针对启动模式为specified的UIAbility返回一个UIAbility实例对应的一个Key值    // 以后示例指的是device Module的EntryAbility   if (want.abilityName === 'MainAbility') {        return `DeviceModule_MainAbilityInstance_${want.parameters.instanceKey}`;    }    return '';}

例如在文档利用中,能够对不同的文档实例内容绑定不同的Key值。当每次新建文档的时候,能够传入不同的新Key值(如能够将文件的门路作为一个Key标识),此时AbilityStage中启动UIAbility时都会创立一个新的UIAbility实例;当新建的文档保留之后,回到桌面,或者新关上一个已保留的文档,回到桌面,此时再次关上该已保留的文档,此时AbilityStage中再次启动该UIAbility时,关上的依然是之前原来已保留的文档界面。

源码链接:https://gitee.com/harmonyos/codelabs/tree/master/PagesRouter