Android 中的定時任務排程

PhxNirvana發表於2019-03-04

在近期的應用開發中,非同步執行任務是很流行的,而且這些任務經常在應用的生命週期之外執行,如下載資料或更新網路資源。有些情況下我們還需要做一些並不是馬上需要執行的工作。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) 上提供。

感謝閱讀。如果感覺有用,還請輕點❤來推薦文章給更多人。

關注接下來的文章。有任何意見和建議請通過下面的渠道聯絡我們: TwitterGoogle+LinkedIn

進入我的 部落格 獲取更多有趣的開發話題。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃

相關文章