背景
公司自己寫的數據分析,額…希望每半小時上報一次。之前是用的Service,但在Android文檔關於內存優化部分提到使用完Service後要將其停止,像這種週期性任務功能上來說是肯定不能停的。而Jetpack剛剛好提供了後臺任務WorkManager,試着用它實現下。
WorkManager 簡介
先看它的使用場景
- 向後端服務發送日誌或分析數據
- 定期將應用數據與服務器同步
這個的使用場景與我的需求完全契合。
WorkManager使用
- 添加依賴
提示:可能會報以下錯誤def work_version = "2.3.1" implementation "androidx.work:work-runtime-ktx:$work_version"
需要在gradle中加入下面代碼:Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target
android{ compileOptions { sourceCompatibility = '1.8' targetCompatibility = '1.8' } kotlinOptions { jvmTarget = "1.8" } }
- 編寫後臺功能
要使用WorkerManager管理後臺任務需要繼承 Worker 並在 doWork() 中編寫我們自己的後臺處理邏輯:
在後臺邏輯中我們可以編寫自己要執行的代碼,並可以根據實際情況返回Result.success() 或 Result.failure()class ReportWorker(val context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { override fun doWork(): Result { // TODO 後臺邏輯 return Result.success() } }
- 啓動Worker
啓動Worker非常簡單,只需要創建一個Worker,把它加入到WorkManager的執行隊列中就可以了。// 一次性任務 // val reportRequest = OneTimeWorkRequestBuilder<ReportWorker>().build() // 週期性任務 val reportRequest = PeriodicWorkRequestBuilder<ReportWorker>(30, TimeUnit.MINUTES).build() WorkManager.getInstance().enqueue(reportRequest)
WorkManager高級用法
-
添加Worker的約束條件
有時我們的後臺任務需要連接網絡下執行,儘管我們在doWork()可以進行判斷,但WorkerManager爲我們提供了更便捷的方式:通過在創建Worker時添加 Constraints 來爲後臺任務添加執行時的約束條件。val constraints = Constraints.Builder() .setRequiresCharging(true) .setRequiredNetworkType(NetworkType.CONNECTED) .build() val reportRequest = PeriodicWorkRequestBuilder<ReportWorker>(30, TimeUnit.MINUTES) .setConstraints(constraints) .build() WorkManager.getInstance().enqueue(reportRequest)
Constraints爲我們提供了很多約束條件,例如:網絡狀態、電量是否充足、存儲空間是否充足等
-
Worker 取消
Worker的取消非常簡單,可以直接使用 WorkManager.cancelWorkById(UUID) 來實現,而在我們創建Worker時每個Worker都會有一個UUID。
如果我們爲Woker設置了tag,也可以通過 WorkManager.cancelAllWorkByTag(String) 來取消Worker -
唯一任務
Worker如果不手動取消那麼它並不會隨應用的退出而自動終止,這樣當我們再次進入App執行到創建Worker的代碼時就會再次創建一個Worker。這種情況對於OneTimeWorkRequest是沒有什麼影響的,但對於PeriodicWorkRequest 會出現越來越多的Worker在WorkerManager中執行。本來半小時執行一次的任務可能因此執行了多次。當然我們可以在創建Worker前cancel掉上一個Worker,但這樣就不能保證切換過程中的執行週期。爲解決這個問題,我們需要使用enqueueUniqueWork來向WorkerManger中添加我們的WorkerWorkManager.getInstance().enqueueUniquePeriodicWork("uniqueWorkName", ExistingPeriodicWorkPolicy.KEEP,reportRequest)
其中:
"uniqueWorkName" 爲唯一名稱,該名稱是後面添加策略的判斷標準,注意它與tag意義不同;
KEEP 表示保持原有的Worker,忽略新創建的;除了KEEP,還可以使用 REPLACE 表示使用新的替換舊的。