鸿蒙 后台任务开发:短时任务
HarmonyOS后台任务管理摘要:针对应用退至后台时的系统资源管控,HarmonyOS提供了BackgroundTasksKit解决方案,支持短时任务、长时任务、延迟任务和代理提醒四种后台任务类型。其中短时任务适用于耗时短(≤3分钟)的实时性任务,具有严格配额机制(单日10分钟,单次3分钟),需在前台或onBackground回调中申请,任务完成后必须主动取消。开发时需注意配额管理、超时处理和多
本文同步发表于 微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
当应用退至后台(返回主界面、锁屏、应用切换)时,系统会对应用进行管控:
-
进程挂起:应用退至后台一段时间后,进程被挂起,无法使用CPU、网络、GPS等资源
-
进程终止:资源不足时,系统会终止部分应用进程以回收资源
Background Tasks Kit的作用
为了解决后台功能需求与系统资源管控的矛盾,HarmonyOS提供了Background Tasks Kit,支持以下四种规范化的后台任务:
| 任务类型 | 适用场景 | 特点 |
|---|---|---|
| 短时任务 | 状态保存、消息发送等实时性高、耗时短的任务 | 单次最长3分钟,有配额限制 |
| 长时任务 | 后台音乐播放、导航、设备连接等用户可感知的任务 | 长时间运行,避免进程挂起 |
| 延迟任务 | 实时性不高、可延迟执行的任务 | 系统统一调度,智能分配资源 |
| 代理提醒 | 倒计时、日历、闹钟等定时提醒 | 系统代理执行,进程终止后仍有效 |
二、短时任务
短时任务允许应用在被系统挂起前,执行一些耗时较短的操作(如状态保存、消息发送等),扩展应用在后台的运行时间。
限制与配额机制
申请时机限制
// 正确:在前台或onBackground回调内申请
onForeground() {
this.requestShortTask();
}
onBackground() {
this.requestShortTask(); // 在回调内申请
}
// 错误:在onStop或应用已退到后台后申请
onStop() {
this.requestShortTask(); // 会失败
}
数量限制
-
一个应用同一时刻最多申请3个短时任务
-
多个短时任务可以重叠执行
配额机制
| 配额类型 | 限制值 | 说明 |
|---|---|---|
| 单日配额 | 10分钟 | 24小时内所有短时任务总时长 |
| 单次配额 | 3分钟 | 单次短时任务最大时长 |
| 低电量单次 | 1分钟 | 设备低电量时自动降低 |
| 剩余时间查询 | 支持 | 可查询本次任务剩余时间 |
配额计算规则
// 重要规则:
// 1. 仅当应用在后台时才会计时
// 2. 前台时间不计入配额
// 3. 同一时间段内的多个任务不重复计时
假设场景:
-
应用在前台申请任务A
-
退到后台开始计时(阶段①)
-
回到前台(阶段②不计时)
-
再次退到后台(阶段③计时)
-
任务A结束后,任务B仍在运行(阶段④计时)
总耗时 = ① + ③ + ④
三、实例代码
3.1 导入模块
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { BusinessError } from '@kit.BasicServicesKit';
3.2 申请短时任务
let taskId: number = 0; // 任务ID
let remainingTime: number = 0; // 剩余时间
/**
* 申请短时任务
* @param reason 申请原因(用于系统日志和调试)
*/
function requestShortTask(reason: string = '状态保存') {
try {
// 1. 申请短时任务
const delayInfo = backgroundTaskManager.requestSuspendDelay(
reason,
() => {
// 超时回调:任务即将结束时触发
console.warn('短时任务即将超时!请立即清理并取消任务');
// 执行清理工作
this.cleanupResources();
// 必须取消任务
this.cancelShortTask();
}
);
// 2. 保存任务信息
taskId = delayInfo.requestId;
remainingTime = delayInfo.actualDelayTime;
console.info(`短时任务申请成功!`);
console.info(`任务ID: ${taskId}`);
console.info(`获得时间: ${remainingTime}ms`);
console.info(`最大允许: 3分钟`);
// 3. 执行业务逻辑
this.executeBackgroundWork();
} catch (error) {
const err = error as BusinessError;
console.error(`短时任务申请失败!错误码: ${err.code}, 消息: ${err.message}`);
// 常见错误码:
// 12900001: 配额已用完
// 12900002: 申请时机不正确
// 12900003: 已达到最大任务数
}
}
3.3 查询剩余时间
/**
* 查询短时任务剩余时间
* 用于判断是否继续执行其他任务
*/
async function checkRemainingTime(): Promise<boolean> {
try {
const remaining = await backgroundTaskManager.getRemainingDelayTime(taskId);
console.info(`剩余时间: ${remaining}ms`);
// 判断是否还有足够时间执行新任务
if (remaining > 30000) { // 30秒
console.info('时间充足,可以继续执行其他任务');
return true;
} else {
console.warn('时间不足,建议只执行关键任务');
return false;
}
} catch (error) {
const err = error as BusinessError;
console.error(`查询剩余时间失败!错误码: ${err.code}, 消息: ${err.message}`);
return false;
}
}
// 使用示例
async function executeMultipleTasks() {
// 执行第一个任务
await this.saveAppState();
// 检查剩余时间
const hasTime = await this.checkRemainingTime();
// 根据时间决定是否执行第二个任务
if (hasTime) {
await this.sendPendingMessages();
} else {
console.warn('时间不足,跳过非关键任务');
}
}
3.4 取消短时任务
/**
* 取消短时任务
* 重要:任务完成后必须主动取消!
*/
function cancelShortTask() {
if (taskId === 0) {
console.warn('没有活动的短时任务');
return;
}
try {
backgroundTaskManager.cancelSuspendDelay(taskId);
console.info('短时任务已取消');
// 重置状态
taskId = 0;
remainingTime = 0;
} catch (error) {
const err = error as BusinessError;
console.error(`取消短时任务失败!错误码: ${err.code}, 消息: ${err.message}`);
}
}
3.5 完整代码
@Entry
@Component
struct BackgroundTaskDemo {
private taskId: number = 0;
// 应用进入后台
onBackground() {
console.info('应用进入后台,申请短时任务');
// 申请短时任务进行状态保存
this.requestShortTask('保存用户数据');
}
// 申请短时任务
private requestShortTask(reason: string) {
try {
const delayInfo = backgroundTaskManager.requestSuspendDelay(
reason,
this.onTaskTimeout.bind(this)
);
this.taskId = delayInfo.requestId;
// 执行后台任务
this.saveUserData();
} catch (error) {
console.error(`申请失败: ${error.message}`);
}
}
// 超时回调
private onTaskTimeout() {
console.warn('任务即将超时,立即保存进度并取消');
// 保存当前进度
this.saveProgress();
// 取消任务
this.cancelTask();
}
// 保存用户数据
private async saveUserData() {
try {
// 模拟数据保存
await this.saveToStorage();
console.info('数据保存完成');
// 任务完成,立即取消
this.cancelTask();
} catch (error) {
console.error('保存失败', error);
}
}
// 取消任务
private cancelTask() {
if (this.taskId > 0) {
backgroundTaskManager.cancelSuspendDelay(this.taskId);
this.taskId = 0;
}
}
}
四、注意事项
4.1 必须遵守的规则
1. 及时取消任务
// 正确:任务完成立即取消
async function saveData() {
await data.save();
backgroundTaskManager.cancelSuspendDelay(taskId);
}
2. 正确处理超时
// 超时回调中必须:
// 1. 执行紧急清理
// 2. 保存当前状态
// 3. 取消任务
const timeoutCallback = () => {
// 紧急保存
this.emergencySave();
// 记录日志
console.warn('任务超时,已保存进度');
// 必须取消!
this.cancelTask();
};
3. 配额管理
class ShortTaskManager {
private usedQuotaToday: number = 0;
private MAX_DAILY_QUOTA: number = 10 * 60 * 1000; // 10分钟
// 申请前检查配额
canRequestTask(duration: number): boolean {
if (this.usedQuotaToday + duration > this.MAX_DAILY_QUOTA) {
console.warn('今日配额不足');
return false;
}
// 检查设备电量
if (this.isLowBattery()) {
console.warn('低电量模式,任务时间可能缩短');
}
return true;
}
// 记录已用配额
recordQuotaUsage(duration: number) {
this.usedQuotaToday += duration;
console.info(`今日已用配额: ${this.usedQuotaToday}ms`);
}
}
六、短时任务 vs 其他后台任务
| 场景特征 | 推荐方案 | 理由 |
|---|---|---|
| 任务时长 < 3分钟 实时性要求高 |
短时任务 | 立即执行,不延迟 |
| 任务时长 > 3分钟 用户可感知 |
长时任务 | 避免进程挂起 |
| 可延迟执行 不紧急 |
延迟任务 | 系统智能调度,更省电 |
| 定时提醒 进程终止后仍需执行 |
代理提醒 | 系统代理,可靠性高 |
备注
-
申请时机:必须在前台或onBackground回调中申请
-
配额要管理:单日10分钟,单次3分钟,低电量时1分钟
-
任务要取消:完成或超时必须调用
cancelSuspendDelay(),如果超时不取消,系统会对应用进行管控,包括进程挂起和进程终止。 -
时间要检查:使用
getRemainingDelayTime()合理安排任务 -
数量要控制:同一时刻不超过3个任务
更多推荐



所有评论(0)