一、概述
1.1 功能介紹
應用退至後台後,需要執行實時性要求不高的任務,例如有網絡時不定期主動獲取郵件等,可以使用延遲任務。當應用滿足設定的觸發條件(包括網絡類型、充電類型、存儲狀態、電池狀態、定時狀態等)時,將任務添加到執行隊列,系統會根據內存、功耗、設備温度、用户使用習慣等統一調度拉起應用。
1.2 運行原理
圖1 延遲任務實現原理
應用調用延遲任務接口添加、刪除、查詢延遲任務,延遲任務管理模塊會根據任務設置的條件(通過WorkInfo參數設置,包括網絡類型、充電類型、存儲狀態等)和系統狀態(包括內存、功耗、設備温度、用户使用習慣等)統一決策調度時機。
當滿足調度條件或調度結束時,系統會回調應用WorkSchedulerExtensionAbility中 onWorkStart() 或 onWorkStop() 的方法,同時會為應用單獨創建一個Extension擴展進程用以承載WorkSchedulerExtensionAbility,並給WorkSchedulerExtensionAbility一定的活動週期,開發者可以在對應回調方法中實現自己的任務邏輯。
1.3 約束與限制
- 數量限制:一個應用同一時刻最多申請10個延遲任務。
- 執行頻率限制:系統會根據應用的活躍分組,對延遲任務做分級管控,限制延遲任務調度的執行頻率。
表1 應用活躍程度分組
|
應用活躍分組
|
延遲任務執行頻率
|
|
活躍分組
|
最小間隔2小時
|
|
經常使用分組
|
最小間隔4小時
|
|
常用分組
|
最小間隔24小時
|
|
極少使用分組
|
最小間隔48小時
|
|
受限使用分組
|
禁止
|
|
從未使用分組
|
禁止
|
- 超時:WorkSchedulerExtensionAbility單次回調最長運行2分鐘。如果超時不取消,系統會終止對應的Extension進程。
- 調度延遲:系統會根據內存、功耗、設備温度、用户使用習慣等統一調度,如當系統內存資源不足或温度達到一定擋位時,系統將延遲調度該任務。
- WorkSchedulerExtensionAbility接口調用限制:為實現對WorkSchedulerExtensionAbility能力的管控,在WorkSchedulerExtensionAbility中限制以下接口的調用: @ohos.resourceschedule.backgroundTaskManager (後台任務管理) @ohos.backgroundTaskManager (後台任務管理) @ohos.multimedia.camera (相機管理) @ohos.multimedia.audio (音頻管理) @ohos.multimedia.media (媒體服務)
二、接口説明
表2 延遲任務主要接口
以下是延遲任務開發使用的相關接口
|
接口名
|
接口描述
|
|
startWork(work: WorkInfo): void;
|
申請延遲任務
|
|
stopWork(work: WorkInfo, needCancel?: boolean): void;
|
取消延遲任務
|
|
getWorkStatus(workId: number, callback: AsyncCallback\): void;
|
獲取延遲任務狀態(Callback形式)
|
|
getWorkStatus(workId: number): Promise; 獲取延遲任務狀態(Promise形式)
|
|
|
obtainAllWorks(callback: AsyncCallback<Array\>): void;
|
獲取所有延遲任務(Callback形式)
|
|
obtainAllWorks(): Promise<Array\>;
|
獲取所有延遲任務(Promise形式)
|
|
stopAndClearWorks(): void;
|
停止並清除任務
|
|
isLastWorkTimeOut(workId: number, callback: AsyncCallback): void;
|
獲取上次任務是否超時(針對RepeatWork,Callback形式)
|
|
isLastWorkTimeOut(workId: number): Promise;
|
獲取上次任務是否超時(針對RepeatWork,Promise形式)
|
表3 WorkInfo參數
|
名稱
|
類型
|
只讀
|
可選
|
説明
|
|
workId
|
number
|
否
|
否
|
延遲任務ID。
|
|
bundleName
|
string
|
否
|
否
|
延遲任務所在應用的包名。
|
|
abilityName
|
string
|
否
|
否
|
包內ability名稱。
|
|
networkType
|
NetworkType
|
否
|
是
|
網絡類型。
|
|
isCharging
|
boolean
|
否
|
是
|
是否充電。
- true表示充電觸發延遲任務回調。
- false表示不充電觸發延遲任務回調。
|
|
chargerType
|
ChargingType
|
否
|
是
|
充電類型。
|
|
batteryLevel
|
number
|
否
|
是
|
電量。
|
|
batteryStatus
|
BatteryStatus
|
否
|
是
|
電池狀態。
|
|
storageRequest
|
StorageRequest
|
否
|
是
|
存儲狀態。
|
|
isRepeat
|
boolean
|
否
|
是
|
是否循環任務。
- true表示循環任務。
- false表示非循環任務。
|
|
repeatCycleTime
|
number
|
否
|
是
|
循環間隔,單位為毫秒。
|
|
repeatCount
|
number
|
否
|
是
|
循環次數。
|
|
isPersisted
|
boolean
|
否
|
是
|
註冊的延遲任務是否可保存在系統中。
- true表示可保存,即系統重啓後,任務可恢復。
- false表示不可保存。
|
|
isDeepIdle
|
boolean
|
否
|
是
|
是否要求設備進入空閒狀態。
- true表示需要。
- false表示不需要。
|
|
idleWaitTime
|
number
|
否
|
是
|
空閒等待時間,單位為毫秒。
|
|
parameters
|
\[key: string]: number | string | boolean
|
否
|
是
|
攜帶參數信息。
|
WorkInfo參數用於設置延遲任務的觸發條件,參數設置時需遵循以下規則:
- workId、bundleName、abilityName為必填項,bundleName需為本應用包名。
- 攜帶參數信息僅支持number、string、boolean三種類型。
- 至少設置一個滿足的條件,包括網絡類型、充電類型、存儲狀態、電池狀態、定時狀態等。
- 對於重複任務,任務執行間隔至少2小時。設置重複任務時間間隔時,須同時設置是否循環或循環次數中的一個。
表4 延遲任務回調接口
以下是延遲任務回調開發使用的相關接口,更多接口及使用方式請見延遲任務調度回調文檔。
|
接口名
|
接口描述
|
|
onWorkStart(work: workScheduler.WorkInfo): void
|
延遲調度任務開始的回調
|
|
onWorkStop(work: workScheduler.WorkInfo): void
|
延遲調度任務結束的回調
|
三、開發步驟
延遲任務調度開發步驟分為兩步:實現延遲任務調度擴展能力、實現延遲任務調度。
- 延遲任務調度擴展能力:實現WorkSchedulerExtensionAbility開始和結束的回調接口。
- 延遲任務調度:調用延遲任務接口,實現延遲任務申請、取消等功能。
3.1 實現延遲任務回調擴展能力
- 新建工程目錄。 在工程entry Module對應的ets目錄(./entry/src/main/ets)下,新建目錄及ArkTS文件,例如新建一個目錄並命名為WorkSchedulerExtension。在WorkSchedulerExtension目錄下,新建一個ArkTS文件並命名為WorkSchedulerExtension.ets,用以實現延遲任務回調接口。
- 導入模塊。
import { WorkSchedulerExtensionAbility, workScheduler } from '@kit.BackgroundTasksKit';
- 實現WorkSchedulerExtension生命週期接口。
export default class MyWorkSchedulerExtensionAbility extends WorkSchedulerExtensionAbility {
// 延遲任務開始回調
onWorkStart(workInfo: workScheduler.WorkInfo) {
console.info(`onWorkStart, workInfo = ${JSON.stringify(workInfo)}`);
// 打印 parameters中的參數,如:參數key1
// console.info(`work info parameters: ${JSON.parse(workInfo.parameters?.toString()).key1}`)
}
// 延遲任務結束回調。當延遲任務2分鐘超時或應用調用stopWork接口取消任務時,觸發該回調。
onWorkStop(workInfo: workScheduler.WorkInfo) {
console.info(`onWorkStop, workInfo is ${JSON.stringify(workInfo)}`);
}
}
- 在module.json5配置文件中註冊WorkSchedulerExtensionAbility,並設置如下標籤:
- type標籤設置為“workScheduler”。
- srcEntry標籤設置為當前ExtensionAbility組件所對應的代碼路徑。
{
"module": {
"extensionAbilities": [
{
"name": "MyWorkSchedulerExtensionAbility",
"srcEntry": "./ets/WorkSchedulerExtension/WorkSchedulerExtension.ets",
"type": "workScheduler"
}
]
}
}
3.2 實現延遲任務調度
示例效果圖
示例完整代碼WorkSchedulerExtension.ets
import { workScheduler, WorkSchedulerExtensionAbility } from '@kit.BackgroundTasksKit';
import { BusinessError } from '@kit.BasicServicesKit';
const TAG = "MyWorkSchedulerExtensionAbility"
export default class MyWorkSchedulerExtensionAbility extends WorkSchedulerExtensionAbility {
// 延遲任務開始回調
onWorkStart(workInfo: workScheduler.WorkInfo) {
console.info(`${TAG} onWorkStart 回調, workInfo = ${JSON.stringify(workInfo)}`);
// 打印 parameters中的參數,如:參數key1
// console.info(`work info parameters: ${JSON.parse(workInfo.parameters?.toString()).key1}`)
}
// 延遲任務結束回調。當延遲任務2分鐘超時或應用調用stopWork接口取消任務時,觸發該回調。
onWorkStop(workInfo: workScheduler.WorkInfo) {
console.info(`${TAG} onWorkStop 回調, workInfo is ${JSON.stringify(workInfo)}`);
}
/**
* 申請延遲任務。
*/
startWorkScheduler() {
// 創建workinfo
const workInfo: workScheduler.WorkInfo = {
workId: 1,
networkType: workScheduler.NetworkType.NETWORK_TYPE_WIFI,
bundleName: 'com.learn.learnharmonyos',
abilityName: 'MyWorkSchedulerExtensionAbility'
}
try {
workScheduler.startWork(workInfo);
console.info(`${TAG} 執行 startWorkScheduler startWork success`);
} catch (error) {
console.error(`TAG} 執行 startWorkScheduler startWork failed. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);
}
}
/**
* 取消延遲任務。
*/
stopWorkScheduler() {
// 創建workinfo
const workInfo: workScheduler.WorkInfo = {
workId: 1,
networkType: workScheduler.NetworkType.NETWORK_TYPE_WIFI,
bundleName: 'com.example.application',
abilityName: 'MyWorkSchedulerExtensionAbility'
}
try {
workScheduler.stopWork(workInfo);
console.info(`stopWork success`);
} catch (error) {
console.error(`stopWork failed. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);
}
}
}
TestBackgroundTasksKit4.ets
import MyWorkSchedulerExtensionAbility from '../../workSchedulerExtension/WorkSchedulerExtension'
@Entry
@Component
struct TestBackgroundTasksKit4 {
myWorkSchedulerExtensionAbility: MyWorkSchedulerExtensionAbility = new MyWorkSchedulerExtensionAbility()
build() {
Column({space: 20}) {
Button('申請延遲任務')
.fontColor(Color.Black)
.fontSize(20)
.margin({top: 10})
.onClick(() => {
this.myWorkSchedulerExtensionAbility.startWorkScheduler()
})
Button('取消延遲任務')
.fontColor(Color.Black)
.margin({top: 10})
.fontSize(20)
.onClick(() => {
this.myWorkSchedulerExtensionAbility.stopWorkScheduler()
})
}
.height('100%')
.width('100%')
}
}
3.3 延遲任務調度功能驗證
確認延遲任務WorkSchedulerExtensionAbility回調方法onWorkStart、onWorkStop實現是否正確、是否可以成功回調
延遲任務申請成功之後,需要等到條件滿足後才可以執行延遲任務回調,為了快速驗證延遲任務回調功能是否正確,可以通過以下hidumper命令手動觸發延遲任務執行回調。
$ hidumper -s 1904 -a '-t com.example.application MyWorkSchedulerExtensionAbility'
-------------------------------[ability]-------------------------------
----------------------------------WorkSchedule----------------------------------
提醒 需要先配置hidumper系統環境變量