1 任务(Mission)管理场景
任务(Mission)管理相关的基本概念如下:
-
AbilityRecord :系统服务侧管理一个
UIAbility
实例的最小单元,对应一个应用侧的UIAbility
组件实例。系统服务侧管理UIAbility
实例数量上限为512
个。 -
MissionRecord :任务管理的最小单元。一个
MissionRecord
中仅有一个AbilityRecord
,即一个UIAbility
组件实例对应一个单独的任务。 -
MissionList:一个从桌面开始启动的任务列表,记录了任务之间的启动关系,下一个任务由上一个任务启动,最底部的任务由桌面启动,这里称之为任务链。
-
MissionListManager :系统任务管理模块,内部维护了当前所有的任务链,与最近任务列表保持一致。
任务的管理由
系统应用
(如桌面应用)负责,三方应用无法管理任务。用户通过最近任务列表进行任务的相关交互。当创建任务后,用户可以对最近任务列表进行如下操作: -
删除一个指定的任务。
-
加锁或解锁一个指定的任务(加锁后的任务在清理所有任务时不会被清理)。
-
清理最近任务列表中的所有任务。
-
将一个指定的任务切换到前台。
一个UIAbility
实例对应一个单独的任务
,因此应用调用startAbility()
方法启动一个UIAbility
时,就是创建了一个任务。
- 桌面应用调用
missionManager
的接口管理任务,需要申请ohos.permission.MANAGE_MISSIONS
权限,配置方式请参见配置文件权限声明。 - 利用
missionManager
进行任务管理(监听任务变化、获取任务信息、获取任务快照、清理任务、任务加锁/解锁等)。
typescript
import missionManager from '@ohos.app.ability.missionManager'
import { BusinessError } from '@ohos.base';
let listener: missionManager.MissionListener = {
// 任务创建
onMissionCreated: (mission) => {
console.info("--------onMissionCreated-------")
},
// 任务销毁
onMissionDestroyed: (mission) => {
console.info("--------onMissionDestroyed-------")
},
// 任务快照变化
onMissionSnapshotChanged: (mission) => {
console.info("--------onMissionSnapshotChanged-------")
},
// 任务被移动到前台
onMissionMovedToFront: (mission) => {
console.info("--------onMissionMovedToFront-------")
},
// 任务图标变化
onMissionIconUpdated: (mission, icon) => {
console.info("--------onMissionIconUpdated-------")
},
// 任务名称变化
onMissionLabelUpdated: (mission) => {
console.info("--------onMissionLabelUpdated-------")
},
// 任务实例被关闭
onMissionClosed: (mission) => {
console.info("--------onMissionClosed-------")
}
};
// 1.注册任务变化通知
let listenerId = missionManager.on('mission', listener);
// 2.获取系统最近20个任务
missionManager.getMissionInfos("", 20, (error, missions) => {
console.info("getMissionInfos is called, error.code = " + error.code);
console.info("size = " + missions.length);
console.info("missions = " + JSON.stringify(missions));
});
// 3.获取单个任务的详细信息()
let missionId = 11; // 11只是示例,实际是从系统中获取的任务id,下面类似
let mission = missionManager.getMissionInfo("", missionId).catch((err: BusinessError) => {
console.info('${err.code}');
});
// 4.获取任务快照
missionManager.getMissionSnapShot("", missionId, (error, snapshot) => {
console.info("getMissionSnapShot is called, error.code = " + error.code);
console.info("bundleName = " + snapshot.ability.bundleName);
})
// 5.获取低分辨任务快照
missionManager.getLowResolutionMissionSnapShot("", missionId, (error, snapshot) => {
console.info("getLowResolutionMissionSnapShot is called, error.code = " + error.code);
console.info("bundleName = " + snapshot.ability.bundleName);
})
// 6.加锁/解锁任务
missionManager.lockMission(missionId).then(() => {
console.info("lockMission is called ");
});
missionManager.unlockMission(missionId).then(() => {
console.info("unlockMission is called ");
});
// 7.把任务切到前台
missionManager.moveMissionToFront(missionId).then(() => {
console.info("moveMissionToFront is called ");
});
// 8.删除单个任务
missionManager.clearMission(missionId).then(() => {
console.info("clearMission is called ");
});
// 9.删除全部任务
missionManager.clearAllMissions().catch((err: BusinessError) => {
console.info('${err.code}');
});
// 10.解注册任务变化通知
missionManager.off('mission', listenerId, (error) => {
console.info("unregisterMissionListener");
})
2 任务(Mission)与启动模式
如前文所述,一个UIAbility实例对应一个任务。UIAbility实例个数与UIAbility配置的启动模式有关。在FA模型下,通过config.json配置文件中的"launchType"属性配置;在Stage模型下,通过module.json5配置文件中的"launchType"属性配置。
下面介绍了任务管理如何实现以下三种启动模式UIAbility组件的管理:
2.1 singleton单实例模式
应用在运行时只存在一个该UIAbility
实例。
2.2 multiton多实例模式
每次调用startAbility()
方法,都会在应用进程中创建一个该UIAbility
实例。
2.3 specified指定实例模式
由AbilityStage
的(onAcceptWant()
)决定是否创建新的UIAbility
实例。
每个UIAbility
实例都对应了一个最近任务列表中看到的Mission
(任务)。
每个UIAbility
实例对应的Mission
都保留有该UIAbility
实例的快照(Snapshot)
,UIAbility
实例销毁后,Mission
信息(包括UIAbility
信息和任务快照
)依然会保留,直到用户删除该任务。
3 页面栈及任务链
3.1 页面栈
单个UIAbility
组件可以实现多个页面,并在多个页面之间跳转,这种UIAbility
组件内部的页面跳转关系称为"页面栈",由ArkUI框架统一管理,如下图中:
UIAbility1
的Page1->Page2->Page3
UIAbility2
的PageA->PageB->PageC
。
- 页面栈的形成(下面2/3/5/6步骤为页面跳转,由ArkUI管理)
- 点击桌面图标(
startAbility
)启动UIAbility1
,UIAbility1
的初始页面为Page1
。 - 点击
Page1
页面按钮(Navigator
)跳转到Page2
页面。 - 点击
Page2
页面按钮(Navigator
)跳转到Page3
页面。 - 点击Page3页面按钮(
startAbility
)跳转到UIAbility2
,UIAbility2
的初始页面为PageA
。 - 点击
PageA
页面按钮(Navigator
)跳转到PageB
页面。 - 点击
PageB
页面按钮(Navigator
)跳转到PageC
页面。
- 页面栈的返回(下面1/2/4/5步骤为页面跳转,由ArkUI管理)
- 在
UIAbility2
的PageC
页面点击返回键回到UIAbility2
的PageB
页面。 - 在
UIAbility2
的PageB
页面点击返回键回到UIAbility2
的PageA
页面。 - 在
UIAbility2
的PageA
页面点击返回键跳转到UIAbility1
的Page3
页面。 - 在
UIAbility1
的Page3
页面点击返回键回到UIAbility1
的Page2
页面。 - 在
UIAbility1
的Page2
页面点击返回键回到UIAbility1
的Page1
页面。 - 在
UIAbility1
的Page1
页面点击返回键回到桌面
。
3.2 任务链
上文介绍了页面栈的返回,如果Ability2页面栈
一层层通过返回键返回到最底层,再次点击返回键时,会返回到Ability1
。因为在MissionList
中记录了任务(Mission)
之间的启动关系,即如果Ability1
通过startAbility
启动Ability2
,则会形成一个MissionList任务链
:Ability1->Ability2
,当Ability2
页面栈返回到首页时,再次点击返回键,会返回到Ability1
的页面。
MissionList任务链
记录了任务之间的拉起关系,但是这个任务链可能会断开,有以下几种情况会导致任务链的断开:
- 进入任务列表,把任务链中间某个任务移动到前台。
- 进入任务列表,把任务链中间某个任务清理掉。
- 单实例
UIAbility
的任务,被不同的任务(包括Ability
或桌面)反复拉起(AbilityB
为单例)。
4 设置任务快照的图标和名称
设置任务快照的图标和名称是为了提高用户界面的可视化性和用户体验,以便更好地管理和跟踪应用程序中的任务和功能。通过为每个任务快照设置不同的图标
和名称
,可以更轻松地区分和识别每个任务的功能。
默认情况下任务快照的图标和名称采用的是module.json5
配置文件的abilities
标签中的icon
和label
字段,如下图所示。
也可以使用UIAbilityContext.setMissionIcon()
和UIAbilityContext.setMissionLabel()
方法,根据需要自定义任务快照的图标和名称。例如,对于UIAbility
的多实例启动模式,可以根据不同的功能配置相应的任务快照的图标
和名称
。
4.1 设置任务快照的图标(仅对系统应用开放)
通过调用UIAbilityContext.setMissionIcon()
方法修改任务快照的图标。
typescript
import common from '@ohos.app.ability.common';
import { BusinessError } from '@ohos.base';
let context: common.UIAbilityContext = ...; // UIAbilityContext
let pixelMap: PixelMap = ...; // 图片的PixelMap信息
context.setMissionIcon(pixelMap, (err: BusinessError) => {
if (err.code) {
console.error(`Failed to set mission icon. Code is ${err.code}, message is ${err.message}`);
}
})
4.2 设置任务快照的名称
通过调用UIAbilityContext.setMissionLabel()
方法修改任务快照的名称。
typescript
import common from '@ohos.app.ability.common';
import { BusinessError } from '@ohos.base';
let context: common.UIAbilityContext = this.context; // UIAbilityContext
context.setMissionLabel('test').then(() => {
console.info('Succeeded in seting mission label.');
}).catch((err: BusinessError) => {
console.error(`Failed to set mission label. Code is ${err.code}, message is ${err.message}`);
});