鸿蒙开发——Stage模型之Ability组件

305 阅读6分钟

一、基本概念

image.png

多个应用组件共享同一个ArkTS引擎(运行ArkTS语言的虚拟机)实例,应用组件之间可以方便的共享对象和状态,同时减少复杂应用运行对内存的占用。

  • AbilityStage:每个Entry类型或者Feature类型的HAP在运行期都有一个AbilityStage类实例,当HAP中的代码首次被加载到进程中的时候,系统会先创建AbilityStage实例。

  • UIAbility组件和ExtensionAbility组件:UIAbility组件是一种包含UI的应用组件,主要用于和用户交互。ExtensionAbility组件是一种面向特定场景的应用组件,开发者直接使用ExtensionAbility组件的派生类。

  • WindowStage:每个UIAbility实例都会与一个WindowStage类实例绑定,该类起到了应用进程内窗口管理器的作用。也就是说UIAbility通过WindowStage持有了一个主窗口,该主窗口为ArkUI提供了绘制区域。

  • Context:在Stage模型上,Context及其派生类向开发者提供在运行期可以调用的各种资源和能力。UIAbility组件和各种ExtensionAbility派生类都有各自不同的Context类。

二、UIAbility组件

1、基本概念

  • UIAbility组件是一种包含UI的应用组件,主要用于和用户交互。是系统调度的基本单元,为应用提供绘制界面的窗口。一个应用可以包含一个或多个UIAbility组件。
  • 每一个UIAbility组件实例都会在最近任务列表中显示一个对应的任务
  • UIAbility的生命周期包含创建/销毁/前台/后台等状态,与显示相关的状态通过WindowStage的事件暴露给开发者。

选择单个还是多个UIAbility:
如果希望在任务视图中看到一个任务,则建议使用一个UIAbility,多个页面的方式。

2、生命周期

image.png

  • onCreate:UIAbility实例创建,可以在onCreate回调中进行相关初始化操作。
  • onForeground:在UIAbility的UI可见之前,如UIAbility切换至前台时触发。
  • onBackground:在UIAbility的UI完全不可见之后,如UIAbility切换至后台时候触发。可以在该回调中释放UI不可见时无用的资源,或者在此回调中执行较为耗时的操作,例如状态保存等。
  • onDestroy:在UIAbility销毁时触发。可以在onDestroy回调中进行系统资源的释放、数据的保存等操作。
export default class EntryAbility extends UIAbility {

    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {

    }

    onWindowStageCreate(windowStage: window.WindowStage): void {

    }

    onForeground(): void {

    }

    onBackground(): void {

    }

    onWindowStageDestroy(): void {

    }

    onDestroy(): void {

    }

}

onNewWant

  • 当应用的UIAbility实例已创建,且UIAbility配置为singleton启动模式时(默认启动模式),再次调用startAbility()方法启动该UIAbility实例时,只会进入该UIAbility的onNewWant()回调。

  • 比如通过deeplink或appLink的方式再次启动应用,也会进入onNewWant()回调。

3、启动模式

  • singleton启动模式为单实例模式,也是默认情况下的启动模式。每次调用startAbility()方法时,如果应用进程中该类型的UIAbility实例已经存在,则复用系统中的UIAbility实例,只会进入该UIAbility的onNewWant()回调。最近任务列表中只存在一个该类型的UIAbility实例。

  • multiton启动模式为多实例模式,每次调用startAbility()方法时,都会在应用进程中创建一个新的该类型UIAbility实例。

  • specified启动模式为指定实例模式,针对一些特殊场景使用通过key匹配对应的UIAbility,如匹配成功则启动该UIAbility实例,如果实现则创建新的UIAbility实例。

实例模式的使用:

  • 调用startAbility()方法时,可以在want参数中增加一个自定义参数,例如instanceKey,以此来区分不同的UIAbility实例。

  • 在Ability启动之前,会先进入对应的AbilityStage的onAcceptWant()生命周期回调中,以获取该UIAbility实例的Key值。然后系统会自动匹配,如果存在与该UIAbility实例匹配的Key,则会启动与之绑定的UIAbility实例,否则会创建一个新的UIAbility实例。

4、UIAbility使用

4.1 启动UIAbility

@Entry
@Component
struct Index {
  private context = getContext(this) as common.UIAbilityContext;

  startAbilityTest() {
    let want: Want = {
      deviceId: '', // deviceId为空表示本设备
      bundleName: 'com.example.myapplication',
      moduleName: 'func', // moduleName非必选
      abilityName: 'FuncAbility',
      parameters: { // 自定义信息
        info: '来自EntryAbility Index页面',
      },
    }
    this.context.startAbility(want);
  }

}

启动UIAbility有显式Want启动和隐式Want启动两种方式。

  • 显式Want启动:在want参数中需要设置该应用bundleName和abilityName

  • 隐式Want启动:根据匹配条件由用户选择启动哪一个UIAbility,其入参want中指定了一系列的entities和actions字段

4.2 参数接收

在onCreate()或者onNewWant()回调中接收前一个UIAbility传递过来的参数

export default class FuncAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    // 接收调用方UIAbility传过来的参数
    let funcAbilityWant = want;
    let info = funcAbilityWant?.parameters?.info;
    // ...
  }
}

4.3 启动UIAbility并获取返回结果

// 启动并接收返回的参数
let want :Want = {

}
this.context.startAbilityForResult(want).then((data) => {
  // ...
}).catch((err: BusinessError) => {
})
let abilityResult : common.AbilityResult = {
  resultCode: 1,
  want : {

  }
}

//停止自身并返回所需参数
this.context.terminateSelfWithResult(abilityResult, (err) => {
  if (err.code) {
    console.error(`Failed to terminate self with result. Code is ${err.code}, message is ${err.message}`);
    return;
  }
})

4.4 停止当前UIAbility

this.context.terminateSelf((error) => {

})

4.5 关闭所有UIAbility

this.context.getApplicationContext().killAllProcesses()

5、UIAbility和UI组件通信

  • 使用EventHub进行数据通信,通过发布订阅方式来实现事件的传递。

  • 使用AppStorage/LocalStorage进行数据同步,通过这两种应用级别的状态管理方案通信。

5.1 EventHub事件发送

@Entry
@Component
struct Index {
  private context = getContext(this) as common.UIAbilityContext;

  // 页面展示
  build() {
    Button('按钮')
      .onClick(() => {
        // 不带参数触发自定义“event1”事件
        this.context.eventHub.emit('event1');
        // 带多个参数触发自定义“event1”事件
        this.context.eventHub.emit('event1', 2, 'test');
      })
    Button('关闭')
      .onClick(() => {
        //取消该事件的订阅
        this.context.eventHub.off('event1');
      })
  }
}

5.2 EventHub事件接收

export default class EntryAbility extends UIAbility {

  eventFunc() {
    console.log('EntryAbility', "eventFunc:");
  }

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    let eventHub = this.context.eventHub;
      // 执行订阅操作
    eventHub.on('event1', this.eventFunc)
    eventHub.on('event1', (data: String, data1: number) => {
    //接收事件
      console.log('EntryAbility', "data:" + data + "====" + data1);
    })
  }
}

三、ExtensionAbility组件

  • ExtensionAbility组件是基于特定场景(例如服务卡片、输入法等)提供的应用组件,只能使用系统已定义的类型。

  • 所有类型的ExtensionAbility组件均不能被应用直接启动,而是由相应的系统管理服务拉起,以确保其生命周期受系统管控,使用时拉起,使用完销毁。

1、常用ExtensionAbility

  • FormExtensionAbility: FORM类型的ExtensionAbility组件,用于提供服务卡片的相关能力。

  • WorkSchedulerExtensionAbility:WORK_SCHEDULER类型的ExtensionAbility组件,用于提供延迟任务的相关能力。

  • InputMethodExtensionAbility:INPUT_METHOD类型的ExtensionAbility组件,用于实现输入法应用的开发。

  • BackupExtensionAbility:BACKUP类型的ExtensionAbility组件,用于提供备份及恢复应用数据的能力

  • DriverExtensionAbility:DRIVER类型的ExtensionAbility组件,用于提供驱动相关扩展框架

  • EmbeddedUIExtensionAbility:EMBEDDED_UI类型的ExtensionAbility组件,用于提供跨进程界面嵌入的能力。

  • ShareExtensionAbility:SHARE类型的ExtensionAbility组件,用于提供分享模板服务扩展的能力。