赞
踩
UIAbility组件是一种包含UI界面的应用组件,主要用于和用户交互。直白来说就是构建页面,可以通过多个页面来实现功能模块。
创建的module默认情况下就是一个ability,除此之外还有HAR(静态资源包)和HSP(动态共享包),主要用于module间共用资源,后续会做详细讲解。
主要内容:
1. `ability module`目录结构及声明配置;
2. 生命周期;
3. 与UI界面数据同步;
4. 应用内`UIAbility`间跳转;
5. 启动模式;
如`media`中的`icon.png`,可以这样访问:
```js
- //页面中
-
- Image($r("app.media.icon"))
-
- // 配置文件中
-
- "icon": "$media:icon"
```
国际化使用(文本):
```js
- // element/string.json 默认文本
-
- {
-
- "string": [
-
- {
-
- "name": "title",
-
- "value": "柏木白"
-
- }
-
- ]
-
- }
-
- // en_US/element/string.json 英文
-
- {
-
- "string": [
-
- {
-
- "name": "title",
-
- "value": "1000phone"
-
- }
-
- ]
-
- }
-
- // zh_CN/element/string.json 中文
-
- {
-
- "string": [
-
- {
-
- "name": "title",
-
- "value": "柏木白"
-
- }
-
- ]
-
- }
-
- //页面中访问
-
- Text($r("app.string.title"))
-
- // 配置文件中
-
- "label": "$string:title"
```
为使应用能够正常使用`UIAbility`,需要在`module.json5`配置文件的`abilities`标签中声明`UIAbility`的名称、入口、标签等相关信息。
```js
- {
-
- "module": {
-
- // ...
-
- "abilities": [
-
- {
-
- "name": "EntryAbility", // UIAbility组件的名称
-
- "srcEntrance": "./ets/entryability/EntryAbility.ts", // UIAbility组件的代码路径
-
- "description": "$string:EntryAbility_desc", // UIAbility组件的描述信息
-
- "icon": "$media:icon", // UIAbility组件的图标
-
- "label": "$string:EntryAbility_label", // UIAbility组件的标签
-
- "startWindowIcon": "$media:icon", // UIAbility组件启动页面图标资源文件的索引
-
- "startWindowBackground": "$color:start_window_background", // UIAbility组件启动页面背景颜色资源文件的索引
-
- // ...
-
- }
-
- ]
-
- }
-
- }
```
当用户打开、切换和返回到对应应用时,应用中的`UIAbility`实例会在其生命周期的不同状态之间转换。
`UIAbility`的生命周期包括`Create`、`Foreground`、`Background`、`Destroy`四个状态,如下图所示。
`Create`状态为在应用加载过程中,`UIAbility`实例创建完成时触发,系统会调用`onCreate()`回调。可以在该回调中进行应用初始化操作,例如变量定义资源加载等,用于后续的UI界面展示。
```js
- import UIAbility from '@ohos.app.ability.UIAbility';
-
- import Window from '@ohos.window';
-
-
-
- export default class EntryAbility extends UIAbility {
-
- onCreate(want, launchParam) {
-
- // 应用初始化
-
- // want中包含如包代码路径、Bundle名称、Ability名称和应用程序需要的环境状态等属性信息
-
- // launchParam包含启动参数 主要在被其他UIAbility唤起时使用
-
- // 可通过this.context访问上下文对象 后续会做讲解
-
- }
-
- // ...
-
- }
```
`UIAbility`实例创建完成之后,在进入`Foreground`之前,系统会创建一个`WindowStage`。`WindowStage`创建完成后会进入`onWindowStageCreate()`回调,可以在该回调中设置UI界面加载、设置`WindowStage`的事件订阅。
在`onWindowStageCreate()`回调中通过`loadContent()`方法设置应用要加载的页面并根据需要订阅WindowStage的事件(获焦/失焦、可见/不可见)。
```js
- import UIAbility from '@ohos.app.ability.UIAbility';
-
- import Window from '@ohos.window';
-
-
-
- export default class EntryAbility extends UIAbility {
-
- onWindowStageCreate(windowStage: Window.WindowStage) {
-
- // 设置WindowStage的事件订阅(获焦/失焦、可见/不可见)
-
-
-
- // 设置UI界面加载
-
- windowStage.loadContent('pages/Index', (err, data) => {
-
- // ...
-
- });
-
- }
-
- }
```
对应于`onWindowStageCreate()`回调。在`UIAbility`实例销毁之前,则会先进入`onWindowStageDestroy()`回调,可以在该回调中释放UI界面资源。例如在`onWindowStageDestroy()`中注销获焦/失焦等`WindowStage`事件。
```js
- import UIAbility from '@ohos.app.ability.UIAbility';
-
- import Window from '@ohos.window';
-
-
-
- export default class EntryAbility extends UIAbility {
-
- onWindowStageDestroy() {
-
- // 释放UI界面资源
-
- }
-
- }
```
`Foreground`和`Background`状态分别在`UIAbility`实例切换至前台和切换至后台时触发,对应于`onForeground()`回调和`onBackground()`回调。
- `onForeground()`回调,在`UIAbility`的UI界面可见之前,如`UIAbility`切换至前台时触发。可以在`onForeground()`回调中申请系统需要的资源,或者重新申请在`onBackground()`中释放的资源。
- `onBackground()`回调,在`UIAbility`的UI界面完全不可见之后,如`UIAbility`切换至后台时候触发。可以在`onBackground()`回调中释放UI界面不可见时无用的资源,或者在此回调中执行较为耗时的操作,例如状态保存等。
```js
- import UIAbility from '@ohos.app.ability.UIAbility';
-
-
-
- export default class EntryAbility extends UIAbility {
-
- onForeground() {
-
- // 申请系统需要的资源,或者重新申请在onBackground中释放的资源
-
- }
-
-
-
- onBackground() {
-
- // 释放UI界面不可见时无用的资源,或者在此回调中执行较为耗时的操作
-
- // 例如状态保存等
-
- }
-
- }
-
- ```
-
- `Destroy`状态在`UIAbility`实例销毁时触发。可以在`onDestroy()`回调中进行系统资源的释放、数据的保存等操作。
-
- ```js
-
- import UIAbility from '@ohos.app.ability.UIAbility';
-
- import Window from '@ohos.window';
-
-
-
- export default class EntryAbility extends UIAbility {
-
- onDestroy() {
-
- // 系统资源的释放、数据的保存等
-
- }
-
- }
```
> 有时我们需要让`UIAbility`组件与UI界面之间进行通信,例如:通知UI界面应用的前后台切换、多`module`下的UI界面传值、传递启动参数等。
基于HarmonyOS的应用模型,可以通过以下两种方式来实现:
- `EventHub`:基于发布订阅模式来实现,事件需要先订阅后发布,订阅者收到消息后进行处理。
- `globalThis`:`ArkTS`引擎实例内部的一个全局对象,在`ArkTS`引擎实例内部都能访问。
- 使用`AppStorage`/`LocalStorage`进行数据同步:`ArkUI`提供了`AppStorage`和`LocalStorage`两种应用级别的状态管理方案,可用于实现应用级别和`UIAbility`级别的数据同步。
主要使用上下文对象中的`eventHub`模块,提供了事件中心,提供订阅、取消订阅、触发事件的能力。
```js
- //UIAbility组件中访问上下文
- export default class EntryAbility extends UIAbility {
- onCreate() {
- // 创建之后 可通过this.context访问上下文对象
- }
- }
- // UI页面访问上下文对象
- import common from '@ohos.app.ability.common';
- @Entry
- @Component
- struct Index {
- private context = getContext(this) as common.UIAbilityContext;
- }
```
```js
- //UIAbility组件---------------------------
- export default class EntryAbility extends UIAbility {
- onCreate(){
- this.context.eventHub.on("UIEmit",(data)=>{
- //通知其他Ability
- })
- }
- onForeground() {
- // 触发自定义事件 第一个参数:事件名 后续参数作为监听回调的参数
- // 切至前台 通知页面启动计时器
- this.context.eventHub.emit("EventName","start")
- }
- onBackground() {
- // 切至后台 通知页面停止计时器
- this.context.eventHub.emit("EventName","stop")
- }
- }
- // UI界面--------------------------------
- import common from '@ohos.app.ability.common';
- @Entry
- @Component
- struct Index {
- private context = getContext(this) as common.UIAbilityContext;
- @State num:number=0;
- private timer;
- aboutToAppear(){
- this.start();
- //监听前后台切换事件
- this.context.eventHub.on("EventName",(data)=>{
- this[data]()
- })
- }
- start(){
- this.timer=setInterval(()=>{
- this.num++;
- },1000)
- }
- stop(){
- clearInterval(this.timer);
- }
- build() {
- Column(){
- Text(this.num.toString())
- .width("100%")
- .height("100%")
- .fontSize(30)
- .textAlign(TextAlign.Center)
- Button(){
- Text("页面触发事件")
- }
- .onClick(()=>{
- // 向UIAbility发射信号
- this.context.eventHub.emit("UIEmit","params");
- })
- }
- }
- }
```
`globalThis`是`ArkTS`引擎实例内部的一个全局对象,引擎内部的`UIAbility/ExtensionAbility/Page`都可以使用,因此可以使用`globalThis`对象进行数据同步。
```js
- //UIAbility组件---------------------------
- export default class EntryAbility extends UIAbility {
- onCreate(want, launch) {
- globalThis.title="柏木白";
- }
- }
- // UI界面--------------------------------
- @Entry
- @Component
- struct Index {
- aboutToAppear() {
- console.log(globalThis)
- }
- }
```
<p style="color:red">globalThis注意事项</p>
- `Stage`模型下进程内的`UIAbility`组件共享`ArkTS`引擎实例,使用`globalThis`时需要避免存放相同名称的对象。例如`AbilityA`和`AbilityB`可以使用`globalThis`共享数据,在存放相同名称的对象时,先存放的对象会被后存放的对象覆盖。
- `FA`模型因为每个`UIAbility`组件之间引擎隔离,不会存在该问题。
- 对于绑定在`globalThis上`的对象,其生命周期与`ArkTS`虚拟机实例相同,建议在使用完成之后将其赋值为`null`,以减少对应用内存的占用。
`ArkUI`提供了`AppStorage`和`LocalStorage`两种应用级别的状态管理方案,可用于实现应用级别和UIAbility级别的数据同步。其中,`AppStorage`是一个全局的状态管理器,适用于多个`UIAbility`共享同一状态数据的情况;而`LocalStorage`则是一个局部的状态管理器,适用于单个`UIAbility`内部使用的状态数据。
UIAbility组件中创建LocalStorage实例:
```js
- export default class EntryAbility extends UIAbility {
- // 创建LocalStorage实例
- storage: LocalStorage = new LocalStorage({
- title:"柏木白"
- })
- onWindowStageCreate(windowStage: window.WindowStage) {
- // 注入页面
- windowStage.loadContent('pages/Index',this.storage)
- }
- }
```
在UI页面通过GetShared接口获取在通过loadContent共享的LocalStorage实例:
```js
- // 通过GetShared接口获取stage共享的LocalStorage实例
- let storage = LocalStorage.GetShared()
- @Entry(storage)
- @Component
- struct CompA {
- //组件内部可以用@LocalStorageLink/Prop接收
- @LocalStorageLink('title') title: string="";
- build() {
- Column() {
- Text(this.title).fontSize(50)
- }
- }
- }
```
<span style="color:red">---- 注意:存储在预览视图中无效 需要用模拟器或真机调试 -----</span>
`AppStorage`是应用级的全局状态共享,相当于整个应用的“中枢”,是在应用启动的时候会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。
随时随地设置:
```js
- export default class EntryAbility extends UIAbility {
- onCreate(){
- AppStorage.SetOrCreate("name","周杰伦")
- }
- }
```
在UI页面通过`@StorageLink`访问:
```js
- @Entry
- @Component
- struct Storage {
- @StorageLink('name') name: string = "";
- build() {
- Row() {
- Column() {
- Text(this.name)
- .fontSize(50)
- .fontWeight(FontWeight.Bold)
- }
- .width('100%')
- }
- .height('100%')
- }
- }
```
> `UIAbility`组件是系统调度的基本单元,为应用提供绘制界面的窗口;一个`UIAbility`组件中可以通过多个页面来实现一个功能模块。每一个`UIAbility`组件实例,都对应于一个最近任务列表中的任务。
对于开发者而言,可以根据具体场景选择单个还是多个`UIAbility`,划分建议如下:
* 如果希望在任务视图中看到一个任务,则建议使用一个`UIAbility`,多个页面的方式。
* 如果希望在任务视图中看到多个任务,或者需要同时开启多个窗口,则建议使用多个`UIAbility`开发不同的模块功能。
* `Entry module`是项目主模块,当应用比较大时,可以拆分`Feature module`,配置成按需下载安装,不同设备下也可以随意搭配组合。
得到一个和`entry`一样的目录结构:
`module.json5`文件中包含模块的基本信息:
```js
- import common from '@ohos.app.ability.common';
- @Entry
- @Component
- struct Index {
- // 获取上下文对象
- private context = getContext(this) as common.UIAbilityContext;
- build() {
- Navigation(){
- Flex({justifyContent:FlexAlign.Center,alignItems:ItemAlign.Center}){
- Button({type:ButtonType.Capsule}){
- Text("跳转").fontColor("white")
- }
- .padding(15)
- .width(150)
- .onClick(()=>{
- //跳转至指定Ability
- this.context.startAbility({
- deviceId:"",//设备id 留空表示当前设备
- bundleName:"com.example.myapplication",//包名 可以从AppScope/app.json5中拿到
- moduleName:"application",//模块名
- abilityName:"ApplicationAbility",
- parameters:{//携带的参数 可以借助参数指定目标Ability启动的页面
- val:"柏木白"
- }
- })
- })
- }
- .width("100%")
- .height("100%")
- }
- .title("入口模块首页")
- }
- }
```
跳转目标接收参数 在页面中显示:
```js
- //UIAbility组件 ------------------------------------------
- import UIAbility from '@ohos.app.ability.UIAbility';
- import window from '@ohos.window';
-
- export default class ApplicationAbility extends UIAbility {
- onCreate(want, launchParam) {
- // 接收参数
- globalThis.title=want.parameters.title;
- }
- onWindowStageCreate(windowStage: window.WindowStage) {
- windowStage.loadContent('pages/Index');
- }
- }
- //UI界面-------------------------------------------------
- @Entry
- @Component
- struct Index {
- build() {
- Row() {
- Column() {
- Text("接收到的数据:"+globalThis.title)
- .fontSize(20)
- .fontWeight(FontWeight.Bold)
- }
- .width('100%')
- }
- .height('100%')
- }
- }
```
编辑部署配置:
选择部署多个hap包:
运行效果:
目标Ability中的页面,调用terminateSelfWithResult()方法,入参为需要返回给EntryAbility的信息:
```js
- import common from '@ohos.app.ability.common';
- @Entry
- @Component
- struct Index {
- // 获取上下文对象
- private context = getContext(this) as common.UIAbilityContext;
- build() {
- Row() {
- Column() {
- Text("接收到的数据:"+globalThis.title)
- .fontSize(20)
- .fontWeight(FontWeight.Bold)
- Button({type:ButtonType.Capsule}){
- Text("返回").fontColor("white")
- }
- .padding(15)
- .margin(10)
- .width(150)
- .onClick(()=>{
- let abilityResult = {
- resultCode: 200,
- want: {
- parameters: {
- title:"鸿蒙生态"
- },
- },
- }
- //停止自身 并携带数据返回
- this.context.terminateSelfWithResult(abilityResult);
- })
- }
- .width('100%')
- }
- .height('100%')
- }
- }
```
调用方跳转方法改为`startAbilityForResult`,通过回调访问结果:
```js
- //跳转至指定Ability并要接收结果
- this.context.startAbilityForResult({
- deviceId:"",//设备id 留空表示当前设备
- bundleName:"com.example.myapplication",//包名 可以从AppScope/app.json5中拿到
- moduleName:"application",//模块名
- abilityName:"ApplicationAbility",
- parameters:{
- title:"柏木白"
- }
- })
- .then((data:any) => {
- //接收目标销毁时返回的数据
- console.log(data.want.parameters.title,"-----------------");
- })
```
目标`UIAbility`首次启动时,在目标`UIAbility`的`onWindowStageCreate()`生命周期回调中,解析`EntryAbility`传递过来的want参数,获取到需要加载的页面信息`url`,传入`windowStage.loadContent()`方法。
```js
- onWindowStageCreate(windowStage: Window.WindowStage) {
- let url =this.context.want.parameters.url||'pages/Index';
- windowStage.loadContent(url);
- }
```
目标`UIAbility`非首次启动,在目标`UIAbility`中,默认加载的是`Index`页面。由于当前`UIAbility`实例之前已经创建完成,此时会进入`UIAbility`的`onNewWant()`回调中且不会进入`onCreate()`和`onWindowStageCreate()`生命周期回调,在`onNewWant()`回调中解析调用方传递过来的`want`参数,并挂在到全局变量`globalThis`中,以便于后续在页面中获取。
```js
- //增加onNewWant钩子
- onNewWant(want, launchParam) {
- // 接收调用方UIAbility传过来的参数
- globalThis.url = want.parameters.url;
- }
```
目标`UIAbility`首页中判断跳转:
```js
- import router from '@ohos.router';
- @Entry
- @Component
- struct Index {
- onPageShow() {
- if (globalThis.url) {
- router.replaceUrl({
- url: globalThis.url,
- })
- }
- }
- }
```
`UIAbility`的启动模式是指`UIAbility`实例在启动时的不同呈现状态。针对不同的业务场景,系统提供了三种启动模式:
- singleton(单实例模式)
- multiton(多实例模式)
- specified(指定实例模式)
`singleton`启动模式为单实例模式,也是默认情况下的启动模式。每次调用`startAbility()`方法时,如果应用进程中该类型的`UIAbility`实例已经存在,则复用系统中的`UIAbility`实例。系统中只存在唯一一个该`UIAbility`实例,即在最近任务列表中只存在一个该类型的`UIAbility`实例。
> 注意:应用的`UIAbility`实例已创建,该`UIAbility`配置为单实例模式,再次调用`startAbility()`方法启动该`UIAbility`实例。由于启动的还是原来的`UIAbility`实例,并未重新创建一个新
> `UIAbility`实例,此时只会进入该`UIAbility`的`onNewWant()`回调,不会进入其`onCreate()`和`onWindowStageCreate()`生命周期回调。
如果需要使用`singleton`启动模式,在module.json5配置文件中的`launchType`字段配置为`singleton`即可:
```js
- {
- "module": {
- ...
- "abilities": [
- {
- "launchType": "singleton",
- ...
- }
- ]
- }
- }
```
`multiton`启动模式为多实例模式,每次调用`startAbility()`方法时,都会在应用进程中创建一个新的该类型`UIAbility`实例。即在最近任务列表中可以看到有多个该类型的`UIAbility`实例。这种情况下可以将`UIAbility`配置为`multiton`(多实例模式)。
`multiton`启动模式的开发使用,在`module.json5`配置文件中的`launchType`字段配置为`multiton`即可。
```js
- {
- "module": {
- ...
- "abilities": [
- {
- "launchType": "multiton",
- ...
- }
- ]
- }
- }
```
`specified`启动模式为指定实例模式,针对一些特殊场景使用(例如文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例)。
`specified`启动模式的开发使用,在`module.json5`配置文件中的`launchType`字段配置为`specified`即可。
```js
- {
- "module": {
- ...
- "abilities": [
- {
- "launchType": "specified",
- ...
- }
- ]
- }
- }
```
在`EntryAbility`中,调用`startAbility()`方法时,在`want`参数中,增加一个自定义参数来区别`UIAbility`实例,例如增加一个"instanceKey"自定义参数。
```js
- // 在启动指定实例模式的UIAbility时,给每一个UIAbility实例配置一个独立的Key标识
- // 例如在文档使用场景中,可以用文档路径作为Key标识
- function getInstance() {
- // return id
- }
- let want = {
- deviceId: '', // deviceId为空表示本设备
- bundleName: 'com.example.myapplication',
- abilityName: 'FuncAbility',
- moduleName: 'module1', // moduleName非必选
- parameters: { // 自定义信息
- instanceKey: getInstance(),
- },
- }
- // context为调用方UIAbility的AbilityContext
- this.context.startAbility(want).then(() => {
- // ...
- }).catch((err) => {
- // ...
- })
```
目标`UIAbility`:
```js
- import AbilityStage from '@ohos.app.ability.AbilityStage';
-
- export default class MyAbilityStage extends AbilityStage {
- onAcceptWant(want): string {
- // 在被调用方的AbilityStage中,针对启动模式为specified的UIAbility返回一个UIAbility实例对应的一个Key值
- return want.parameters.instanceKey
- }
- }
```
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。