UIAbility 组件启动模式
singleton(单实例模式)
multiton(多实例模式)
specified(指定实例模式)
singleton 启动模式
singleton 启动模式为单实例模式,也是默认情况下的启动模式。
每次调用 startAbility()方法时,如果应用进程中该类型的 UIAbility 实例已经存在,则复用系统中的 UIAbility 实例。系统中只存在唯一一个该 UIAbility 实例,即在最近任务列表中只存在一个该类型的 UIAbility 实例。
INFO
应用的 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(多实例模式)。
multiton 启动模式的开发使用,在 module.json5
配置文件中的 launchType 字段配置为 multiton 即可。
{
"module": {
// ...
"abilities": [
{
"launchType": "multiton",
// ...
}
]
}
}
specified 启动模式
specified 启动模式为指定实例模式,针对一些特殊场景使用(例如文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例)。
例如有两个 UIAbility:EntryAbility 和 SpecifiedAbility,SpecifiedAbility 配置为指定实例模式启动,需要从 EntryAbility 的页面中启动 SpecifiedAbility。
设置
- (1) 启用
在 SpecifiedAbility 中,将 module.json5 配置文件的 launchType 字段配置为 specified。
{
"module": {
// ...
"abilities": [
{
"launchType": "specified",
// ...
}
]
}
}
- (2) 指定 KEY
在创建 UIAbility 实例之前,开发者可以为该实例指定一个唯一的字符串 Key,这样在调用 startAbility()方法时,应用就可以根据指定的 Key 来识别响应请求的 UIAbility 实例。在 EntryAbility 中,调用 startAbility()方法时,可以在 want 参数中增加一个自定义参数,例如 instanceKey,以此来区分不同的 UIAbility 实例。
// 在启动指定实例模式的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 的启动模式被配置为指定实例启动模式,因此在 SpecifiedAbility 启动之前,会先进入对应的 AbilityStage 的 onAcceptWant()生命周期回调中,以获取该 UIAbility 实例的 Key 值。然后系统会自动匹配,如果存在与该 UIAbility 实例匹配的 Key,则会启动与之绑定的 UIAbility 实例,并进入该 UIAbility 实例的 onNewWant()回调函数;否则会创建一个新的 UIAbility 实例,并进入该 UIAbility 实例的 onCreate()回调函数和 onWindowStageCreate()回调函数。
示例代码中,通过实现 onAcceptWant()生命周期回调函数,解析传入的 want 参数,获取自定义参数 instanceKey。业务逻辑会根据这个参数返回一个字符串 Key,用于标识当前 UIAbility 实例。如果返回的 Key 已经对应一个已启动的 UIAbility 实例,系统会将该 UIAbility 实例拉回前台并获焦,而不会创建新的实例。如果返回的 Key 没有对应已启动的 UIAbility 实例,则系统会创建新的 UIAbility 实例并启动。
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";
}
}
INFO
当应用的 UIAbility 实例已经被创建,并且配置为指定实例模式时,如果再次调用 startAbility()方法启动该 UIAbility 实例,且 AbilityStage 的 onAcceptWant()回调匹配到一个已创建的 UIAbility 实例,则系统会启动原来的 UIAbility 实例,并且不会重新创建一个新的 UIAbility 实例。此时,该 UIAbility 实例的 onNewWant()回调会被触发,而不会触发 onCreate()和 onWindowStageCreate()生命周期回调。
举例
例如在文档应用中,可以为不同的文档实例内容绑定不同的 Key 值。每次新建文档时,可以传入一个新的 Key 值(例如可以将文件的路径作为一个 Key 标识),此时 AbilityStage 中启动 UIAbility 时都会创建一个新的 UIAbility 实例;当新建的文档保存之后,回到桌面,或者新打开一个已保存的文档,回到桌面,此时再次打开该已保存的文档,此时 AbilityStage 中再次启动该 UIAbility 时,打开的仍然是之前原来已保存的文档界面。
打开文件 A,对应启动一个新的 UIAbility 实例,例如启动 UIAbility 实例 1。
在最近任务列表中关闭文件 A 的任务进程,此时 UIAbility 实例 1 被销毁,回到桌面,再次打开文件 A,此时对应启动一个新的 UIAbility 实例,例如启动 UIAbility 实例 2。
回到桌面,打开文件 B,此时对应启动一个新的 UIAbility 实例,例如启动 UIAbility 实例 3。
回到桌面,再次打开文件 A,此时仍然启动之前的 UIAbility 实例 2,因为系统会自动匹配 UIAbility 实例的 Key 值,如果存在与之匹配的 Key,则会启动与之绑定的 UIAbility 实例。在此例中,之前启动的 UIAbility 实例 2 与文件 A 绑定的 Key 是相同的,因此系统会拉回 UIAbility 实例 2 并让其获焦,而不会创建新的实例。