Android 中高效執行Schedule 任務(譯)

wutongke發表於2017-07-20

在目前的Application開發中,執行一些非同步任務非常普遍,其中有些任務的執行週期甚至超過了Application的生命週期,比如一些下載資料的任務或者一些更新網路資源的任務。有時我們需要執行一些非立即開始的任務。Android提供了一些可以在applications中明智使用的API,用於 執行一些預期後臺任務。

選擇一個合適執行方式可以提高application 的效能,同時可以節省裝置的電量損耗。

Android M引入了 Doze mode用於在使用者不使用手機一段時間後最大可能地節省電量。

以下是幾個Android提供的API:

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

使用Service的問題

Services允許在後臺長時間執行任務。但是在後臺執行Services相對來說比較耗電。

Services即使不執行什麼有效的任務,也會一直佔用裝置的資源。當這些後臺Services監聽系統的廣播時會加重以上的問題。

App執行期的Schedule任務

在app執行期執行一些Schedule任務時,推薦使用Handler配合Timer和Thread。這比使用Alarm Manager, Job Scheduler等更簡單,也更高效。

App生命週期外的Schedule 任務

Alarm Manager

AlarmManager提供了系統級別alarm service的入口。它提供了在應用執行期外執行操作的方法。AlarmManager可以在未來的某個時間啟動一個服務,它可以在定時到達時觸發一個PendingIntent。

註冊後的alarm可以在裝置鎖屏時依然是保留的(任務可以在裝置鎖屏時觸發),但是在裝置關閉或重啟之後就無效了。

AlarmManager 可以在用於在特定時間觸發任務的操作,並不提供其他更完善的執行條件:如裝置空閒、網路可用或者開始充電等條件。

示例:當我們需要在一個小時後或者每個小時執行一些操作時,AlarmManager是一個不錯的選擇。但是無法在諸如網路可用或者裝置非充電狀態等狀態出現時觸發事件。

Job Scheduler

Job Scheduler 是所有提到的執行預期任務首選的方式,可以高效地執行後臺任務。Job Scheduler API在Android 5.0(API 21)中引入的。

Job Scheduler執行在裝置有可用資源或者合適的條件時觸發任務。在建立任務時可以自定義各種條件。當滿足生命的條件時,系統將在app的 JobService中執行定義的任務。Job Scheduler還可以根據Doze模式和應用程式的待機限制執行必要的操作。

用這種方式執行任務,可以讓裝置長時間處於休眠狀態,從而延長電池使用時長。一般來說Job Scheduler可以用來執行對時間要求不嚴格的所有任務。

GCM Network Manager

GCM (Google Cloud Messaging)網路管理擁有所有JobScheduler特性。GCM 網路管理可以用於高效執行所有重複或單次不緊急的任務,同時可以有效的節省裝置電量。

它用於後向相容,可以在Android 5.0以下使用。在API 23及以上GCM實際使用了系統的JobSchedule。GCM 網路管理使用了Google Play services中的scheduling 引擎,因此只能在安裝了Google Play 的裝置中使用。

谷歌強烈建議GCM的使用者升級到FCM,使用Firebase Job Dispatcher執行所有任務。

Firebase Job Dispatcher

The Firebase JobDispatcher也是一個執行後臺任務的庫,它向後相容(支援 API 21一下),可以在API 9+上執行。

The Firebase JobDispatcher可以執行在未安裝Google Play 的裝置上。The Firebase JobDispatcher實際使用了AlarmManager,當然如果裝置安裝了Google Play,則The Firebase JobDispatcher使用Google Play中的Scheduling 引擎。

Sync Adapter

Sync Adapter設計用來同步本地和雲端的資料。它只可以用來執行這種任務。在本地或者雲端資料發生變化時可以觸發資料同步,或者定時觸發。Android系統會嘗試使用批量同步從而節省電量,未傳輸的資料將在佇列中等待同步。系統只會在聯網情況下嘗試進行資料同步。

當然,還是建議儘可能使用JobScheduler, Firebase JobDispatcher, or GCM Network Manager等方法。

實踐

介紹了這麼多,我們來提供一個job scheduler的示例。

1. 建立 job service

繼承JobService來建立JobSchedulerService:

public class JobSchedulerService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}複製程式碼

JobService在main thread中執行,所有耗時邏輯應在非同步執行緒中。

同時還需要在AndroidManifest中註冊JobScheduler:

<application>
<service
android:name=”.JobSchedulerService “
android:permission=”android.permission.BIND_JOB_SERVICE”
android:exported=”true”/>
</application>複製程式碼

2. 建立一個JobInfo

建立JobInfo,如下所示需要傳遞 JobService。Job Builder允許建立job 執行的多個條件。

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. 執行任務

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

總結

在執行預期任務,需要仔細考慮執行任務的時機,選擇合適的方式,考慮應用的執行效能和節電效能。

JobScheduler非常方便使用,同時即使在系統重啟後依然可以執行。但是要注意JobScheduler要求API 21+。

歡迎閱讀,原文地址:android.jlelse.eu/schedule-ta…

歡迎關注公眾號wutongke,定期推送移動開發前沿技術文章:

wutongke
wutongke

相關文章