Android 工作排程器
本指南討論如何使用 Android 作業排程器 API 排程背景工作,此 API 適用於執行 Android 5.0 (API 層級 21) 和更新版本的 Android 裝置。
概觀
讓Android應用程式對使用者保持回應的最佳方式之一,是確保背景中執行複雜或長時間執行的工作。 不過,背景工作不會對使用者使用裝置的體驗造成負面影響。
例如,背景作業可能會每隔三到四分鐘輪詢網站,以查詢特定數據集的變更。 這似乎是良性的,但它會對電池使用時間產生災難性的影響。 應用程式會重複喚醒裝置、將CPU提升至較高的電源狀態、啟動無線電、提出網路要求,然後處理結果。 情況變得更糟,因為裝置不會立即關閉電源,並返回低功率閑置狀態。 排程不佳的背景工作可能會不小心讓裝置處於不必要和過度電源需求的狀態。 這種看似無辜的活動(輪詢網站)將使裝置在相對短時間內無法使用。
Android 提供下列 API 來協助在背景中執行工作,但本身不足以進行智慧型手機工作排程。
- 意圖服務 – 意圖服務 非常適合執行工作,但無法排程工作。
- AlarmManager – 這些 API 只允許排程工作,但無法實際執行工作。 此外,AlarmManager 只允許以時間為基礎的條件約束,這表示在特定時間或經過一段時間之後引發警示。
- 廣播接收者 – Android 應用程式可以設定廣播接收者,以執行工作以回應全系統事件或意圖。 不過,廣播接收器不會提供應該執行作業時的任何控制權。 Android 作業系統中的變更也會限制廣播接收者何時能夠運作,或可回應的工作種類。
有兩個主要功能可以有效率地執行背景工作(有時稱為背景工作或工作):
- 以智慧方式排程工作 – 當應用程式在背景中執行做為良好公民的工作時,這一點很重要。 在理想情況下,應用程式不應該要求執行作業。 相反地,應用程式應該指定在作業可以執行時必須符合的條件,然後使用符合條件時執行工作的作業系統排程該作業。 這可讓Android執行作業,以確保裝置上的最大效率。 例如,網路要求可能會批處理以同時執行,以充分利用與網路相關的額外負荷。
- 封裝工作 – 執行背景工作 的程式代碼應該封裝在獨立於使用者介面獨立執行的離散元件中,如果工作因為某些原因而無法完成,則比較容易重新排程。
Android 作業排程器是 Android 作業系統內建的架構,可提供 Fluent API 來簡化排程背景工作。 Android 作業排程器包含下列型態:
Android.App.Job.JobScheduler
是系統服務,用來代表Android應用程式排程、執行及在必要時取消作業。Android.App.Job.JobService
是一個抽象類,必須使用將在應用程式主線程上執行作業的邏輯來擴充。 這表示JobService
負責如何以異步方式執行工作。Android.App.Job.JobInfo
物件會保存準則,以在作業應該執行時引導 Android。
若要排程使用 Android 作業排程器,Xamarin.Android 應用程式必須將程式代碼封裝在擴充 JobService
類別的類別中。 JobService
有三種生命週期方法,可在作業存留期期間呼叫:
bool OnStartJob(JobParameters 參數) – 這個方法是由
JobScheduler
呼叫來執行工作,並在應用程式的主要線程上執行。 負責JobService
異步執行工作,並在剩餘工作時傳回true
;如果工作已完成,false
則為 。JobScheduler
當呼叫此方法時,它會在作業期間要求並保留Android的喚醒鎖定。 當作業完成時,呼叫JobService
方法會負責告訴JobScheduler
這個事實JobFinished
(如下所述)。JobFinished(JobParameters 參數、bool 需要Reschedule) – 這個方法必須由 呼叫
JobService
,才能告知JobScheduler
已完成工作。 如果未JobFinished
呼叫 ,JobScheduler
將不會移除喚醒鎖,造成不必要的電池耗盡。bool OnStopJob(JobParameters 參數) – 當 Android 過早停止作業時,就會呼叫此專案。 如果應該根據重試準則重新排程作業,則應該傳回
true
此作業(如下所述更詳細地討論)。
您可以指定 限制 式或 觸發 程式,以控制作業何時可以或應該執行。 例如,可以限制工作,使其只有在裝置充電或拍攝圖片時啟動工作才會執行。
本指南將詳細討論如何實 JobService
作 類別,並使用 來排程類別 JobScheduler
。
需求
Android 作業排程器需要 Android API 層級 21 (Android 5.0) 或更高版本。
使用Android作業排程器
使用 Android JobScheduler API 有三個步驟:
- 實作JobService類型以封裝工作。
JobInfo.Builder
使用物件來建立JobInfo
物件,該物件會保存 要執行作業的準則JobScheduler
。- 使用
JobScheduler.Schedule
排程作業。
實作 JobService
Android 作業排程器連結庫所執行的所有工作,都必須在擴充 Android.App.Job.JobService
抽象類的類型中完成。 JobService
建立 與使用 Android 架構建立 Service
非常類似:
- 擴充 類別
JobService
。 - 使用 裝飾子類別
ServiceAttribute
,並將 參數設定Name
為由封裝名稱和類別名稱組成的字串(請參閱下列範例)。 - 將
Permission
屬性ServiceAttribute
設定為字串android.permission.BIND_JOB_SERVICE
。 OnStartJob
覆寫 方法,新增程式代碼以執行工作。 Android 會在應用程式的主要線程上叫用這個方法,以執行作業。 應該在線程上執行幾毫秒的時間較長的工作,以避免封鎖應用程式。- 當工作完成時,
JobService
必須呼叫JobFinished
方法。 這個方法是如何JobService
告知JobScheduler
已完成工作。JobFinished
呼叫失敗會導致JobService
對裝置產生不必要的要求,縮短電池使用時間。 - 最好也覆寫
OnStopJob
方法。 在作業完成之前關閉作業時,Android 會呼叫這個方法,並提供JobService
適當處置任何資源的機會。 如果需要重新排程作業,或false
不需要重新執行作業,這個方法應該會傳回true
。
下列程式代碼是應用程式最簡單的 JobService
範例,使用 TPL 以異步方式執行某些工作:
[Service(Name = "com.xamarin.samples.downloadscheduler.DownloadJob",
Permission = "android.permission.BIND_JOB_SERVICE")]
public class DownloadJob : JobService
{
public override bool OnStartJob(JobParameters jobParams)
{
Task.Run(() =>
{
// Work is happening asynchronously
// Have to tell the JobScheduler the work is done.
JobFinished(jobParams, false);
});
// Return true because of the asynchronous work
return true;
}
public override bool OnStopJob(JobParameters jobParams)
{
// we don't want to reschedule the job if it is stopped or cancelled.
return false;
}
}
建立 JobInfo 以排程作業
Xamarin.Android 應用程式不會直接具現化 JobService
,而是會將 對象傳遞 JobInfo
至 JobScheduler
。 會JobScheduler
根據中的JobInfo
元數據,具現化要求的 JobService
物件、排程和執行 JobService
。 JobInfo
物件必須包含下列資訊:
- JobId – 這是
int
用來識別 作業給JobScheduler
的值。 重複使用此值將會更新任何現有的作業。 此值對應用程式而言必須是唯一的。 - JobService – 這個參數
ComponentName
明確識別應該用來執行作業的類型JobScheduler
。
此擴充方法示範如何使用AndroidContext
建立 JobInfo.Builder
,例如Activity:
public static class JobSchedulerHelpers
{
public static JobInfo.Builder CreateJobBuilderUsingJobId<T>(this Context context, int jobId) where T:JobService
{
var javaClass = Java.Lang.Class.FromType(typeof(T));
var componentName = new ComponentName(context, javaClass);
return new JobInfo.Builder(jobId, componentName);
}
}
// Sample usage - creates a JobBuilder for a DownloadJob and sets the Job ID to 1.
var jobBuilder = this.CreateJobBuilderUsingJobId<DownloadJob>(1);
var jobInfo = jobBuilder.Build(); // creates a JobInfo object.
Android 作業排程器的強大功能是控制作業執行的時間或作業執行狀況的能力。 下表描述一些 JobInfo.Builder
方法,可讓應用程式在作業執行時影響:
方法 | 描述 |
---|---|
SetMinimumLatency |
指定執行作業之前應該觀察到的延遲 (以毫秒為單位)。 |
SetOverridingDeadline |
宣告作業必須在此時間之前執行 (以毫秒為單位) 已過去。 |
SetRequiredNetworkType |
指定作業的網路需求。 |
SetRequiresBatteryNotLow |
只有在裝置未向用戶顯示「低電池」警告時,才能執行作業。 |
SetRequiresCharging |
工作只能在電池充電時執行。 |
SetDeviceIdle |
當裝置忙碌時,作業將會執行。 |
SetPeriodic |
指定應該定期執行作業。 |
SetPersisted |
作業應該會在裝置重新啟動時進行排程。 |
提供 SetBackoffCriteria
一些指引,說明在嘗試再次執行作業之前應該等候的時間 JobScheduler
長度。 輪詢準則有兩個部分:延遲毫秒(預設值為30秒),以及應該使用的退退類型(有時稱為 輪詢原則 或 重試原則)。 這兩個原則會封裝在列舉中 Android.App.Job.BackoffPolicy
:
BackoffPolicy.Exponential
– 指數輪詢原則會在每次失敗后以指數方式增加初始輪詢值。 作業第一次失敗時,連結庫會等候指定的初始間隔,再重新排程作業 – 範例 30 秒。 作業第二次失敗時,連結庫會等候至少 60 秒,再嘗試執行作業。 第三次嘗試失敗之後,連結庫會等候 120 秒,依此等。 這是預設值。BackoffPolicy.Linear
– 此策略是線性輪詢,工作應重新排程為在設定間隔執行(直到成功為止)。 線性輪詢最適合必須儘快完成的工作,或快速解決自己的問題。
如需建立 JobInfo
對象的詳細資訊,請參閱 Google 的 JobInfo.Builder
類別檔。
透過 JobInfo 將參數傳遞至作業
參數會藉由建立 PersistableBundle
與 Job.Builder.SetExtras
方法一起傳遞的 來傳遞至作業:
var jobParameters = new PersistableBundle();
jobParameters.PutInt("LoopCount", 11);
var jobBuilder = this.CreateJobBuilderUsingJobId<DownloadJob>(1)
.SetExtras(jobParameters)
.Build();
PersistableBundle
從 Android.App.Job.JobParameters.Extras
的 方法JobService
中的 OnStartJob
屬性存取 。
public override bool OnStartJob(JobParameters jobParameters)
{
var loopCount = jobParams.Extras.GetInt("LoopCount", 10);
// rest of code omitted
}
排程工作
若要排程作業,Xamarin.Android 應用程式會取得系統服務的參考 JobScheduler
,並使用在上一個步驟中建立的物件呼叫 JobScheduler.Schedule
方法 JobInfo
。 JobScheduler.Schedule
會立即傳回兩個整數值的其中一個:
- JobScheduler.ResultSuccess – 作業已成功排程。
- JobScheduler.ResultFailure – 無法排程作業。 這通常是由衝突
JobInfo
的參數所造成。
此程式代碼是排程作業並通知使用者排程嘗試結果的範例:
var jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
var scheduleResult = jobScheduler.Schedule(jobInfo);
if (JobScheduler.ResultSuccess == scheduleResult)
{
var snackBar = Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_success, Snackbar.LengthShort);
snackBar.Show();
}
else
{
var snackBar = Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_failure, Snackbar.LengthShort);
snackBar.Show();
}
取消作業
您可以使用 方法或 JobScheduler.Cancel(jobId)
方法,取消所有已排程的作業,或只取消JobsScheduler.CancelAll()
單一作業:
// Cancel all jobs
jobScheduler.CancelAll();
// to cancel a job with jobID = 1
jobScheduler.Cancel(1)
摘要
本指南討論了如何使用Android作業排程器,在背景中以智慧方式執行工作。 它討論了如何將要執行的工作封裝為 , JobService
以及如何使用 JobScheduler
來排程該工作、使用 指定準則 JobTrigger
以及應該 RetryStrategy
如何處理失敗。