[技術分享] Android 中的定時任務調度

 作者:新投云  發布于:2017-07-06  瀏覽數:

在近期的應用開發中,異步執行任務是很流行的,而且這些任務經常在應用的生命周期之外運行,如下載數據或更新網絡資源。有些情況下我們還需要做一些并不是馬上需要執行的工作。Android 提供了一些 API 來幫助我們在應用中調度這些任務。

選擇合適調度器可以提升應用的性能并且延長電池使用時間。

Android M 還引入了 打盹模式(Doze mode) 來減少用戶在短期內不使用設備時的電池消耗。

Android 中可以使用的調度器有以下幾種:

  • Alarm Manager
  • Job Scheduler
  • GCM Network Manager
  • Firebase Job Dispatcher
  • Sync Adapter

Services 的問題

Services 允許應用在后臺執行長時間的操作, 但這一行為是十分耗電的。

當持續使用設備資源卻沒有有效任務在執行時,service 便更加有害了。當那些后臺服務在監聽不同系統廣播時(比如 CONNECTIVITY_CHANGE 或者 NEW_PICTURE 等),問題的嚴重性還會提升。

在應用的生命周期之內調度任務

當應用正在運行時,如果我們想在特定時間執行任務的話,推薦使用 Handler 結合 Timer 和 Thread,而不是使用 Alarm Manger, Job Scheduler 等。使用 Handler 更簡單高效。

在應用的生命周期之外調度任務

Alarm Manager

AlarmManager 提供系統級的定時服務。正因此,也是一種在應用生命周期之外執行操作的方法。即使應用沒有運行,也可以觸發事件或動作。AlarmManager 可以在未來喚起服務。當達到預定時間時,觸發特定的 PendingIntent。

注冊過的定時任務會在設備休眠時保留(并且可以選擇是否喚醒設備),但在關機和重啟時會被清空。

“我們應該只在執行特定時間的任務時使用 AlarmManager API。這并不是一個用來粗暴檢查諸如設備空閑、網絡狀況或充電情況的方法。”

用例:假設我們想在一小時后執行任務或每隔一小時執行一次任務, AlarmManager 是完美選擇。但這 API 并不適合執行特定條件的任務,如網絡好或不充電時執行任務這種情況。

Job Scheduler

這是所有提過的調度器中最主要的一個,它可以高效地執行后臺任務。 JobScheduler API 是在 Android 5.0(API level 21) 引入的

該 API 可以在資源充足時或滿足條件時批量執行任務。創建任務時可以定義執行的先決條件。當條件滿足時,系統會在應用的 JobService 上執行任務。 JobScheduler 的執行也取決于系統的打盹模式和應用當前狀態。

批量執行的特性使得設備可以更快地進入休眠,并擁有更長的休眠期,以此來延長電池使用時間。總而言之,這個 API 可以用來執行任何對時間不敏感的計劃。

GCM Network Manager

GCM (Google Cloud Messaging) Network Manager 有著 JobScheduler 的全部特性,GCM Network Manager 也用在重復的或一次性的,不緊急的任務上來延長電量。

這個 API 是向下兼容的,支持 Android 5.0 (API level 21) 以下。從 API level 23 開始,GCM Network Manager 使用 Android 框架的 JobScheduler。GCM Network Manager 使用 Google Play 服務 內置的調度器,所以這個類 只會在安裝了 Google Play 服務 的設備上運行。

Google 強烈建議 GCM 的用戶升級到 FCM 并使用 Firebase Job Dispatcher 執行任務調度。

Firebase Job Dispatcher

Firebase JobDispatcher 也是一個后臺任務調度庫。該庫也被用來向下支持(低于 API level 21)并且支持所有近期 Android 設備(API level 9+)。

這個庫也可以在沒有安裝 Google play 服務的設備,卻仍想調度任務的應用上使用。這時,庫內部的實現是 AlarmManager。如果設備上有 Google Play 服務,則會使用 Google Play 服務內置的調度器。

提示: 當 Google Play 服務不可用時,會使用 AlarmManager 來支持 API level <= 21

如果設備是 API level 21 的話,則使用 JobScheduler。這個庫的框架是相同的,所以沒有什么功能改變。

Sync Adapter

Sync adapter 是被特別設計用來同步設備和云端數據的。它的用途也只限定在這方面。同步可以在云端或客戶端數據有改變時觸發,也可以通過時間差或設定每日一次。Android 系統會試圖執行批量同步來節省電量,無法同步的將會被放到隊列中稍后執行。系統只在聯網時會嘗試執行同步。

不管什么情況,都建議使用 Google 提供的 JobScheduler、Firebase JobDispatcher、或 GCM Network Manager。

在 Android N (API level 24)中,SyncManager 在 JobScheduler (任務)的頂端。如果需要 SyncAdapter 提供的額外功能的話,建議只使用 SyncAdapter。

練習

我們已經討論了一堆理論性的東西,下面來看看如何使用 Android job scheduler。

1. 建立 Job Service

建立 JobSchedulerService 并繼承 JobService 類,需要重寫下面兩個方法:onStartJob(JobParameters params) 和 onStopJob(JobParameters params)

public class JobSchedulerService extends JobService {

@Override

public boolean onStartJob(JobParameters params) {

return false;

}

@Override

public boolean onStopJob(JobParameters params) {

return false;

}

}

onStartJob(JobParameters params) 方法在 JobScheduler 決定執行任務時調用。JobService 在主線程工作,所以任何耗時操作都應該在另外的線程執行。onStopJob(JobParameters params) 在任務還沒執行完(調用 jobFinished(JobParameters, boolean) 之前),但系統決定停止執行時調用。

還需要在 AndroidManifest 中注冊 job service





2. 創建 JobInfo 對象

建立 JobInfo 對象需要將 JobService 傳遞到 JobInfo.Builder() 中,如下所示。這個 job builder 允許設置不同選項來控制任務的執行。

ComponentName serviceName = new ComponentName(context, JobSchedulerService.class);

JobInfo jobInfo = new JobInfo.Builder(JOB_ID, serviceName)

.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)

.setRequiresDeviceIdle(true)

.setRequiresCharging(true)

.build();

3. 調度任務

現在有了 JobInfo 和 JobService ,所以是時候來調度任務了。 用 JobInfo 調度任務時只需要執行如下代碼即可:

JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

int result = scheduler.schedule(jobInfo);

if (result == JobScheduler.RESULT_SUCCESS) {

Log.d(TAG, “Job scheduled successfully!”);

}

可以在 GitHub 下載 JobSchedulerExample 的源碼

總結

當調度任務時,需要仔細考慮執行的時間和條件,以及出錯的后果。需要在應用性能和其他電池之類的條件間取舍。

JobScheduler 容易實現,并且處理了大多數的復雜情況。當使用 JobScheduler 時,即使系統重啟我們的任務依舊可以執行下去。此刻,JobScheduler 唯一的缺點就是它最低只在 api level 21 (Android 5.0) 上提供。

相關文章

三期必中一期平特肖