性能優化(8.4)-在Android Lollipop中使用JobScheduler

主目錄見::Android高級進階知識(這是總目錄索引)
[譯]Using the JobScheduler API on Android Lollipop
谷歌官網的例子:JobScheduler

?今天還是打算以上面一篇英文文章為基礎,同時你也可以參考谷歌官網的JobScheduler例子來了解它的使用方式。JobScheduler作為系統服務的形式出現,任務的調配統一由系統在特定的條件下進行協調,是android 5.0及之后一個相對于AlarmManager+wakeLock而言比較節能的方案,也是谷歌推薦的一個做法。

一.目標

這篇文章作為電量優化的一個方案出現,我們有理由去了解怎么使用它還有它的原理,今天我們目標是:
1.了解JobScheduler的使用方法;
2.能在實際場景中使用JobScheduler。

二.JobScheduler

這篇教程里面,你將學會如何在 Android Lollipop中使用JobScheduler APIJobScheduler的API允許開發者在條件滿足的情況下創建一些后臺任務。

介紹

在Android開發中,在某些場景中,你可能希望在之后的某個時間節點或者在某些條件下執行你的任務,比如你的設備正在充電的情況下或者連到wifi網絡的情況下。幸虧有了Android 21也就是Android Lollipop,谷歌提供了一個新的組件JobScheduler來滿足這些場景。

當一系列的前置條件被滿足之后,JobScheduler API就會執行你應用的某個操作。跟AlarmManager不同的是,它的執行時間是不確定的。另外,JobScheduler API會將任務打包一起執行。這允許你的應用執行某項任務的時候不需要考慮時間控制引起的電量消耗。

這篇文章中,你將通過執行一個簡單的后臺任務來學習更多關于JobScheduler APIJobService類的知識。這篇文章里面涉及的代碼見GITHUB.

1.創建Job Service

首先,你需要創建一個基于最低版本為Android 21的Android工程,因為JobScheduler API是在最新Android版本才被添加進來的,而且在寫這篇文章的時候,還沒有向后兼容的support 庫。

這里假設你用的是Android Studio,當你點擊完成創建新的工程,你將得到一個"Hello World"應用的骨架。第一步要做的就是你要在這個工程基礎上創建一個新的Java 類。為了盡可能簡單,這里就把這個類命名為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)是用在任務開始執行的時候,因為這是系統用來觸發已經計劃執行的任務。你可以看到,這個方法返回一個boolean類型的值。如果你返回的是false,那么系統就會認為要執行的任務耗費的時長不長,且在方法返回的時候已經完成了。如果返回的是true,那么系統會認為要執行的任務需要的時長比較長,執行任務的重擔也會落在你的身上,開發者就必須通過jobFinished(JobParameters params, boolean needsRescheduled)方法來告訴系統你的任務是什么時候結束的。

當系統接收到cancel 的請求,那么onStopJob(JobParameters params)方法就會被用來取消正在等待執行的任務。需要注意的是當onStartJob(JobParameters params)方法返回為false的時候,當接收到cancel 請求的時候,系統會任務當前沒有任務正在執行,換句話說就是,onStopJob(JobParameters params)不會被調用。

有一點需要特別注意的是你的 job service 是運行在主線程的,這就意味著你必須使用另外的線程,或者Handler,或者一個異步任務來執行耗時長的任務以避免阻塞主線程。因為多線程已經超出本教程的范圍了,所以我們在JobSchedulerService類中就簡單地用一個Handler來執行我們的任務。

private Handler mJobHandler = new Handler( new Handler.Callback() {
    @Override
    public boolean handleMessage( Message msg ) {
        Toast.makeText( getApplicationContext(), 
            "JobService task running", Toast.LENGTH_SHORT )
            .show();
        jobFinished( (JobParameters) msg.obj, false );
        return true;
    }
} );

在這個Handler中,你實現了它的handleMessage(Message msg)方法并且在方法里執行你的代碼邏輯。在這個例子中,我們盡量保持簡單,只是彈出了一個Toast消息,這個地方也就是你放自己代碼邏輯的地方,比如同步數據。

當任務完成,你必須調用jobFinished(JobParameters params, boolean needsRescheduled)來通知系統你已經完成了任務的執行并且可以執行下一個操作了。如果你不這么做的話,那么你的任務就會執行一次并且應用不會被允許執行額外的任務。

jobFinished(JobParameters params, boolean needsRescheduled)方法中的兩個參數,第一個參數JobParameters 是從JobService類中的onStartJob(JobParameters params)方法傳遞過來的,第二個參數的boolean值是讓系統知道是否在原有的條件下重新執行任務。理解這個boolean值是很有用的,因為他決定了在某些情況下任務不能被執行完成應該怎么處理,比如網絡請求失敗。

Handler實例被創建, 你就可以繼續實現onStartJob(JobParameters params)方法和onStopJob(JobParameters params)方法來控制你的任務。你會注意到,下面代碼片段里onStartJob(JobParameters params)方法返回了true,這是因為你將使用Handler實例來控制你的操作,也就意味著代碼邏輯的執行會超過onStartJob(JobParameters params)的結束。通過返回true,你就可以讓系統知道,你會自己調用jobFinished(JobParameters params, boolean needsRescheduled)方法來結束任務。同時你注意到數字1被傳遞給Handler實例,這是你用來標識任務的標記。

@Override
public boolean onStartJob(JobParameters params) {
    mJobHandler.sendMessage( Message.obtain( mJobHandler, 1, params ) );
    return true;
}
@Override
public boolean onStopJob(JobParameters params) {
    mJobHandler.removeMessages( 1 );
    return false;
}

一旦完成了JobSchedulerService類的java部分,你就必須在AndroidManifest.xml中添加一個service節點來使你的應用有權限來綁定(bind)和使用(use)JobService這個類。

<service android:name=".JobSchedulerService"
    android:permission="android.permission.BIND_JOB_SERVICE" />

2.創建Job Scheduler

當編寫完JobSchedulerService類之后,我們就可以來看你的應用是怎么和JobScheduler API進行交互的,第一件事就是創建一個叫做mJobSchedulerJobScheduler對象,并且通過獲取系統服務JOB_SCHEDULER_SERVICE來初始化它。 在例子里面,這步操作寫在MainActivity中。

mJobScheduler = (JobScheduler) 
    getSystemService( Context.JOB_SCHEDULER_SERVICE );

當你想要創建你的計劃任務的時候,你必須通過JobInfo.Builder來構建你的JobInfo對象,然后傳給你的JobScheduler服務。為了創建JobInfo對象,JobInfo.Builder接收兩個參數,第一個參數是為了標識你的任務的,第二個參數是service的組件名字(component name)。

JobInfo.Builder builder = new JobInfo.Builder( 1,
        new ComponentName( getPackageName(), 
            JobSchedulerService.class.getName() ) );

這個builder允許你在任務執行之前設置不同的控制選項,下面的代碼片段展示了你的程序將會被每三秒執行一次。

builder.setPeriodic( 3000 );

其他的方法包括:

  • setMinimumLatency(long minLatencyMillis):這個方法是讓你設置任務的延遲執行時間,這個方法不能與setPeriodic(long time)方法合用,不然會拋出異常。
  • setOverrideDeadline(long maxExecutionDelayMillis):這個方法設置任務的最后執行時間。甚至其他條件為滿足,你的任務也會在這個規定時間啟動。跟setMinimumLatency(long time)方法一樣,這個方法也不能與setPeriodic(long time)方法合用,不然會拋出異常。
  • setPersisted(boolean isPersisted):這個函數告訴系統是否你的任務在設備重啟的時候要繼續存在。
  • setRequiredNetworkType(int networkType):這個函數告訴系統你的任務是否在特定的網絡類型下才執行。默認情況下是JobInfo.NETWORK_TYPE_NONE,意思就是說,不管你的網絡連接與否任務都會被執行。另外兩個類型,一種是JobInfo.NETWORK_TYPE_ANY,只有在有網絡連接的情況下才會執行你的任務,還有一種是JobInfo.NETWORK_TYPE_UNMETERED,它允許你的任務在不是蜂窩網絡例如wifi連接的時候才執行.
  • setRequiresCharging(boolean requiresCharging):這個函數是告訴系統只有在充電的情況下才會執行你的任務。
  • setRequiresDeviceIdle(boolean requiresDeviceIdle):這個函數讓你的任務在用戶未使用設備且有一段時間未使用的情況下才執行即設備處于空閑狀態。

需要注意的是setRequiredNetworkType(int networkType), setRequiresCharging(boolean requireCharging)setRequiresDeviceIdle(boolean requireIdle)可能讓你的任務不會被執行,除非你也設置了setOverrideDeadline(long time),這樣你的條件不滿足任務還是會被執行,只要滿足最后的執行時間。一旦你的前置條件被設置,你就可以創建JobInfo對象然后將它傳給JobScheduler對象:

if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
    //If something goes wrong
}

你會注意到schedule方法返回一個integer,如果方法執行失敗,方法就會返回0或者小于0的數, 如果執行成功的話,那么就會返回JobInfo.Builder中設置的任務的唯一標識。

如果你要停止特定的一個任務或者所有的任務,你可以調用JobScheduler對象中的cancel(int jobId)方法和cancelAll()方法:

mJobScheduler.cancelAll();

到這里,你應該會使用JobSchedulerAPI來批量執行你的任務和一些后臺任務了。

總結

這篇文章中,你已經學會了如何實現JobService的子類和用Handler對象來執行一個后臺任務了。而且你也學會了用JobInfo.Builder來設置一些執行條件來決定任務的執行與否。掌握了這些之后,你就可以減少你應用程序執行所消耗的電量。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容