一、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@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