在應用開發中,有以下一些常見的耗電場景:
- 經常爲了使一些特殊模塊正常工作,而通過喚醒 CPU 去執行對應程序,但 Google 測試發現,每次喚醒 CPU,即使程序只運行 1 秒鐘,但實際上消耗了大約兩分鐘的耗電量。
- 一些並不重要的數據,在非 Wi-Fi 環境下上報,如上傳日誌等。
- 在 CPU 高負荷狀態下去做一些數據清理工作。
以上這些操作在應用中是有必要的,但並不緊急,可以選擇在合適的環境下完成,因此Google 爲了提高電池的續航能力,在 Android 5.0(API 21)提供了一個 JobScheduler 組件,只有一系列的預置條件滿足時,才執行對應的操作,這樣既能省電,又保證了功能的完整性。也就是說可以將不緊急的任務交給 Job Scheduler 來處理,Job Scheduler 集中處理收到的任務,選擇合適的時間、合適的網絡,再一起進行執行。
在以下場景可以考慮使用 Job Scheduler:
- 重要不緊急的任務,可以延遲執行,如定期數據庫數據更新和數據上報。
- 耗電量較大的任務,比如充電時才希望執行的備份數據操作。
- 不緊急可以不執行的網絡任務,如在 Wi-Fi 環境預加載數據。
- 可以批量執行的任務。
使用 JobScheduler 主要兩個步驟,創建一個 JobScheduler 對象預設置任務執行條件以及創建 Job Service 執行具體的任務,接下來詳細介紹使用方法。
- 創建 JobScheduler
創建 JobScheduler,用來初始化一個 JobScheduler 以及設置觸發 JobScheduler 執行任務的條件。
1)通過 getSystemService()獲取一個 JobScheduler 的對象:
2)創建一個 JobInfo,描述一個任務的執行 ID,以及觸發這個任務的條件。
public class JobScheduleManager {
private Context mContext;
private JobScheduler jobScheduler;
public JobScheduleManager(Context mContext) {
this.mContext = mContext;
jobScheduler = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
}
public boolean addJobScheduleTask(int taskId) {
JobInfo.Builder builder = new JobInfo.Builder(taskId, new ComponentName(mContext.getPackageName(), JobScheduleService.class.getName()));
switch (taskId) {
case 1:
builder.setPeriodic(1000);
break;
case 2:
builder.setPersisted(false);
break;
default:
break;
}
if (jobScheduler != null) {
return this.jobScheduler.schedule(builder.build()) > 0;
}
return false;
}
}
從代碼看到,首先通過 JobInfo 的 build 方法創建一個 JobInfo,有兩個參數,第一個參數 task_id 是任務 ID,這個 ID 有兩個作用:
- 添加任務時,對不同的 ID 做不同的觸發條件,即用 switch 代碼實現。
- 在執行時需要根據任務 ID 執行具體的任務。
第二個參數 ComponentName 是具體執行 JobSchedluer 任務的服務,參數爲進程包名以及服務類名。
在 switch 代碼段中,針對不同的任務設置不同的觸發條件,JobInfo 支持以下觸發條件:
在 switch 代碼段中,針對不同的任務設置不同的觸發條件,JobInfo 支持以下觸發條件:
- setMinimumLatency(long minLatencyMillis):設置任務的延遲執行時間(單位是 ms),需要注意的是,setMinimumLatency 與 setPeriodic(long time)方法不兼容,同時調用這兩個方法會引起異常。
- setOverrideDeadline(long maxExecutionDelayMillis):設置任務最晚的延遲時間。如果到了規定的時間,其他條件還未滿足,這個任務也會被啓動。與 setMinimumLatency (long time)一樣,setOverrideDeadline 與 setPeriodic(long time)同時調用會引發異常。
- setPersisted(boolean isPersisted):設備重啓之後,任務是否還要繼續執行。
- setRequiredNetworkType(int networkType):只有在滿足指定的網絡條件時,纔會被執行。共有三種類型:
- JobInfo.NETWORK_TYPE_NONE:不管是否有網絡,這個任務都會被執行(如果未設置,這個參數就是默認參數)。
- JobInfo.NETWORK_TYPE_ANY:只有在有網絡的情況下,任務纔可以執行,和網絡類型無關。
- JobInfo.NETWORK_TYPE_UNMETERED:非運營商網絡(比如在 Wi-Fi 連接時),時任務纔會被執行。
- setRequiresCharging(boolean requiresCharging):只有當設備在充電時,這個任務纔會被執行。
- setRequiresDeviceIdle(boolean requiresDeviceIdle):只有當用戶沒有在使用該設備且有一段時間沒有使用時,纔會啓動該任務。
setRequiredNetworkType (int networkType)、setRequiresCharging (booleanrequireCharging)and setRequiresDeviceIdle(boolean requireIdle)這幾個方法可能會使任務無法執行,除非調用 setOverrideDeadline(long time)設置了最大延遲時間,使任務在爲滿足條件的情況下也會被執行。
這樣就完成添加一個任務到 JobScheduler 中。在添加一個任務時,要指定一個完成任務的 Service,JobSchedulerService,在任務條件觸發後,進入JobSchedulerService 執行具體的工作。接下來實現一個 JobService,也就是 JobSchedulerService。
public class JobScheduleService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
// 具體執行的任務
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
// 取消一個任務
return false;
}
}
<service
android:name=".JobScheduleService"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
JobSchedulerService 類必須實現兩個方法 onStartJob(JobParameters params)和 onStopJob(JobParameters params)。
(1)onStartJob(JobParameters params)
任務開始時,執行 onStartJob(JobParameters params)方法,系統用來觸發已經被執行的 任 務 。 任 務 執 行 完 畢 , 需 要 調 用 jobFinished ( JobParameters params , booleanneedsRescheduled)來通知系統。
(2)void jobFinished(JobParameters params,boolean needsReschedule)
任務執行完後,調用 jobFinished 方法通知 JobScheduler。
(3)onStopJob(JobParameters params)
系統接收到一個取消請求時,調用 onStopJob(JobParameters params)方法取消正在等待執行的任務。如果系統在接收到一個取消請求時,實際任務隊列中已經沒有正在運行的任務,onStopJob(JobParameters params)不會被調用。
注意 JobService 運行在主線程,如果是耗時任務,一定要使用 ThreadHandler或者一個異步任務來運行耗時的操作,以防止阻塞主線程。