一、UIAbility 概述
UIAbility 是一种蕴含用户界面的利用组件,次要用于和用户进行交互。UIAbility 也是系统调度的单元,为利用提供窗口在其中绘制界面。每一个 UIAbility 实例,都对应于一个最近工作列表中的工作。一个利用能够有一个 UIAbility,也能够有多个 UIAbility,如下图所示。
例如浏览器利用能够通过一个 UIAbility 联合多页面的模式让用户进行的搜寻和浏览内容;而聊天利用减少一个“外卖性能”的场景,则能够将聊天利用中“外卖性能”的内容独立为一个 UIAbility,当用户关上聊天利用的“外卖性能”,查看外卖订单详情,此时有新的聊天音讯,即能够通过最近工作列表切换回到聊天窗口持续进行聊天对话。
一个 UIAbility 能够对应于多个页面,倡议将一个独立的功能模块放到一个 UIAbility 中,以多页面的模式出现。例如新闻利用在浏览内容的时候,能够进行多页面的跳转应用。
二、UIAbility 页面跳转和数据传递
UIAbility 的数据传递包含有 UIAbility 内页面的跳转和数据传递、UIAbility 间的数据跳转和数据传递,本章节次要解说 UIAbility 内页面的跳转和数据传递。
在一个利用蕴含一个 UIAbility 的场景下,能够通过新建多个页面来实现和丰盛利用的内容。这会波及到 UIAbility 内页面的新建以及 UIAbility 内页面的跳转和数据传递。
关上 DevEco Studio,抉择一个 Empty Ability 工程模板,创立一个工程,例如命名为 MyApplication。
- 在 src/main/ets/entryability 目录下,初始会生成一个 UIAbility 文件 EntryAbility.ts。能够在 EntryAbility.ts 文件中依据业务须要实现 UIAbility 的生命周期回调内容。
- 在 src/main/ets/pages 目录下,会生成一个 Index 页面。这也是基于 UIAbility 实现的利用的入口页面。能够在 Index 页面中依据业务须要实现入口页面的性能。
- 在 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
@Component
struct 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
@Component
struct 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 的 AbilityContext
context.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