HarmonyOS APP周期任务:定时重复执行的后台利器
HarmonyOS APP周期任务:定时重复执行的后台利器
📌 核心要点:周期任务基于
workScheduler的isRepeat: true配置,支持最小 20 分钟的重复间隔,适合数据定期刷新、健康检查等规律性后台操作。
一、背景与动机
你有没有注意到,手机上的天气预报 App 不用你手动刷新,每隔一段时间就会自动更新天气数据?微信的消息也不是你打开才收到的,它在后台定期拉取新消息。还有运动手环的 App,每隔一段时间就同步一次步数数据。
这些场景有一个共同特征:任务需要定期、重复地执行。不是一次性的,也不是持续不间断的,而是"每隔一段时间来一次"。
这就像你每天早上 7 点的闹钟——不是只响一次,而是每天重复。或者你每周一的例会——不是开一次就完了,而是每周固定时间重复。
HarmonyOS 的周期任务就是为这种"定期重复"的需求设计的。它和延迟任务使用同一个 workScheduler 模块,区别在于 isRepeat 参数设为 true,并指定 repeatInterval(重复间隔)。
你可能会问:既然都是 workScheduler,为什么要把周期任务单独拿出来讲?因为周期任务有很多独特的考量和陷阱——间隔怎么设、重复次数怎么控、和延迟任务到底有什么区别、怎么避免"过度调度"导致耗电……这些都是在实际开发中必须搞清楚的问题。
二、核心原理
2.1 周期任务调度模型
周期任务的调度模型和延迟任务类似,但增加了"重复执行"的逻辑:
flowchart TD
A([应用注册周期任务]) --> B[设置 isRepeat = true]
B --> C[设置 repeatInterval 间隔]
C --> D[提交到 workScheduler]
D --> E{系统评估执行条件}
E -->|条件不满足| F[等待下一个调度窗口]
F --> E
E -->|条件满足| G[执行 WorkSchedulerExtension 回调]
G --> H[执行周期任务逻辑]
H --> I{是否继续重复?}
I -->|是| J[等待 repeatInterval 间隔]
J --> E
I -->|否| K[取消周期任务]
K --> L([任务结束])
classDef primary fill:#4CAF50,stroke:#388E3C,color:#fff
classDef warning fill:#FF9800,stroke:#F57C00,color:#fff
classDef error fill:#F44336,stroke:#D32F2F,color:#fff
classDef info fill:#2196F3,stroke:#1976D2,color:#fff
classDef purple fill:#9C27B0,stroke:#7B1FA2,color:#fff
class A,L primary
class B,C,D,G,H info
class E,F,J warning
class I,K purple
2.2 间隔配置规则
周期任务的 repeatInterval 有严格的限制:
| 配置项 | 规则 | 说明 |
|---|---|---|
| 最小间隔 | 20 分钟(1200000ms) | 不能低于此值,否则注册失败 |
| 推荐间隔 | 1-6 小时 | 平衡实时性和省电 |
| 最大间隔 | 无硬性上限 | 但间隔太长不如用延迟任务 |
| 精度保证 | 不保证精确 | 系统会根据电量等条件调整 |
常见的间隔配置:
// 常用间隔常量
const INTERVAL_20_MIN = 20 * 60 * 1000; // 最小间隔:20分钟
const INTERVAL_1_HOUR = 60 * 60 * 1000; // 1小时
const INTERVAL_3_HOUR = 3 * 60 * 60 * 1000; // 3小时
const INTERVAL_6_HOUR = 6 * 60 * 60 * 1000; // 6小时
const INTERVAL_12_HOUR = 12 * 60 * 60 * 1000; // 12小时
const INTERVAL_24_HOUR = 24 * 60 * 60 * 1000; // 24小时
2.3 周期任务 vs 延迟任务对比
很多人搞不清周期任务和延迟任务的区别,下面这个对比表帮你一目了然:
graph TB
subgraph 延迟任务
A1[一次性执行] --> A2[条件满足时触发]
A2 --> A3[执行完毕后任务消失]
end
subgraph 周期任务
B1[重复执行] --> B2[条件满足+间隔到达时触发]
B2 --> B3[执行完毕后等待下一周期]
B3 --> B2
end
classDef primary fill:#4CAF50,stroke:#388E3C,color:#fff
classDef warning fill:#FF9800,stroke:#F57C00,color:#fff
classDef error fill:#F44336,stroke:#D32F2F,color:#fff
classDef info fill:#2196F3,stroke:#1976D2,color:#fff
classDef purple fill:#9C27B0,stroke:#7B1FA2,color:#fff
class A1,A2,A3 info
class B1,B2,B3 purple
| 对比维度 | 延迟任务 | 周期任务 |
|---|---|---|
isRepeat |
false |
true |
| 执行次数 | 1 次 | 重复多次 |
repeatInterval |
不需要 | 必须设置(≥20分钟) |
| 典型场景 | 数据备份、文件上传 | 数据刷新、健康检查 |
| 资源消耗 | 低(一次性) | 中(定期消耗) |
| 取消时机 | 执行完自动消失 | 需主动取消 |
| 精确度 | 不保证 | 不保证 |
三、代码实战
3.1 天气数据定期刷新
最经典的周期任务场景——每隔几小时自动刷新天气数据:
import workScheduler from '@ohos.resourceschedule.workScheduler';
import { BusinessError } from '@ohos.base';
/**
* 天气数据周期刷新管理器
* 每隔3小时在Wi-Fi条件下自动刷新天气数据
*/
export class WeatherRefreshScheduler {
/** 周期任务ID */
private readonly WEATHER_TASK_ID: number = 40001;
/** 回调能力名称 */
private readonly WEATHER_TASK_NAME: string = 'weatherRefreshTask';
/** 刷新间隔:3小时 */
private readonly REFRESH_INTERVAL: number = 3 * 60 * 60 * 1000;
/**
* 注册天气数据周期刷新任务
* 条件:Wi-Fi网络 + 每3小时重复
*/
registerWeatherRefresh(): void {
try {
const workInfo: workScheduler.WorkInfo = {
workId: this.WEATHER_TASK_ID,
// 网络条件:Wi-Fi(避免流量消耗)
networkType: workScheduler.NetworkType.NETWORK_TYPE_WIFI,
// 重复执行
isRepeat: true,
// 重复间隔:3小时
repeatInterval: this.REFRESH_INTERVAL,
// 回调能力名称
abilityName: this.WEATHER_TASK_NAME,
// 额外参数
parameters: {
cityCode: '110000', // 北京
dataType: 'current_and_forecast',
},
};
workScheduler.startWork(workInfo);
console.info('[天气刷新] 周期任务注册成功');
console.info(`[天气刷新] 刷新间隔: ${this.REFRESH_INTERVAL / 3600000} 小时`);
console.info('[天气刷新] 网络条件: Wi-Fi');
} catch (error) {
const err = error as BusinessError;
console.error(`[天气刷新] 注册失败,错误码: ${err.code},错误信息: ${err.message}`);
}
}
/**
* 更新刷新间隔
* 用户在设置中调整刷新频率时调用
* @param intervalHours 新的间隔(小时)
*/
updateRefreshInterval(intervalHours: number): void {
// 先取消旧任务
this.cancelWeatherRefresh();
// 用新间隔重新注册
try {
const workInfo: workScheduler.WorkInfo = {
workId: this.WEATHER_TASK_ID,
networkType: workScheduler.NetworkType.NETWORK_TYPE_WIFI,
isRepeat: true,
repeatInterval: intervalHours * 60 * 60 * 1000,
abilityName: this.WEATHER_TASK_NAME,
parameters: {
cityCode: '110000',
dataType: 'current_and_forecast',
},
};
workScheduler.startWork(workInfo);
console.info(`[天气刷新] 刷新间隔已更新为 ${intervalHours} 小时`);
} catch (error) {
const err = error as BusinessError;
console.error(`[天气刷新] 更新间隔失败,错误码: ${err.code}`);
}
}
/**
* 取消天气数据周期刷新
*/
cancelWeatherRefresh(): void {
try {
workScheduler.stopWork(this.WEATHER_TASK_ID);
console.info('[天气刷新] 周期任务已取消');
} catch (error) {
const err = error as BusinessError;
console.error(`[天气刷新] 取消失败,错误码: ${err.code}`);
}
}
/**
* 获取当前任务状态
*/
getTaskStatus(): string {
try {
const workInfo = workScheduler.getWorkStatusSync(this.WEATHER_TASK_ID);
if (workInfo) {
return `运行中,间隔: ${workInfo.repeatInterval / 3600000}小时`;
}
return '未注册';
} catch (error) {
return '查询失败';
}
}
}
3.2 健康检查周期任务
服务器监控、应用健康检查等场景需要定期检测服务状态:
import WorkSchedulerExtensionAbility from '@ohos.app.ability.WorkSchedulerExtensionAbility';
import workScheduler from '@ohos.resourceschedule.workScheduler';
/**
* 健康检查周期任务回调
* 每小时检查一次服务器状态,异常时发送通知提醒
*/
export default class HealthCheckWorkScheduler extends WorkSchedulerExtensionAbility {
/**
* 周期任务执行回调
* 每次调度时触发
*/
onWorkStart(workInfo: workScheduler.WorkInfo): void {
console.info('[健康检查] 开始执行周期健康检查');
const serverUrl = workInfo.parameters?.serverUrl as string || 'https://api.example.com';
const timeout = parseInt(workInfo.parameters?.timeout as string || '5000', 10);
// 执行健康检查
this.performHealthCheck(serverUrl, timeout);
}
/**
* 执行健康检查
*/
private async performHealthCheck(serverUrl: string, timeout: number): Promise<void> {
const startTime = Date.now();
try {
// 模拟HTTP健康检查请求
const isHealthy = await this.checkServerHealth(serverUrl, timeout);
const responseTime = Date.now() - startTime;
if (isHealthy) {
console.info(`[健康检查] ✅ 服务器正常,响应时间: ${responseTime}ms`);
// 检查响应时间是否异常
if (responseTime > 3000) {
console.warn(`[健康检查] ⚠️ 响应时间过长: ${responseTime}ms`);
this.sendWarningNotification('服务器响应缓慢', `响应时间: ${responseTime}ms`);
}
} else {
console.error('[健康检查] ❌ 服务器异常');
this.sendWarningNotification('服务器异常', '健康检查失败,请及时处理');
}
} catch (error) {
console.error(`[健康检查] 检查过程出错: ${error}`);
this.sendWarningNotification('健康检查出错', '无法连接到服务器');
}
}
/**
* 检查服务器健康状态
* @param url 服务器地址
* @param timeout 超时时间
* @returns 是否健康
*/
private async checkServerHealth(url: string, timeout: number): Promise<boolean> {
try {
// 模拟网络请求(实际开发中使用 @ohos.net.http)
await new Promise<void>((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error('请求超时'));
}, timeout);
// 模拟请求成功
setTimeout(() => {
clearTimeout(timer);
resolve();
}, 800); // 模拟800ms响应时间
});
return true;
} catch (error) {
return false;
}
}
/**
* 发送警告通知
*/
private sendWarningNotification(title: string, text: string): void {
try {
// 实际开发中使用 notificationManager 发布通知
console.warn(`[健康检查] 📢 通知: ${title} - ${text}`);
} catch (error) {
console.error('[健康检查] 发送通知失败');
}
}
/**
* 周期任务结束回调
*/
onWorkStop(workInfo: workScheduler.WorkInfo): void {
console.info(`[健康检查] 本轮检查结束,任务ID: ${workInfo.workId}`);
}
}
/**
* 健康检查周期任务注册器
*/
export class HealthCheckScheduler {
private readonly HEALTH_TASK_ID: number = 40002;
private readonly HEALTH_TASK_NAME: string = 'healthCheckTask';
/**
* 注册健康检查周期任务
* @param serverUrl 服务器地址
* @param intervalMinutes 检查间隔(分钟),最小20分钟
*/
register(serverUrl: string, intervalMinutes: number = 60): void {
// 确保间隔不小于最小值
const minInterval = 20;
const actualInterval = Math.max(intervalMinutes, minInterval);
try {
const workInfo: workScheduler.WorkInfo = {
workId: this.HEALTH_TASK_ID,
// 任意网络(健康检查不能只等Wi-Fi)
networkType: workScheduler.NetworkType.NETWORK_TYPE_ANY,
isRepeat: true,
repeatInterval: actualInterval * 60 * 1000,
abilityName: this.HEALTH_TASK_NAME,
parameters: {
serverUrl: serverUrl,
timeout: '5000',
},
};
workScheduler.startWork(workInfo);
console.info(`[健康检查] 周期任务注册成功,间隔: ${actualInterval}分钟`);
} catch (error) {
const err = error as BusinessError;
console.error(`[健康检查] 注册失败,错误码: ${err.code}`);
}
}
/**
* 取消健康检查
*/
cancel(): void {
try {
workScheduler.stopWork(this.HEALTH_TASK_ID);
console.info('[健康检查] 周期任务已取消');
} catch (error) {
console.error('[健康检查] 取消失败');
}
}
}
3.3 周期任务最佳实践封装
将周期任务的最佳实践封装成一个通用的管理类,涵盖注册、更新、取消、状态监控等完整功能:
import workScheduler from '@ohos.resourceschedule.workScheduler';
import { BusinessError } from '@ohos.base';
/**
* 周期任务配置
*/
export interface PeriodicTaskConfig {
/** 任务ID,全局唯一 */
taskId: number;
/** WorkSchedulerExtension 名称 */
abilityName: string;
/** 重复间隔(毫秒),最小20分钟 */
intervalMs: number;
/** 网络类型,默认不限 */
networkType?: workScheduler.NetworkType;
/** 是否需要充电,默认否 */
requireCharging?: boolean;
/** 最低电量要求,默认0 */
minBatteryLevel?: number;
/** 传递给回调的参数 */
parameters?: Record<string, string>;
}
/**
* 周期任务运行状态
*/
export interface PeriodicTaskStatus {
/** 任务ID */
taskId: number;
/** 是否已注册 */
isRegistered: boolean;
/** 重复间隔(毫秒) */
intervalMs: number;
/** 网络条件 */
networkType: string;
/** 是否需要充电 */
requireCharging: boolean;
}
/**
* 周期任务管理器
* 提供周期任务的注册、更新、取消、状态查询等完整管理功能
* 遵循最佳实践,内置参数校验和安全防护
*/
export class PeriodicTaskManager {
/** 已注册的任务配置缓存 */
private registeredTasks: Map<number, PeriodicTaskConfig> = new Map();
/** 最小重复间隔:20分钟 */
private readonly MIN_INTERVAL_MS: number = 20 * 60 * 1000;
/**
* 注册周期任务
* @param config 任务配置
* @throws 参数校验失败时抛出错误
*/
register(config: PeriodicTaskConfig): void {
// 参数校验
this.validateConfig(config);
// 如果已有同ID任务,先取消
if (this.registeredTasks.has(config.taskId)) {
console.warn(`[周期任务] 任务ID ${config.taskId} 已存在,将覆盖`);
this.cancel(config.taskId);
}
try {
const workInfo: workScheduler.WorkInfo = {
workId: config.taskId,
networkType: config.networkType ?? workScheduler.NetworkType.NETWORK_TYPE_ANY,
isCharging: config.requireCharging ?? false,
batteryLevel: config.minBatteryLevel ?? 0,
isRepeat: true,
repeatInterval: config.intervalMs,
abilityName: config.abilityName,
parameters: config.parameters || {},
};
workScheduler.startWork(workInfo);
// 缓存配置
this.registeredTasks.set(config.taskId, config);
console.info(`[周期任务] 注册成功,ID=${config.taskId},间隔=${config.intervalMs / 60000}分钟`);
} catch (error) {
const err = error as BusinessError;
console.error(`[周期任务] 注册失败,错误码: ${err.code},错误信息: ${err.message}`);
throw err;
}
}
/**
* 更新周期任务配置
* 更新间隔或条件时使用(先取消再重新注册)
* @param taskId 任务ID
* @param newInterval 新的间隔(毫秒)
*/
updateInterval(taskId: number, newInterval: number): void {
const config = this.registeredTasks.get(taskId);
if (!config) {
console.error(`[周期任务] 未找到任务ID ${taskId}`);
return;
}
// 校验新间隔
if (newInterval < this.MIN_INTERVAL_MS) {
console.error(`[周期任务] 间隔不能小于 ${this.MIN_INTERVAL_MS / 60000} 分钟`);
return;
}
// 更新配置并重新注册
config.intervalMs = newInterval;
this.register(config);
console.info(`[周期任务] 任务ID ${taskId} 间隔已更新为 ${newInterval / 60000} 分钟`);
}
/**
* 取消周期任务
* @param taskId 任务ID
*/
cancel(taskId: number): void {
try {
workScheduler.stopWork(taskId);
this.registeredTasks.delete(taskId);
console.info(`[周期任务] 任务ID ${taskId} 已取消`);
} catch (error) {
const err = error as BusinessError;
console.error(`[周期任务] 取消失败,错误码: ${err.code}`);
}
}
/**
* 取消所有周期任务
*/
cancelAll(): void {
try {
workScheduler.stopAllWorks();
this.registeredTasks.clear();
console.info('[周期任务] 所有周期任务已取消');
} catch (error) {
const err = error as BusinessError;
console.error(`[周期任务] 批量取消失败,错误码: ${err.code}`);
}
}
/**
* 获取所有周期任务的状态
*/
getAllStatus(): PeriodicTaskStatus[] {
const statusList: PeriodicTaskStatus[] = [];
this.registeredTasks.forEach((config, taskId) => {
const networkTypeNames: Record<number, string> = {
[workScheduler.NetworkType.NETWORK_TYPE_ANY]: '任意网络',
[workScheduler.NetworkType.NETWORK_TYPE_WIFI]: 'Wi-Fi',
[workScheduler.NetworkType.NETWORK_TYPE_MOBILE]: '移动网络',
};
statusList.push({
taskId: taskId,
isRegistered: true,
intervalMs: config.intervalMs,
networkType: networkTypeNames[config.networkType ?? 0] || '不限',
requireCharging: config.requireCharging ?? false,
});
});
return statusList;
}
/**
* 参数校验
* @throws 校验失败时抛出错误
*/
private validateConfig(config: PeriodicTaskConfig): void {
if (!config.taskId || config.taskId <= 0) {
throw new Error('任务ID必须为正整数');
}
if (!config.abilityName || config.abilityName.trim() === '') {
throw new Error('abilityName 不能为空');
}
if (config.intervalMs < this.MIN_INTERVAL_MS) {
throw new Error(`重复间隔不能小于 ${this.MIN_INTERVAL_MS / 60000} 分钟,当前: ${config.intervalMs / 60000} 分钟`);
}
if (config.minBatteryLevel !== undefined && (config.minBatteryLevel < 0 || config.minBatteryLevel > 100)) {
throw new Error('电量阈值必须在 0-100 之间');
}
}
}
// ============ 使用示例 ============
/**
* 演示周期任务管理器的完整使用流程
*/
function demoPeriodicTaskManager(): void {
const manager = new PeriodicTaskManager();
// 注册天气刷新周期任务
manager.register({
taskId: 50001,
abilityName: 'weatherRefreshTask',
intervalMs: 3 * 60 * 60 * 1000, // 3小时
networkType: workScheduler.NetworkType.NETWORK_TYPE_WIFI,
parameters: { cityCode: '110000' },
});
// 注册健康检查周期任务
manager.register({
taskId: 50002,
abilityName: 'healthCheckTask',
intervalMs: 60 * 60 * 1000, // 1小时
networkType: workScheduler.NetworkType.NETWORK_TYPE_ANY,
parameters: { serverUrl: 'https://api.example.com' },
});
// 注册数据同步周期任务
manager.register({
taskId: 50003,
abilityName: 'dataSyncTask',
intervalMs: 6 * 60 * 60 * 1000, // 6小时
networkType: workScheduler.NetworkType.NETWORK_TYPE_WIFI,
requireCharging: true,
minBatteryLevel: 30,
parameters: { syncScope: 'user_data' },
});
// 查看所有任务状态
const allStatus = manager.getAllStatus();
console.info(`[周期任务] 当前共 ${allStatus.length} 个周期任务:`);
allStatus.forEach(status => {
console.info(` - 任务${status.taskId}: 间隔${status.intervalMs / 60000}分钟, 网络=${status.networkType}, 充电=${status.requireCharging}`);
});
// 更新天气刷新间隔为6小时
manager.updateInterval(50001, 6 * 60 * 60 * 1000);
// 取消健康检查任务
manager.cancel(50002);
}
四、踩坑与注意事项
4.1 间隔小于20分钟会注册失败
踩坑:设置了 repeatInterval: 10 * 60 * 1000(10分钟),调用 startWork() 时直接报错。
解决方案:周期任务的最小间隔是 20 分钟,这是系统的硬性限制。如果你的需求确实需要更短的间隔,应该重新评估——也许你需要的是长时任务而不是周期任务。
4.2 周期任务不会精确按时执行
踩坑:设置了每小时执行一次,但实际执行时间经常偏移,有时甚至延迟几个小时。
解决方案:这是正常行为。周期任务的 repeatInterval 是最小间隔,不是精确间隔。系统会综合考虑电量、Doze 状态、应用待机分组等因素来决定实际执行时间。如果需要精确时间,请使用 reminderAgentManager。
4.3 周期任务必须主动取消
踩坑:应用退出后,周期任务还在继续执行,白白消耗系统资源。
解决方案:周期任务的生命周期不随应用退出而结束。在以下场景中必须主动取消:
- 用户在设置中关闭了自动刷新功能
- 应用被卸载
- 不再需要周期执行时
// 在设置变更时取消周期任务
onUserDisableAutoRefresh(): void {
manager.cancel(WEATHER_TASK_ID);
console.info('用户已关闭自动刷新,周期任务已取消');
}
4.4 不要同时注册太多周期任务
踩坑:一个应用注册了 5 个以上的周期任务,每个间隔不同,系统调度压力很大,导致所有任务都执行不及时。
解决方案:合并相似任务。比如天气刷新和新闻刷新可以合并为一个周期任务,在回调中同时处理两种数据。
// ❌ 两个独立的周期任务
manager.register({ taskId: 1, abilityName: 'weatherTask', intervalMs: HOUR_3 });
manager.register({ taskId: 2, abilityName: 'newsTask', intervalMs: HOUR_3 });
// ✅ 合并为一个周期任务
manager.register({
taskId: 1,
abilityName: 'combinedRefreshTask',
intervalMs: HOUR_3,
parameters: { tasks: 'weather,news' },
});
4.5 周期任务和延迟任务不要混用同一 workId
踩坑:先用 workId=100 注册了一个延迟任务,后来又用同一个 workId 注册了周期任务,导致延迟任务被覆盖。
解决方案:不同类型的任务使用不同的 workId 范围,避免冲突。
// workId 分段管理
const DEFERRED_TASK_ID_START = 10000; // 延迟任务ID起始
const PERIODIC_TASK_ID_START = 40000; // 周期任务ID起始
五、HarmonyOS 6 适配
5.1 API 变更
| 变更项 | HarmonyOS 5.0 | HarmonyOS 6 |
|---|---|---|
| 最小间隔 | 20 分钟 | 15 分钟(降低门槛) |
| 智能调度 | 无 | 根据用户习惯优化执行时机 |
| 执行次数限制 | 无 | 新增maxRepeatCount 参数 |
| 回调增强 | onWorkStart/onWorkStop | 新增 onWorkFailed 失败回调 |
| 电池感知 | 仅通过约束条件 | 新增自适应间隔,低电量时自动延长间隔 |
5.2 迁移指南
- 执行次数限制:6.0 新增了
maxRepeatCount参数,可以限制周期任务的最大重复次数,避免无限执行:
// HarmonyOS 6 新增:限制最大重复次数
const workInfo: workScheduler.WorkInfo = {
workId: taskId,
isRepeat: true,
repeatInterval: 60 * 60 * 1000,
maxRepeatCount: 24, // 最多重复24次(即1天)
abilityName: 'dataRefreshTask',
};
- 自适应间隔:6.0 的 workScheduler 支持自适应间隔功能。当设备电量较低时,系统会自动延长周期任务的执行间隔,无需手动调整:
// HarmonyOS 6 新增:启用自适应间隔
const workInfo: workScheduler.WorkInfo = {
workId: taskId,
isRepeat: true,
repeatInterval: 60 * 60 * 1000,
// 启用自适应间隔,低电量时自动延长
isAdaptiveInterval: true,
abilityName: 'dataRefreshTask',
};
- 最小间隔降低:6.0 将最小间隔从 20 分钟降低到 15 分钟,对于需要更频繁更新的场景(如即时通讯消息拉取),可以设置更短的间隔。
六、总结
核心知识点回顾
周期任务(Periodic Task)
├── 核心配置
│ ├── isRepeat: true → 标记为周期任务
│ ├── repeatInterval → 重复间隔(≥20分钟)
│ └── 其他约束条件(网络/充电/电量)
│
├── 与延迟任务对比
│ ├── 延迟任务 → 一次性 + 条件触发
│ ├── 周期任务 → 重复性 + 间隔触发
│ └── 同一模块 workScheduler,参数不同
│
├── 间隔配置
│ ├── 最小间隔:20分钟(6.0为15分钟)
│ ├── 推荐间隔:1-6小时
│ └── 不保证精确执行时间
│
├── 最佳实践
│ ├── 合并相似任务,减少注册数量
│ ├── 主动取消不再需要的任务
│ ├── workId 与延迟任务分段管理
│ └── 参数校验 + 配置缓存
│
├── 常见陷阱
│ ├── 间隔小于20分钟 → 注册失败
│ ├── 不主动取消 → 无限执行
│ ├── 注册太多任务 → 调度压力
│ └── workId冲突 → 任务覆盖
│
└── HarmonyOS 6 增强
├── 最小间隔降低到15分钟
├── 新增 maxRepeatCount 限制
├── 新增自适应间隔
└── 新增 onWorkFailed 回调
一句话总结:周期任务是"定时闹钟"式的后台任务——设好间隔和条件,系统定期帮你执行。记住"间隔不低于20分钟、用完主动取消、合并相似任务"这三条铁律,周期任务就能用得又稳又省。
- 点赞
- 收藏
- 关注作者
评论(0)