許多APP都需要定期執行某個或某幾項任務,如在聯網狀態下,每隔一段時間上傳日誌數據給服務器,或在手機處於Idle狀態時,定期清理手機的存儲空間等。
以往實現這樣的功能時,往往需要啓動一個定時器不斷的輪詢執行任務的條件是否滿足,如果滿足還需啓動定時器定期執行任務,這種機制的實現方式比較麻煩。
34.13.1 JobScheduler介紹
在Android5.0(API 21)中,Google提供了一個叫做JobScheduler的功能組件來處理這種場景;在JobScheduler功能類中,有一個JobService類,它是使用JobScheduler回調的入口點。
JobService類中包含以下幾個函數:
voidjobFinished (JobParameters params, boolean needsReschedule)
這個函數是在任務完成之後被調用
params---這個參數是從onStartJob函數傳遞過來的
needsReschedule---如爲true,此任務只會被執行一次;false則會被反覆執行。
booleanonStartJob (JobParametersparams)
在JobService的子類中,必需重寫這個函數。
params---傳遞此任務的相關信息
返回值爲true,此service必須在一個單獨的子線程中處理工作;返回值爲false,此任務沒有工作要做。
booleanonStopJob (JobParametersparams)
當系統確定必須停止運行任務時,會調用此函數;甚至會在調用jobFinished函數之前被調用。
如果在設定的時間,任務運行的條件不再滿足時,此函數就會被調用:如要求的是設備要連接WiFi,但在執行任務的時候,用戶把WiFi切換掉了;或者任務需要在Idle狀態下執行,但手機進入了非Idle狀態。
params---傳遞此任務的相關信息
返回值爲true時,告訴JobManager根據創建Job時的設置,是否重新安排此任務執行;返回值爲false時,退出Job。
不管返回值是什麼,Job都必須停止執行。
具體代碼如下:
private JobScheduler mJobScheduler;
//聲明Job的任務Id數值
public static final int MY_BACKGROUND_JOB = 0;
//初始化JobScheduler對象
public void initVariables() {
...
mJobScheduler = (JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE );
…
}
//設置執行此任務需滿足的條件、間隔時間和關機重啓後是否繼續執行
public static void scheduleJob(Contextcontext) {
JobScheduler js =
(JobScheduler)context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(
MY_BACKGROUND_JOB,
//在JobSchedulerService類中執行任務
new ComponentName(context,JobSchedulerService.class))
//設置在聯網狀態下執行此任務
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
//設置在設備處於Idle狀態時執行此任務
.setRequiresDeviceIdle(true)
//設置在設備處於充電狀態時執行此任務
.setRequiresCharging(true)
//設置任務的執行間隔時間爲10秒
.setPeriodic(10*1000)
//設置設備關機重啓後,還是繼續按上述要求執行此任務
.setPersisted(true)
.build();
js.schedule(job);
}
Google的官方文檔中描述是必須滿足執行任務的條件後,任務纔會被執行,實際驗證,即使條件不滿足,任務也會被執行,也就是如下代碼和上述代碼的實際執行結果一樣:
public static void scheduleJob(Contextcontext) {
JobScheduler js =
(JobScheduler)context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(
MY_BACKGROUND_JOB,
new ComponentName(context,JobSchedulerService.class))
//設置任務的執行間隔時間爲10秒
.setPeriodic(10*1000)
//設置設備關機重啓後,還是繼續按上述要求執行此任務
.setPersisted(true)
.build();
js.schedule(job);
}
//取消Job
private void cancelJob(){
mJobScheduler.cancelAll();
}
public class JobSchedulerService extendsJobService {
public static final intMY_JOB_MESSAGE = 0;
private Handler mJobHandler = newHandler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg ) {
Toast.makeText(getApplicationContext(), "JobService task running",Toast.LENGTH_LONG).show();
jobFinished( (JobParameters)msg.obj, false);
return true;
}
} );
@Override
public booleanonStartJob(JobParameters params ) {
mJobHandler.sendMessage(Message.obtain( mJobHandler, MY_JOB_MESSAGE, params ) );
return false;
}
@Override
public boolean onStopJob(JobParameters params ) {
Toast.makeText(getApplicationContext(), "JobService task stop", Toast.LENGTH_SHORT).show();
mJobHandler.removeMessages(MY_JOB_MESSAGE);
return false;
}
}
在AndroidManifest.xml中增加如下聲明:
<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<serviceandroid:name=".service.JobSchedulerService"
android:permission="android.permission.BIND_JOB_SERVICE" />