Ability Kit-程序框架服务(类似Android Activity)

文章目录

  • Ability Kit(程序框架服务)
  • 简介
  • Stage模型开发概述
  • Stage模型应用组件
    • 应用/组件级配置
    • UIAbility组件
      • 概述
        • 概述
        • 声明配置
      • 生命周期
        • 概述
        • 生命周期状态说明
          • Create状态
          • WindowStageCreate**和**WindowStageDestroy状态
          • WindowStageWillDestroy状态
          • Foreground**和**Background状态
          • Destroy状态
      • 启动模式
      • 基本用法
        • 指定UIAbility的启动页面
        • 获取UIAbility的上下文信息
      • 与UI的数据同步
        • 使用EventHub进行数据通信
        • 使用AppStorage/LocalStorage进行数据同步
      • 启动应用内的UIAbility组件
          • 概述
          • 调用放UIAbility指定启动页面
          • 目标UIAbility冷启动
          • 目标UIAbility热启动
    • ExtensionAbility组件
    • AbilityStage组件容器
    • 应用上下文Context
      • 概述
        • 各类Context的继承关系
        • 各类Context的持有关系
        • 各类Context的获取方式
          • 获取UIAbilityContext。
          • 获取特定场景ExtensionContext。
          • 获取AbilityStageContext(Module级别的Context)
          • 获取ApplicationContext(应用级别的Context)
      • Context的典型使用场景
        • 获取应用文件路径
        • 获取和修改加密分区
        • 获取本应用中其他Module的Context
        • 订阅进程内UIAbility生命周期变化
    • 信息传递载体Want
      • Want概述
        • Want的定义与用途
        • Want的类型
      • 显式Want与隐式Want匹配规则
        • 显式Want匹配原理
        • 隐式Want匹配原理
      • 使用显式Want启动应用组件
      • 常见Action与Entities(不推荐使用)
    • 组件启动规则(Stage模型)
    • 应用启动框架AppStartup
    • 订阅系统环境变量的变化
  • 应用间跳转
  • 进程模型
  • 线程模型
  • Stage模型应用配置文件

Ability Kit(程序框架服务)

参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/stage-model-development-V13

简介

Ability Kit(程序框架服务)提供了应用程序开发和运行的应用模型,是系统为开发者提供的应用程序所需能力的抽象提炼,它提供了应用程序必备的组件和运行机制。有了应用模型,开发者可以基于一套统一的模型进行应用开发,使应用开发更简单、高效。

Stage模型开发概述

在这里插入图片描述

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

Stage模型应用组件

应用/组件级配置

1)应用包名配置
应用需要在工程的AppScope目录下的app.json5配置文件中配置bundleName标签,该标签用于标识应用的唯一性。推荐采用反域名形式命名(如com.example.demo,建议第一级为域名后缀com,第二级为厂商/个人名,第三级为应用名,也可以多级)。
在这里插入图片描述
2)图标和标签配置
图标和标签通常一起配置,对应app.json5配置文件和module.json5配置文件中的icon和label标签。DevEco Studio从5.0.3.800版本开始,不再对module.json5中的icon和label做强制校验,因此module.json5与app.json5只需要选择其一配置。

  • 生成机制

    1. HAP中包含UIAbility

      如果在module.json5配置文件的abilities标签中配置了icon和label,且该对应的ability中skills标签下面的entities中包含"entity.system.home"、actions中包含"ohos.want.action.home"或者"action.system.home",则系统将优先返回module.json5中的icon与label。如果存在多个满足条件的ability,优先返回module.json5中mainElement对应的ability配置的icon和label。

      如果在module.json5配置文件的abilities标签中未设置icon和label,或者对应的skills标签下面的entities与actions没有做相关配置(entities中包含"entity.system.home"、actions中包含"ohos.want.action.home"),那么系统将使用app.json5中的icon和label。

    2. HAP中不包含UIAbility,系统将返回app.json5中的icon和label

  • 应用场景

    1. 用于在应用界面内展示当前应用。例如:在设置应用中展示应用列表,在设置的隐私管理中展示应用申请的权限。

    2. 用于在设备桌面上展示当前应用。例如:桌面或者最近任务列表中显示应用。

    3. 用于在通知栏中展示发出通知消息的应用。

  • 配置示例
    方式一:配置app.json5(推荐)

    {
      "app": {
        "icon": "$media:app_icon",
        "label": "$string:app_name"
        // ...
      }
    }
    

    方式二:配置module.json5
    如果需要在桌面显示UIAbility图标,除了需要配置icon与label字段,还需要在skills标签下面的entities中添加"entity.system.home"、actions中添加"ohos.want.action.home"。

    {
      "module": {
        // ...
        "abilities": [
          {
            "icon": "$media:icon",
            "label": "$string:EntryAbility_label",
            "skills": [
              {
                "entities": [
                  "entity.system.home"
                ],
                "actions": [
                  "ohos.want.action.home"
                ]
              }
            ],
          }
        ]
      }
    }
    
  • 管控规则
    系统对无图标应用实施严格管控,防止一些恶意应用故意配置无桌面应用图标,导致用户找不到软件所在的位置,无法操作卸载应用,在一定程度上保证用户终端设备的安全。

    如果预置应用确需隐藏桌面应用图标,需要配置AllowAppDesktopIconHide应用特权。申请该特权后,应用不会在桌面上显示。除预置应用外,其他应用不支持隐藏桌面图标。

UIAbility组件

概述

概述

UIAbility组件是一种包含UI的应用组件,主要用于和用户交互。
UIAbility的设计理念:

  1. 原生支持应用组件级的跨端迁移和多端协同。
  2. 支持多设备和多窗口形态。

UIAbility划分原则与建议:
UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口。一个应用可以包含一个或多个UIAbility组件。例如,在支付应用中,可以将入口功能和收付款功能分别配置为独立的UIAbility。

对于开发者而言,可以根据具体场景选择单个还是多个UIAbility,划分建议如下:

  • 如果开发者希望在任务视图中看到一个任务,建议使用“一个UIAbility+多个页面”的方式,可以避免不必要的资源加载。

  • 如果开发者希望在任务视图中看到多个任务,或者需要同时开启多个窗口,建议使用多个UIAbility实现不同的功能。

    例如,即时通讯类应用中的消息列表与音视频通话采用不同的UIAbility进行开发,既可以方便地切换任务窗口,又可以实现应用的两个任务窗口在一个屏幕上分屏显示。

声明配置

为使应用能够正常使用UIAbility,需要在module.json5配置文件的abilities标签中声明UIAbility的名称、入口、标签等相关信息。

{
  "module": {
    // ...
    "abilities": [
      {
        "name": "EntryAbility", // UIAbility组件的名称
        "srcEntry": "./ets/entryability/EntryAbility.ets", // 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类提供了一系列回调,通过这些回调可以知道当前UIAbility实例的某个状态发生改变,会经过UIAbility实例的创建和销毁,或者UIAbility实例发生了前后台的状态切换。

UIAbility的生命周期包括CreateForegroundBackgroundDestroy四个状态,如下图所示。
在这里插入图片描述

生命周期状态说明
Create状态

Create状态为在应用加载过程中,UIAbility实例创建完成时触发,系统会调用onCreate()回调。可以在该回调中进行页面初始化操作,例如变量定义资源加载等,用于后续的UI展示。

	import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
	
	export default class EntryAbility extends UIAbility {
	  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
	    // 页面初始化
	  }
	  // ...
	}

说明
Want是对象间信息传递的载体,可以用于应用组件间的信息传递。Want的详细介绍请参见信息传递载体Want。

WindowStageCreateWindowStageDestroy状态

UIAbility实例创建完成之后,在进入Foreground之前,系统会创建一个WindowStage。WindowStage创建完成后会进入onWindowStageCreate()回调,可以在该回调中设置UI加载、设置WindowStage的事件订阅

在这里插入图片描述
onWindowStageCreate() 回调中通过**loadContent()**方法设置应用要加载的页面,并根据需要调用on(‘windowStageEvent’)方法订阅WindowStage的事件(获焦/失焦、切到前台/切到后台、前台可交互/前台不可交互)。

import { UIAbility } from '@kit.AbilityKit';
	import { window } from '@kit.ArkUI';
	import { hilog } from '@kit.PerformanceAnalysisKit';
	
	const TAG: string = '[EntryAbility]';
	const DOMAIN_NUMBER: number = 0xFF00;
	
	export default class EntryAbility extends UIAbility {
	  // ...
	  onWindowStageCreate(windowStage: window.WindowStage): void {
	    // 设置WindowStage的事件订阅(获焦/失焦、切到前台/切到后台、前台可交互/前台不可交互)
	    try {
	      windowStage.on('windowStageEvent', (data) => {
	        let stageEventType: window.WindowStageEventType = data;
	        switch (stageEventType) {
	          case window.WindowStageEventType.SHOWN: // 切到前台
	            hilog.info(DOMAIN_NUMBER, TAG, `windowStage foreground.`);
	            break;
	          case window.WindowStageEventType.ACTIVE: // 获焦状态
	            hilog.info(DOMAIN_NUMBER, TAG, `windowStage active.`);
	            break;
	          case window.WindowStageEventType.INACTIVE: // 失焦状态
	            hilog.info(DOMAIN_NUMBER, TAG, `windowStage inactive.`);
	            break;
	          case window.WindowStageEventType.HIDDEN: // 切到后台
	            hilog.info(DOMAIN_NUMBER, TAG, `windowStage background.`);
	            break;
	          case window.WindowStageEventType.RESUMED: // 前台可交互状态
	            hilog.info(DOMAIN_NUMBER, TAG, `windowStage resumed.`);
	            break;
	          case window.WindowStageEventType.PAUSED: // 前台不可交互状态
	            hilog.info(DOMAIN_NUMBER, TAG, `windowStage paused.`);
	            break;
	          default:
	            break;
	        }
	      });
	    } catch (exception) {
	      hilog.error(DOMAIN_NUMBER, TAG,
	        `Failed to enable the listener for window stage event changes. Cause: ${JSON.stringify(exception)}`);
	    }
	    hilog.info(DOMAIN_NUMBER, TAG, `%{public}s`, `Ability onWindowStageCreate`);
	    // 设置UI加载
	    windowStage.loadContent('pages/Index', (err, data) => {
	      // ...
	    });
	  }
	}

对应于onWindowStageCreate()回调。在UIAbility实例销毁之前,则会先进入onWindowStageDestroy() 回调,可以在该回调中释放UI资源。

import { UIAbility } from '@kit.AbilityKit';
	import { window } from '@kit.ArkUI';
	
	export default class EntryAbility extends UIAbility {
	  windowStage: window.WindowStage | undefined = undefined;
	
	  // ...
	  onWindowStageCreate(windowStage: window.WindowStage): void {
	    this.windowStage = windowStage;
	    // ...
	  }
	
	  onWindowStageDestroy() {
	    // 释放UI资源
	  }
	}
WindowStageWillDestroy状态

对应onWindowStageWillDestroy()回调,在WindowStage销毁前执行,此时WindowStage可以使用。

	import { UIAbility } from '@kit.AbilityKit';
	import { window } from '@kit.ArkUI';
	import { BusinessError } from '@kit.BasicServicesKit';
	import { hilog } from '@kit.PerformanceAnalysisKit';
	
	const TAG: string = '[EntryAbility]';
	const DOMAIN_NUMBER: number = 0xFF00;
	
	export default class EntryAbility extends UIAbility {
	  windowStage: window.WindowStage | undefined = undefined;
	  // ...
	  onWindowStageCreate(windowStage: window.WindowStage): void {
	    this.windowStage = windowStage;
	    // ...
	  }
	
	  onWindowStageWillDestroy(windowStage: window.WindowStage) {
	    // 释放通过windowStage对象获取的资源
	    // 在onWindowStageWillDestroy()中注销WindowStage事件订阅(获焦/失焦、切到前台/切到后台、前台可交互/前台不可交互)
	    try {
	      if (this.windowStage) {
	        this.windowStage.off('windowStageEvent');
	      }
	    } catch (err) {
	      let code = (err as BusinessError).code;
	      let message = (err as BusinessError).message;
	      hilog.error(DOMAIN_NUMBER, TAG, `Failed to disable the listener for windowStageEvent. Code is ${code}, message is ${message}`);
	    }
	  }
	
	  onWindowStageDestroy() {
	    // 释放UI资源
	  }
	}
ForegroundBackground状态

Foreground和Background状态分别在UIAbility实例切换至前台和切换至后台时触发,对应于onForeground()回调和onBackground()回调。

onForeground()回调,在UIAbility的UI可见之前,如UIAbility切换至前台时触发。可以在onForeground()回调中申请系统需要的资源,或者重新申请在onBackground()中释放的资源。
onBackground()回调,在UIAbility的UI完全不可见之后,如UIAbility切换至后台时候触发。可以在onBackground()回调中释放UI不可见时无用的资源,或者在此回调中执行较为耗时的操作,例如状态保存等。

	import { UIAbility } from '@kit.AbilityKit';
	
	export default class EntryAbility extends UIAbility {
	  // ...
	
	  onForeground(): void {
	    // 申请系统需要的资源,或者重新申请在onBackground()中释放的资源
	  }
	
	  onBackground(): void {
	    // 释放UI不可见时无用的资源,或者在此回调中执行较为耗时的操作
	    // 例如状态保存等
	  }
	}

当应用的UIAbility实例已创建,且UIAbility配置为singleton启动模式时,再次调用startAbility()方法启动该UIAbility实例时,只会进入该UIAbility的**onNewWant()**回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。应用可以在该回调中更新要加载的资源和数据等,用于后续的UI展示。

	import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
	
	export default class EntryAbility extends UIAbility {
	  // ...
	
	  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
	    // 更新资源、数据
	  }
	}
Destroy状态

Destroy状态在UIAbility实例销毁时触发。可以在onDestroy()回调中进行系统资源的释放、数据的保存等操作。
例如,调用terminateSelf()方法停止当前UIAbility实例,执行onDestroy()回调,并完成UIAbility实例的销毁。

	import { UIAbility } from '@kit.AbilityKit';
	
	export default class EntryAbility extends UIAbility {
	  // ...
	
	  onDestroy() {
	    // 系统资源的释放、数据的保存等
	  }
	}

启动模式

UIAbility的启动模式是指UIAbility实例在启动时的不同呈现状态。针对不同的业务场景,系统提供了三种启动模式:

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

在这里插入图片描述

说明
应用的UIAbility实例已创建,该UIAbility配置为单实例模式,再次调用startAbility()方法启动该UIAbility实例。由于启动的还是原来的UIAbility实例,并未重新创建一个新的UIAbility实例,此时只会进入该UIAbility的onNewWant() 回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。

如果需要使用singleton启动模式,在module.json5配置文件中的launchType字段配置为singleton即可。

{
  "module": {
    // ...
    "abilities": [
      {
        "launchType": "singleton",
        // ...
      }
    ]
  }
}
multiton启动模式
multiton启动模式为多实例模式,每次调用startAbility()方法时,都会在应用进程中创建一个新的该类型UIAbility实例。即在最近任务列表中可以看到有多个该类型的UIAbility实例。这种情况下可以将UIAbility配置为multiton(多实例模式)。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0ee01e4c9e994dbbaa1f61ebaa28636a.gif) multiton启动模式的开发使用,在module.json5配置文件中的launchType字段配置为multiton即可。
{
  "module": {
    // ...
    "abilities": [
      {
        "launchType": "multiton",
        // ...
      }
    ]
  }
}
specified启动模式
specified启动模式为指定实例模式,针对一些特殊场景使用(例如文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例)。

在这里插入图片描述
假设应用有两个UIAbility实例,即EntryAbility和SpecifiedAbility。EntryAbility以specified模式启动SpecifiedAbility。基本原理如下:

  1. EntryAbility调用startAbility()方法,并在Want的parameters字段中设置唯一的Key值,用于标识SpecifiedAbility。
  2. 系统在拉起SpecifiedAbility之前,会先进入对应的AbilityStage的onAcceptWant()生命周期回调,获取用于标识目标UIAbility的Key值。
  3. 系统会根据获取的Key值来匹配UIAbility。
    • 如果匹配到对应的UIAbility,则会启动该UIAbility实例,并进入onNewWant()生命周期回调。
    • 如果无法匹配对应的UIAbility,则会创建一个新的UIAbility实例,并进入该UIAbility实例的onCreate()生命周期回调和onWindowStageCreate()生命周期回调。

在这里插入图片描述

  1. 在SpecifiedAbility中,需要将module.json5配置文件的launchType字段配置为specified。

    {
      "module": {
        // ...
        "abilities": [
          {
            "launchType": "specified",
            // ...
          }
        ]
      }
    }
    
  2. 在EntryAbility中,调用startAbility()方法时,可以在want参数中传入了自定义参数instanceKey作为唯一标识符,以此来区分不同的UIAbility实例。示例中instanceKey的value值设置为字符串’KEY’。

     // 在启动指定实例模式的UIAbility时,给每一个UIAbility实例配置一个独立的Key标识
     // 例如在文档使用场景中,可以用文档路径作为Key标识
     import { common, Want } from '@kit.AbilityKit';
     import { hilog } from '@kit.PerformanceAnalysisKit';
     import { BusinessError } from '@kit.BasicServicesKit';
    
     const TAG: string = '[Page_StartModel]';
     const DOMAIN_NUMBER: number = 0xFF00;
    
     function getInstance(): string {
       return 'KEY';
     }
    
     @Entry
     @Component
     struct Page_StartModel {
       private KEY_NEW = 'KEY';
    
       build() {
         Row() {
           Column() {
             // ...
             Button()
               .onClick(() => {
                 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
                 // context为调用方UIAbility的UIAbilityContext;
                 let want: Want = {
                   deviceId: '', // deviceId为空表示本设备
                   bundleName: 'com.samples.stagemodelabilitydevelop',
                   abilityName: 'SpecifiedFirstAbility',
                   moduleName: 'entry', // moduleName非必选
                   parameters: {
                     // 自定义信息
                     instanceKey: this.KEY_NEW
                   }
                 };
                 context.startAbility(want).then(() => {
                   hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting SpecifiedAbility.');
                 }).catch((err: BusinessError) => {
                   hilog.error(DOMAIN_NUMBER, TAG, `Failed to start SpecifiedAbility. Code is ${err.code}, message is ${err.message}`);
                 })
                 this.KEY_NEW = this.KEY_NEW + 'a';
               })
             // ...
             Button()
               .onClick(() => {
                 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
                 // context为调用方UIAbility的UIAbilityContext;
                 let want: Want = {
                   deviceId: '', // deviceId为空表示本设备
                   bundleName: 'com.samples.stagemodelabilitydevelop',
                   abilityName: 'SpecifiedSecondAbility',
                   moduleName: 'entry', // moduleName非必选
                   parameters: {
                     // 自定义信息
                     instanceKey: getInstance()
                   }
                 };
                 context.startAbility(want).then(() => {
                   hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting SpecifiedAbility.');
                 }).catch((err: BusinessError) => {
                   hilog.error(DOMAIN_NUMBER, TAG, `Failed to start SpecifiedAbility. Code is ${err.code}, message is ${err.message}`);
                 })
                 this.KEY_NEW = this.KEY_NEW + 'a';
               })
             // ...
           }
           .width('100%')
         }
         .height('100%')
       }
     }
    
  3. 开发者根据业务在SpecifiedAbility的onAcceptWant()生命周期回调设置该UIAbility的标识。示例中标识设置为SpecifiedAbilityInstance_KEY。

     import { AbilityStage, Want } from '@kit.AbilityKit';
    
     export default class MyAbilityStage extends AbilityStage {
       onAcceptWant(want: Want): string {
         // 在被调用方的AbilityStage中,针对启动模式为specified的UIAbility返回一个UIAbility实例对应的一个Key值
         // 当前示例指的是module1 Module的SpecifiedAbility
         if (want.abilityName === 'SpecifiedFirstAbility' || want.abilityName === 'SpecifiedSecondAbility') {
           // 返回的字符串KEY标识为自定义拼接的字符串内容
           if (want.parameters) {
             return `SpecifiedAbilityInstance_${want.parameters.instanceKey}`;
           }
         }
         // ...
         return 'MyAbilityStage';
       }
     }
    

说明

  1. 当应用的UIAbility实例已经被创建,并且配置为指定实例模式时,如果再次调用startAbility()方法启动该UIAbility实例,且AbilityStage的onAcceptWant()回调匹配到一个已创建的UIAbility实例,则系统会启动原来的UIAbility实例,并且不会重新创建一个新的UIAbility实例。此时,该UIAbility实例的onNewWant()回调会被触发,而不会触发onCreate()和onWindowStageCreate()生命周期回调。
  2. DevEco Studio默认工程中未自动生成AbilityStage,AbilityStage文件的创建请参见AbilityStage组件容器。

基本用法

UIAbility组件的基本用法包括:指定UIAbility的启动页面以及获取UIAbility的上下文UIAbilityContext

指定UIAbility的启动页面

应用中的UIAbility在启动过程中,需要指定启动页面,否则应用启动后会因为没有默认加载页面而导致白屏。可以在UIAbility的**onWindowStageCreate()**生命周期回调中,通过WindowStage对象的loadContent()方法设置启动页面。

import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    windowStage.loadContent('pages/Index', (err, data) => {
      // ...
    });
  }
  // ...
}

说明
在DevEco Studio中创建的UIAbility中,该UIAbility实例默认会加载Index页面,根据需要将Index页面路径替换为需要的页面路径即可。

获取UIAbility的上下文信息

UIAbility类拥有自身的上下文信息,该信息为UIAbilityContext类的实例,UIAbilityContext类拥有abilityInfo、currentHapModuleInfo等属性。通过UIAbilityContext可以获取UIAbility的相关配置信息,如包代码路径、Bundle名称、Ability名称和应用程序需要的环境状态等属性信息,以及可以获取操作UIAbility实例的方法(如startAbility()、connectServiceExtensionAbility()、terminateSelf()等)。

如果需要在页面中获得当前Ability的Context,可调用getContext接口获取当前页面关联的UIAbilityContext或ExtensionContext。

  • 在UIAbility中可以通过this.context获取UIAbility实例的上下文信息。

    import {UIAbility,AbilityConstant,Want} from '@Kit.AbilityKit';
    
    export default class EntryAbility extends UIAbility{
    	onCreate(want: Want,launchParam: AbilityConstant.LaunchParam) : void {
    		//获取UIAbility实例的上下文
    		let context =  this.context;
    	}
    }
    
  • 在页面中获取UIAbility实例的上下文信息,包括导入依赖资源context模块和在组件中定义一个context变量两个部分。

    import { common, Want } from '@kit.AbilityKit';
    
    @Entry
    @Component
    struct Page_EventHub {
      private context = getContext(this) as common.UIAbilityContext;
    
      startAbilityTest(): void {
        let want: Want = {
          // Want参数信息
        };
        this.context.startAbility(want);
      }
    
      // 页面展示
      build() {
        // ...
      }
    }
    

    也可以在导入依赖资源context模块后,在具体使用UIAbilityContext前进行变量定义。

    import { common, Want } from '@kit.AbilityKit';
    
    @Entry
    @Component
    struct Page_UIAbilityComponentsBasicUsage {
      startAbilityTest(): void {
        let context = getContext(this) as common.UIAbilityContext;
        let want: Want = {
          // Want参数信息
        };
        context.startAbility(want);
      }
    
      // 页面展示
      build() {
        // ...
      }
    }
    
  • 当业务完成后,开发者如果想要终止当前UIAbility实例,可以在通过调用terminateSelf()方法实现。

    import { common } from '@kit.AbilityKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    @Entry
    @Component
    struct Page_UIAbilityComponentsBasicUsage {
      // 页面展示
      build() {
        Column() {
          //...
          Button('FuncAbilityB')
            .onClick(() => {
              let context = getContext(this) as common.UIAbilityContext;
              try {
                context.terminateSelf((err: BusinessError) => {
                  if (err.code) {
                    // 处理业务逻辑错误
                    console.error(`terminateSelf failed, code is ${err.code}, message is ${err.message}`);
                    return;
                  }
                  // 执行正常业务
                  console.info('terminateSelf succeed');
                });
              } catch (err) {
                // 捕获同步的参数错误
                let code = (err as BusinessError).code;
                let message = (err as BusinessError).message;
                console.error(`terminateSelf failed, code is ${code}, message is ${message}`);
              }
            })
        }
      }
    }
    

与UI的数据同步

基于当前的应用模型,可以通过以下几种方式来实现UIAbility组件与UI之间的数据同步。

  • 使用EventHub进行数据通信:在基类Context中提供了EventHub对象,可以通过发布订阅方式来实现事件的传递。在事件传递前,订阅者需要先进行订阅,当发布者发布事件时,订阅者将接收到事件并进行相应处理。
  • 使用AppStorage/LocalStorage进行数据同步:ArkUI提供了AppStorage和LocalStorage两种应用级别的状态管理方案,可用于实现应用级别和UIAbility级别的数据同步。
使用EventHub进行数据通信

EventHub为UIAbility组件提供了事件机制,使它们能够进行订阅、取消订阅和触发事件等数据通信能力。

在基类Context中,提供了EventHub对象,可用于在UIAbility组件实例内通信。使用EventHub实现UIAbility与UI之间的数据通信需要先获取EventHub对象,本章节将以此为例进行说明。

  • 在UIAbility中调用 eventHub.on() 方法注册一个自定义事件“event1”,eventHub.on()有如下两种调用方式,使用其中一种即可。

    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { UIAbility, Context, Want, AbilityConstant } from '@kit.AbilityKit';
    
    const DOMAIN_NUMBER: number = 0xFF00;
    const TAG: string = '[EventAbility]';
    
    export default class EntryAbility extends UIAbility {
      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        // 获取eventHub
        let eventhub = this.context.eventHub;
        // 执行订阅操作
        eventhub.on('event1', this.eventFunc);
        eventhub.on('event1', (data: string) => {
          // 触发事件,完成相应的业务操作
        });
        hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onCreate');
      }
    
      // ...
      eventFunc(argOne: Context, argTwo: Context): void {
        hilog.info(DOMAIN_NUMBER, TAG, '1. ' + `${argOne}, ${argTwo}`);
        return;
      }
    }
    
  • 在UI中通过eventHub.emit()方法触发该事件,在触发事件的同时,根据需要传入参数信息。

    import { common } from '@kit.AbilityKit';
    import { promptAction } from '@kit.ArkUI';
    
    @Entry
    @Component
    struct Page_EventHub {
      private context = getContext(this) as common.UIAbilityContext;
    
      eventHubFunc(): void {
        // 不带参数触发自定义“event1”事件
        this.context.eventHub.emit('event1');
        // 带1个参数触发自定义“event1”事件
        this.context.eventHub.emit('event1', 1);
        // 带2个参数触发自定义“event1”事件
        this.context.eventHub.emit('event1', 2, 'test');
        // 开发者可以根据实际的业务场景设计事件传递的参数
      }
    
      build() {
        Column() {
          // ...
          List({ initialIndex: 0 }) {
            ListItem() {
              Row() {
                // ...
              }
              .onClick(() => {
                this.eventHubFunc();
                promptAction.showToast({
                  message: 'EventHubFuncA'
                });
              })
            }
    
            // ...
            ListItem() {
              Row() {
                // ...
              }
              .onClick(() => {
                this.context.eventHub.off('event1');
                promptAction.showToast({
                  message: 'EventHubFuncB'
                });
              })
            }
            // ...
          }
          // ...
        }
        // ...
      }
    }
    
  • 在UIAbility的注册事件回调中可以得到对应的触发事件结果,运行日志结果如下所示。

    [Example].[Entry].[EntryAbility] 1. []
    [Example].[Entry].[EntryAbility] 1. [1]
    [Example].[Entry].[EntryAbility] 1. [2,"test"]
    
  • 在自定义事件“event1”使用完成后,可以根据需要调用eventHub.off()方法取消该事件的订阅。

    import { UIAbility } from '@kit.AbilityKit';
    
    export default class EntryAbility extends UIAbility {
      // ... 
      onDestroy(): void {
        this.context.eventHub.off('event1');
      }
    }
    
使用AppStorage/LocalStorage进行数据同步

ArkUI提供了AppStorageLocalStorage两种应用级别的状态管理方案,可用于实现应用级别和UIAbility级别的数据同步。使用这些方案可以方便地管理应用状态,提高应用性能和用户体验。其中,AppStorage是一个全局的状态管理器,适用于多个UIAbility共享同一状态数据的情况;而LocalStorage则是一个局部的状态管理器,适用于单个UIAbility内部使用的状态数据。通过这两种方案,开发者可以更加灵活地控制应用状态,提高应用的可维护性和可扩展性。详细请参见应用级变量的状态管理。

启动应用内的UIAbility组件

UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时,会涉及到启动特定的UIAbility,包括应用内的其他UIAbility、或者其他应用的UIAbility(例如启动三方支付UIAbility)。

本文主要介绍启动应用内的UIAbility组件的方式。应用间的组件跳转详见应用间跳转。

  • 启动应用内的UIAbility
  • 启动应用内的UIAbility并获取返回结果
  • 启动UIAbility的指定页面
1)启动应用内的UIAbility
当一个应用内包含多个UIAbility时,存在应用内启动UIAbility的场景。例如在支付应用中从入口UIAbility启动收付款UIAbility。

假设应用中有两个UIAbility:EntryAbility和FuncAbility(可以在同一个Module中,也可以在不同的Module中),需要从EntryAbility的页面中启动FuncAbility。

  • 在EntryAbility中,通过调用startAbility() 方法启动UIAbility,want为UIAbility实例启动的入口参数,其中bundleName为待启动应用的Bundle名称,abilityName为待启动的Ability名称,moduleName在待启动的UIAbility属于不同的Module时添加,parameters为自定义信息参数。示例中的context的获取方式请参见获取UIAbility的上下文信息。

    import { common, Want } from '@kit.AbilityKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    const TAG: string = '[Page_UIAbilityComponentsInteractive]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    @Entry
    @Component
    struct Page_UIAbilityComponentsInteractive {
      private context = getContext(this) as common.UIAbilityContext;
    
      build() {
        Column() {
          //...
          List({ initialIndex: 0 }) {
            ListItem() {
              Row() {
                //...
              }
              .onClick(() => {
                // context为Ability对象的成员,在非Ability对象内部调用需要
                // 将Context对象传递过去
                let wantInfo: Want = {
                  deviceId: '', // deviceId为空表示本设备
                  bundleName: 'com.samples.stagemodelabilitydevelop',
                  moduleName: 'entry', // moduleName非必选
                  abilityName: 'FuncAbilityA',
                  parameters: {
                    // 自定义信息
                    info: '来自EntryAbility Page_UIAbilityComponentsInteractive页面'
                  },
                };
                // context为调用方UIAbility的UIAbilityContext
                this.context.startAbility(wantInfo).then(() => {
                  hilog.info(DOMAIN_NUMBER, TAG, 'startAbility success.');
                }).catch((error: BusinessError) => {
                  hilog.error(DOMAIN_NUMBER, TAG, 'startAbility failed.');
                });
              })
            }
            //...
          }
          //...
        }
        //...
      }
    }
    
    • 在FuncAbility的onCreate()或者onNewWant()生命周期回调文件中接收EntryAbility传递过来的参数。
    import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
    
    export default class FuncAbilityA extends UIAbility {
      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        // 接收调用方UIAbility传过来的参数
        let funcAbilityWant = want;
        let info = funcAbilityWant?.parameters?.info;
      }
      //...
    }
    

    说明
    在被拉起的FuncAbility中,可以通过获取传递过来的want参数的parameters来获取拉起方UIAbility的PID、Bundle Name等信息。

  • 在FuncAbility业务完成之后,如需要停止当前UIAbility实例,在FuncAbility中通过调用terminateSelf()方法实现。

    import { common } from '@kit.AbilityKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    
    const TAG: string = '[Page_FromStageModel]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    @Entry
    @Component
    struct Page_FromStageModel {
      build() {
        Column() {
          //...
          Button('FuncAbilityB')
            .onClick(() => {
              let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
              // context为需要停止的UIAbility实例的AbilityContext
              context.terminateSelf((err) => {
                if (err.code) {
                  hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self. Code is ${err.code}, message is ${err.message}`);
                  return;
                }
              });
            })
        }
        //...
      }
    }
    

    说明
    调用terminateSelf()方法停止当前UIAbility实例时,默认会保留该实例的快照(Snapshot),即在最近任务列表中仍然能查看到该实例对应的任务。如不需要保留该实例的快照,可以在其对应UIAbility的module.json5配置文件中,将abilities标签的removeMissionAfterTerminate字段配置为true。

  • 如需要关闭应用所有的UIAbility实例,可以调用ApplicationContext的killAllProcesses()方法实现关闭应用所有的进程。

2)启动应用内的UIAbility并获取返回结果

在一个EntryAbility启动另外一个FuncAbility时,希望在被启动的FuncAbility完成相关业务后,能将结果返回给调用方。

例如: 在应用中将入口功能账号登录功能分别设计为两个独立的UIAbility,在账号登录UIAbility中完成登录操作后,需要将登录的结果返回给入口UIAbility。

  • 在EntryAbility中,调用**startAbilityForResult()**接口启动FuncAbility,异步回调中的data用于接收FuncAbility停止自身后返回给EntryAbility的信息。示例中的context的获取方式请参见获取UIAbility的上下文信息。

    import { common, Want } from '@kit.AbilityKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { promptAction } from '@kit.ArkUI';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    const TAG: string = '[Page_UIAbilityComponentsInteractive]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    @Entry
    @Component
    struct Page_UIAbilityComponentsInteractive {
      build() {
        Column() {
          //...
          List({ initialIndex: 0 }) {
            ListItem() {
              Row() {
                //...
              }
              .onClick(() => {
                let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
                const RESULT_CODE: number = 1001;
                let want: Want = {
                  deviceId: '', // deviceId为空表示本设备
                  bundleName: 'com.samples.stagemodelabilitydevelop',
                  moduleName: 'entry', // moduleName非必选
                  abilityName: 'FuncAbilityA',
                  parameters: {
                    // 自定义信息
                    info: '来自EntryAbility UIAbilityComponentsInteractive页面'
                  }
                };
                context.startAbilityForResult(want).then((data) => {
                  if (data?.resultCode === RESULT_CODE) {
                    // 解析被调用方UIAbility返回的信息
                    let info = data.want?.parameters?.info;
                    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? '');
                    if (info !== null) {
                      promptAction.showToast({
                        message: JSON.stringify(info)
                      });
                    }
                  }
                  hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? '');
                }).catch((err: BusinessError) => {
                  hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
                });
              })
            }
            //...
          }
          //...
        }
        //...
      }
    }
    
  • 在FuncAbility停止自身时,需要调用 terminateSelfWithResult() 方法,入参abilityResult为FuncAbility需要返回给EntryAbility的信息。

    import { common } from '@kit.AbilityKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    
    const TAG: string = '[Page_FuncAbilityA]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    @Entry
    @Component
    struct Page_FuncAbilityA {
      build() {
        Column() {
          //...
          List({ initialIndex: 0 }) {
            ListItem() {
              Row() {
                //...
              }
              .onClick(() => {
                let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
                const RESULT_CODE: number = 1001;
                let abilityResult: common.AbilityResult = {
                  resultCode: RESULT_CODE,
                  want: {
                    bundleName: 'com.samples.stagemodelabilitydevelop',
                    moduleName: 'entry', // moduleName非必选
                    abilityName: 'FuncAbilityB',
                    parameters: {
                      info: '来自FuncAbility Index页面'
                    },
                  },
                };
                context.terminateSelfWithResult(abilityResult, (err) => {
                  if (err.code) {
                    hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self with result. Code is ${err.code}, message is ${err.message}`);
                    return;
                  }
                });
              })
            }
            //...
          }
          //...
        }
        //...
      }
    }
    
  • FuncAbility停止自身后,EntryAbility通过**startAbilityForResult()**方法回调接收被FuncAbility返回的信息,RESULT_CODE需要与前面的数值保持一致

3)启动UIAbility的指定页面
概述

一个UIAbility可以对应多个页面,在不同的场景下启动该UIAbility时需要展示不同的页面,例如从一个UIAbility的页面中跳转到另外一个UIAbility时,希望启动目标UIAbility的指定页面。

UIAbility的启动分为两种情况:UIAbility冷启动和UIAbility热启动。

  • UIAbility冷启动:指的是UIAbility实例处于完全关闭状态下被启动,这需要完整地加载和初始化UIAbility实例的代码、资源等。
  • UIAbility热启动:指的是UIAbility实例已经启动并在前台运行过,由于某些原因切换到后台,再次启动该UIAbility实例,这种情况下可以快速恢复UIAbility实例的状态。
调用放UIAbility指定启动页面

调用方UIAbility启动另外一个UIAbility时,通常需要跳转到指定的页面。例如FuncAbility包含两个页面(Index对应首页,Second对应功能A页面),此时需要在传入的want参数中配置指定的页面路径信息,可以通过want中的parameters参数增加一个自定义参数传递页面跳转信息。示例中的context的获取方式请参见获取UIAbility的上下文信息。

import { common, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    Column() {
      //...
      List({ initialIndex: 0 }) {
        ListItem() {
          Row() {
            //...
          }
          .onClick(() => {
            let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
            let want: Want = {
              deviceId: '', // deviceId为空表示本设备
              bundleName: 'com.samples.stagemodelabilityinteraction',
              moduleName: 'entry', // moduleName非必选
              abilityName: 'FuncAbility',
              parameters: { // 自定义参数传递页面信息
                router: 'funcA'
              }
            };
            // context为调用方UIAbility的UIAbilityContext
            context.startAbility(want).then(() => {
              hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.');
            }).catch((err: BusinessError) => {
              hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`);
            });
          })
        }
        //...
      }
      //...
    }
    //...
  }
}
目标UIAbility冷启动

目标UIAbility冷启动时,在目标UIAbility的onCreate()生命周期回调中,接收调用方传过来的参数。然后在目标UIAbility的onWindowStageCreate() 生命周期回调中,解析调用方传递过来的want参数,获取到需要加载的页面信息url,传入windowStage.loadContent()方法。

import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window, UIContext } from '@kit.ArkUI';

const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[EntryAbility]';

export default class EntryAbility extends UIAbility {
  funcAbilityWant: Want | undefined = undefined;
  uiContext: UIContext | undefined = undefined;

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 接收调用方UIAbility传过来的参数
    this.funcAbilityWant = want;
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate');
    // Main window is created, set main page for this ability
    let url = 'pages/Index';
    if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') {
      url = 'pages/Page_ColdStartUp';
    }
    windowStage.loadContent(url, (err, data) => {
      // ...
    });
  }
}
目标UIAbility热启动

在应用开发中,会遇到目标UIAbility实例之前已经启动过的场景,这时再次启动目标UIAbility时,不会重新走初始化逻辑,只会直接触发onNewWant()生命周期方法。为了实现跳转到指定页面,需要在onNewWant()中解析参数进行处理

例如: 短信应用和联系人应用配合使用的场景。

  1. 用户先打开短信应用,短信应用的UIAbility实例启动,显示短信应用的主页。
  2. 用户将设备回到桌面界面,短信应用进入后台运行状态。
  3. 用户打开联系人应用,找到联系人张三。
  4. 用户点击联系人张三的短信按钮,会重新启动短信应用的UIAbility实例。
  5. 由于短信应用的UIAbility实例已经启动过了,此时会触发该UIAbility的onNewWant()回调,而不会再走onCreate()和onWindowStageCreate()等初始化逻辑。

ExtensionAbility组件

ExtensionAbility组件是基于特定场景(例如服务卡片、输入法等)提供的应用组件,以便满足更多的使用场景。

AbilityStage组件容器

AbilityStage是一个Module级别的组件容器,应用的HAP在首次加载时会创建一个AbilityStage实例,可以对该Module进行初始化等操作。

AbilityStage与Module一一对应,即一个Module拥有一个AbilityStage。

DevEco Studio默认工程中未自动生成AbilityStage,如需要使用AbilityStage的能力,可以手动新建一个AbilityStage文件,具体步骤如下。

  1. 在工程Module对应的ets目录下,右键选择“New > Directory”,新建一个目录并命名为myabilitystage。

  2. 在myabilitystage目录,右键选择“New > ArkTS File”,新建一个文件并命名为MyAbilityStage.ets。

  3. 打开MyAbilityStage.ets文件,导入AbilityStage的依赖包,自定义类继承AbilityStage并加上需要的生命周期回调,示例中增加了一个onCreate()生命周期回调。

    import { AbilityStage, Want } from '@kit.AbilityKit';
    
    export default class MyAbilityStage extends AbilityStage {
      onCreate(): void {
        // 应用HAP首次加载时触发,可以在此执行该Module的初始化操作(例如资源预加载、线程创建等)。
      }
    
      onAcceptWant(want: Want): string {
        // 仅specified模式下触发
        return 'MyAbilityStage';
      }
    }
    
  4. 在module.json5配置文件中,通过配置 srcEntry 参数来指定模块对应的代码路径,以作为HAP加载的入口。

    {
      "module": {
        "name": "entry",
        "type": "entry",
        "srcEntry": "./ets/myabilitystage/MyAbilityStage.ets",
        // ...
      }
    }
    

AbilityStage拥有onCreate()生命周期回调和onAcceptWant()onConfigurationUpdated()、**onMemoryLevel()**事件回调。

  • onCreate()生命周期回调:在开始加载对应Module的第一个UIAbility实例之前会先创建AbilityStage,并在AbilityStage创建完成之后执行其onCreate()生命周期回调。AbilityStage模块提供在Module加载的时候,通知开发者,可以在此进行该Module的初始化(如资源预加载,线程创建等)能力。
  • onAcceptWant()事件回调:UIAbility指定实例模式(specified)启动时候触发的事件回调,具体使用请参见UIAbility启动模式综述。
  • onConfigurationUpdated()事件回调:当系统全局配置发生变更时触发的事件,系统语言、深浅色等,配置项目前均定义在Configuration类中。
  • onMemoryLevel()事件回调:当系统调整内存时触发的事件。

应用被切换到后台时,系统会将在后台的应用保留在缓存中。即使应用处于缓存中,也会影响系统整体性能。当系统资源不足时,系统会通过多种方式从应用中回收内存,必要时会完全停止应用,从而释放内存用于执行关键任务。为了进一步保持系统内存的平衡,避免系统停止用户的应用进程,可以在AbilityStage中的onMemoryLevel()生命周期回调中订阅系统内存的变化情况,释放不必要的资源。

import { AbilityStage, AbilityConstant } from '@kit.AbilityKit';

export default class MyAbilityStage extends AbilityStage {
  onMemoryLevel(level: AbilityConstant.MemoryLevel): void {
    // 根据系统可用内存的变化情况,释放不必要的内存
  }
}

应用上下文Context

概述

Context是应用中对象的上下文,其提供了应用的一些基础信息,例如resourceManager(资源管理)、applicationInfo(当前应用信息)、dir(应用文件路径)、area(文件分区)等,以及应用的一些基本方法,例如createBundleContext()、getApplicationContext()等。UIAbility组件和各种ExtensionAbility派生类组件都有各自不同的Context类。分别有基类Context、ApplicationContext、AbilityStageContext、UIAbilityContext、ExtensionContext、ServiceExtensionContext等Context。、

各类Context的继承关系

在这里插入图片描述

各类Context的持有关系

在这里插入图片描述

各类Context的获取方式
获取UIAbilityContext。

每个UIAbility中都包含了一个Context属性,提供操作应用组件、获取应用组件的配置信息等能力。

import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    let uiAbilityContext = this.context;
    //...
  }
}

说明
页面中获取UIAbility实例的上下文信息请参见获取UIAbility的上下文信息。

获取特定场景ExtensionContext。

以ServiceExtensionContext为例,表示后台服务的上下文环境,继承自ExtensionContext,提供后台服务相关的接口能力。

import { ServiceExtensionAbility, Want } from '@kit.AbilityKit';

export default class ServiceExtAbility extends ServiceExtensionAbility {
  onCreate(want: Want) {
    let serviceExtensionContext = this.context;
    //...
  }
}
获取AbilityStageContext(Module级别的Context)

和基类Context相比,额外提供HapModuleInfo、Configuration等信息。

import { AbilityStage } from '@kit.AbilityKit';

export default class MyAbilityStage extends AbilityStage {
  onCreate(): void {
    let abilityStageContext = this.context;
    //...
  }
}
获取ApplicationContext(应用级别的Context)

ApplicationContext在基类Context的基础上提供了订阅应用内应用组件的生命周期的变化、订阅系统内存变化、订阅应用内系统环境变化、设置应用语言、设置应用颜色模式、清除应用自身数据和撤销应用向用户申请的权限等能力,在UIAbility、ExtensionAbility、AbilityStage中均可以获取。

import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    let applicationContext = this.context.getApplicationContext();
    //...
  }
}

Context的典型使用场景

获取应用文件路径

基类Context提供了获取应用文件路径的能力,ApplicationContext、AbilityStageContext、UIAbilityContext和ExtensionContext均继承该能力。应用文件路径属于应用沙箱路径,具体请参见应用沙箱目录。

获取和修改加密分区
获取本应用中其他Module的Context
订阅进程内UIAbility生命周期变化

信息传递载体Want

Want概述

Want的定义与用途

Want是一种对象,用于在应用组件之间传递信息。

其中,一种常见的使用场景是作为startAbility()方法的参数。例如,当UIAbilityA需要启动UIAbilityB并向UIAbilityB传递一些数据时,可以使用Want作为一个载体,将数据传递给UIAbilityB。
在这里插入图片描述

Want的类型
  • 显式Want
    在启动目标应用组件时,调用方传入的want参数中指定了abilityName和bundleName,称为显式Want。

    显式Want通常用于应用内组件启动,通过在Want对象内指定本应用Bundle名称信息(bundleName)和abilityName来启动应用内目标组件。当有明确处理请求的对象时,显式Want是一种简单有效的启动目标应用组件的方式。

    说明
    从API 12开始,已不再推荐三方应用使用指定Ability方式(即显式Want)拉起其他应用,推荐通过指定应用链接的方式来实现。

    import { Want } from '@kit.AbilityKit';
    
    let wantInfo: Want = {
      deviceId: '', // deviceId为空表示本设备
      bundleName: 'com.example.myapplication',
      abilityName: 'FuncAbility',
    }
    
  • 隐式Want
    在启动目标应用组件时,调用方传入的want参数中未指定abilityName,称为隐式Want。
    当需要处理的对象不明确时,可以使用隐式Want,在当前应用中使用其他应用提供的某个能力,而不关心提供该能力的具体应用。隐式Want使用skills标签来定义需要使用的能力,并由系统匹配声明支持该请求的所有应用来处理请求。例如,需要打开一个链接的请求,系统将匹配所有声明支持该请求的应用,然后让用户选择使用哪个应用打开链接。

    import { Want } from '@kit.AbilityKit';
    
    let wantInfo: Want = {
      // uncomment line below if wish to implicitly query only in the specific bundle.
      // bundleName: 'com.example.myapplication',
      action: 'ohos.want.action.search',
      // entities can be omitted
      entities: [ 'entity.system.browsable' ],
      uri: 'https://www.test.com:8080/query/student',
      type: 'text/plain',
    };
    

    说明

    • 根据系统中待匹配应用组件的匹配情况不同,使用隐式Want启动应用组件时会出现以下三种情况。

      未匹配到满足条件的应用组件:启动失败。
      匹配到一个满足条件的应用组件:直接启动该应用组件。
      匹配到多个满足条件的应用组件(UIAbility):弹出选择框让用户选择。

    • 对于启动ServiceExtensionAbility的场景。
      调用方传入的want参数中带有abilityName,则不允许通过隐式Want启动ServiceExtensionAbility。
      调用方传入的want参数中带有bundleName,则允许使用startServiceExtensionAbility()方法隐式Want启动ServiceExtensionAbility,默认返回优先级最高的ServiceExtensionAbility,如果优先级相同,返回第一个。

显式Want与隐式Want匹配规则

在启动目标应用组件时,会通过显式Want或者隐式Want进行目标应用组件的匹配,这里说的匹配规则就是调用方传入的want参数中设置的参数如何与目标应用组件声明的配置文件进行匹配。

显式Want匹配原理
名称类型匹配项必选规则
deviceIdstring留空将仅匹配本设备内的应用组件。
bundleNamestring如果指定abilityName,而不指定bundleName,则匹配失败。
abilityNamestring该字段必须设置表示显式匹配。
moduleNamestring留空时当同一个应用内存在多个模块且模块间存在重名应用组件,将默认匹配第一个。
uristring系统匹配时将忽略该参数,但仍可作为参数传递给目标应用组件。
typestring系统匹配时将忽略该参数,但仍可作为参数传递给目标应用组件。
actionstring系统匹配时将忽略该参数,但仍可作为参数传递给目标应用组件。
entitiesArray系统匹配时将忽略该参数,但仍可作为参数传递给目标应用组件。
flagsnumber不参与匹配,直接传递给系统处理,一般用来设置运行态信息,例如URI数据授权等。
parameters{[key: string]: Object}不参与匹配,应用自定义数据将直接传递给目标应用组件。
隐式Want匹配原理
名称类型匹配项必选规则
deviceIdstring跨设备目前不支持隐式调用。
abilityNamestring该字段必须留空表示隐式匹配。
bundleNamestring匹配对应应用包内的目标应用组件。
moduleNamestring匹配对应Module内的目标应用组件。
uristring参见want参数的uri和type匹配规则。
typestring参见want参数的uri和type匹配规则。
actionstring参见want参数的action匹配规则。
entitiesArray参见want参数的entities匹配规则。
flagsnumber不参与匹配,直接传递给系统处理,一般用来设置运行态信息,例如URI数据授权等。
parameters{[key: string]: Object}应用自定义数据将直接传递给目标应用组件。当前支持使用key为linkFeature的参数进行匹配,当linkFeature字段取值不为空时,优先进行linkFeature匹配。

使用显式Want启动应用组件

常见Action与Entities(不推荐使用)

组件启动规则(Stage模型)

启动组件是指一切启动或连接应用组件的行为:

  1. 启动UIAbility、ServiceExtensionAbility、DataShareExtensionAbility,如使用startAbility()、startServiceExtensionAbility()、startAbilityByCall()、openLink()等相关接口。
  2. 连接ServiceExtensionAbility、DataShareExtensionAbility,如使用connectServiceExtensionAbility()、createDataShareHelper()等相关接口。

应用启动框架AppStartup

订阅系统环境变量的变化

应用间跳转

进程模型

线程模型

Stage模型应用配置文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/955884.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Harmony OS 5.0.1 模拟器报未开启 Hyper-V解决方法

程序员Feri一名12年的程序员,做过开发带过团队创过业,擅长Java、嵌入式、鸿蒙、人工智能等,专注于程序员成长那点儿事,希望在成长的路上有你相伴!君志所向,一往无前! 今天在写Harmony NEXT版本的元服务的时候,突然模拟器无法启动了&#xff0…

WPS数据分析000004

目录 一、表格阅读技巧 冻结窗格 拆分窗口 新建窗口 阅读模式 护眼模式 二、表格打印技巧 打印预览 打印缩放 打印区域 打印标题 分页打印 打印位置 页眉页脚 逐份打印 三、表格保护技巧 锁定单元格 隐藏公式 文档权限 文件加密 一、表格阅读技巧 冻结窗…

LabVIEW桥接传感器数据采集与校准程序

该程序设计用于采集来自桥接传感器的数据,执行必要的设置(如桥接配置、信号采集参数、时间与触发设置),并进行适当的标定和偏移校正,最终通过图表呈现采集到的数据信息。程序包括多个模块,用于配置通道、触…

2025西湖论剑-babytrace

前言 就做了下题目,pwn1/3 都是签到,pwn2 后面绕 ptrace 有点意思,简单记录一下 漏洞分析 子进程中的读/写功能没有检查负数的情况,存在越界读写: void __fastcall get_value(__int64 *int64_arr) {__int64 ll; //…

【统计的思想】假设检验(一)

假设检验是统计学里的重要方法,同时也是一种“在理想与现实之间观察求索”的测试活动。假设检验从概率的角度去考察理想与现实之间的关系,籍此来缓解测试可信性问题。 我们先来看一个例子。民航旅客服务系统,简称PSS系统,有一种业…

GPT-5 传言:一场正在幕后发生的 AI 变革

新的一年,让我们从一个引人入胜的话题开始:如果我告诉你,GPT-5 并非虚构,而是真实存在呢?它不仅真实存在,而且正在你看不见的地方悄然塑造着世界。我的基本假设是:OpenAI 已经秘密开发出 GPT-5&…

【20】Word:小许-质量管理-论文❗

目录 题目​ NO1.2.3.4.5 NO6.7 NO8 NO9 NO10.11 题目 NO1.2.3.4.5 另存为“Word.docx”文件在考生文件夹下,F12Fn是另存为的作用布局→页面设置对话框→纸张:大小A4→页边距:上下左右不连续ctrl选择除表格外的所有内容→开始→字体对…

Leetcode - 周赛432

目录 一、3417. 跳过交替单元格的之字形遍历二、3418. 机器人可以获得的最大金币数三、3419. 图的最大边权的最小值四、3420. 统计 K 次操作以内得到非递减子数组的数目 一、3417. 跳过交替单元格的之字形遍历 题目链接 本题是一道模拟题,第一行走0,2&…

ASP.NET Core - 配置系统之配置提供程序

ASP.NET Core - 配置系统之配置提供程序 3. 配置提供程序3.1 文件配置提供程序3.1.1 JSON配置提供程序3.1.2 XML配置提供程序3.1.3 INI配置提供程序 3.2 环境变量配置提供程序3.3 命令行配置提供程序3.4 内存配置提供程序3.5 配置加载顺序 3.6 默认配置来源 3. 配置提供程序 前…

探索与创作:2024年CSDN平台上的成长与突破

文章目录 我与CSDN的初次邂逅初学阶段的阅读CSDN:编程新手的避风港初学者的福音:细致入微的知识讲解考试复习神器:技术总结的“救命指南”曾经的自己:为何迟迟不迈出写博客的第一步兴趣萌芽:从“读”到“想写”的初体验…

CSS中样式继承+优先级

继承属性和非继承属性 一、定义及分类 1、继承属性是指在父元素上设置了这些属性后,子元素会自动继承这些属性的值,除非子元素显式地设置了不同的值。 常见的继承属性: 字体 font 系列文本text-align text-ident line-height letter-spacing颜色 col…

macOS 安装JDK17

文章目录 前言介绍新特性下载安装1.下载完成后打开downloads 双击进行安装2.配置环境变量3.测试快速切换JDK 小结 前言 近期找开源软件,发现很多都已经使用JDK17springboot3 了,之前的JDK8已经被替换下场,所以今天就在本机安装了JDK17&#…

ChatGPT大模型极简应用开发-CH1-初识 GPT-4 和 ChatGPT

文章目录 1.1 LLM 概述1.1.1 语言模型和NLP基础1.1.2 Transformer及在LLM中的作用1.1.3 解密 GPT 模型的标记化和预测步骤 1.2 GPT 模型简史:从 GPT-1 到 GPT-41.2.1 GPT11.2.2 GPT21.2.3 GPT-31.2.4 从 GPT-3 到 InstructGPT1.2.5 GPT-3.5、Codex 和 ChatGPT1.2.6 …

vector迭代器的使用以及迭代器失效

一、iterator的使用注意 begin与end 遵循左闭右开的原则,begin 指向vector的第一个元素,end 指向vector的最后一个元素的往下一个位置。 rbegin 与 rend rbegin指向最后一个元素的位置,rend指向第一个元素的往前一个位置。 二、vector的常…

【Linux】15.Linux进程概念(4)

文章目录 程序地址空间前景回顾C语言空间布局图:代码1代码2代码3代码4代码5代码6代码7 程序地址空间前景回顾 历史核心问题: pid_t id fork(); if(id 0) else if(id>0) 为什么一个id可以放两个值呢?之前没有仔细讲。 C语言空间布局图&am…

【无法下载github文件】虚拟机下ubuntu无法拉取github文件

修改hosts来进行解决。 步骤一:打开hosts文件 sudo vim /etc/hosts步骤二:查询 github.com的ip地址 https://sites.ipaddress.com/github.com/#ipinfo将github.com的ip地址添加到hosts文件末尾,如下所示。 140.82.114.3 github.com步骤三…

Android BitmapShader实现狙击瞄具十字交叉线准星,Kotlin

Android BitmapShader实现狙击瞄具十字交叉线准星&#xff0c;Kotlin <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.…

Android系统开发(十):标准协议和通讯的桥梁:探索蓝牙、NFC、WLAN 的工作原理

引言&#xff1a; 现代社会已经是信息互联的世界&#xff0c;各种设备之间的互联互通已经成为了生活的一部分。而在这个过程中&#xff0c;Android 设备与其他硬件之间的通信扮演着至关重要的角色。从蓝牙耳机到 WiFi 路由器&#xff0c;甚至与电话功能的互动&#xff0c;所有…

node中文名的js文件有问题

新版Node无法运行含有中文名的JS文件&#xff0c;具体表现在无报错无反应。如下图&#xff1a; 源码如下&#xff1a; 改成英文的JS文件&#xff0c;则正常&#xff0c;如下图&#xff1a;

BERT与CNN结合实现糖尿病相关医学问题多分类模型

完整源码项目包获取→点击文章末尾名片&#xff01; 使用HuggingFace开发的Transformers库&#xff0c;使用BERT模型实现中文文本分类&#xff08;二分类或多分类&#xff09; 首先直接利用transformer.models.bert.BertForSequenceClassification()实现文本分类 然后手动实现B…