JobService的使用介紹

JobService是Android L時候官方加入的組件。適用於需要特定條件下才執行後臺任務的場景。

由系統統一管理和調度,在特定場景下使用JobService更加靈活和省心,相當於是Service的加強或者優化。


我們來研究下JobService如何使用。


官方鏈接如下:

https://developer.android.google.cn/reference/android/app/job/JobService.html


我們先看看JobService類的繼承關係。

public abstract class JobService 

extends Service

可以看到JobService是繼承自Service的抽象類。
看來JobService的本質還是Service,只不過封裝了些額外的方法和邏輯。


那到底JobService如何使用?和Service有什麼區別呢?實現原理又是什麼?


第一個問題:如何使用JobService?


首先我們來看下官方的對於JobService的解釋。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
Entry point for the callback from the JobScheduler.

This is the base class that handles asynchronous requests that were previously scheduled.
You are responsible for overriding onStartJob(JobParameters), which is where you will implement your job logic.

This service executes each incoming job on a Handler running on your application's main thread.
This means that you must offload your execution logic to another thread/handler/AsyncTask 
of your choosing.

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

大概就是下面的意思:
JobService是JobScheduler的回調,是安排的Job請求的實際處理類。
需要我們覆寫onStartJob(JobParameters)方法,並在裏面實現實際的任務邏輯。
因爲JobService的執行是在APP的主線程裏響應的,所以必須提供額外的異步邏輯去執行這些任務。

我們先看下JobService公開的API有哪些。


onStartJob()

定義:Job開始的時候的回調,實現實際的工作邏輯。
注意:如果返回false的話,系統會自動結束本job;


jobFinished()
定義:Job的任務執行完畢後,APP端自己的調用,用以通知JobScheduler已經完成了任務。
注意:該方法執行完後不會回調onStopJob(),但是會回調onDestroy()


onStopJob()
定義:停止該Job。當JobScheduler發覺該Job條件不滿足的時候,或者job被搶佔被取消的時候的強制回調。
注意:如果想在這種意外的情況下讓Job重新開始,返回值應該設置爲true。


另外還有父類Service的基礎方法,可以覆寫來實現一些輔助作用。
onCreate()
定義:Service被初始化後的回調。
作用:可以在這裏設置BroadcastReceiver或者ContentObserver


onDestroy()
定義:Service被銷燬前的回調。
作用:可以在這裏註銷BroadcastReceiver或者ContentObserver


上面可以看出,JobService只是實際的執行和停止任務的回調入口。
那如何將這個入口告訴系統,就需要用到JobScheduler了。

官方鏈接如下:
https://developer.android.google.cn/reference/android/app/job/JobScheduler.html


我們先看看JobScheduler類的繼承關係。
JobScheduler
public abstract class JobScheduler
extends Object



可以看到JobScheduler就是個抽象類。
實際上它的實現邏輯在android.app.JobSchedulerImpl裏。
但是我們暫時不管那麼多,只要知道使用JobScheduler裏面提供的API即可。


照例,看下官方的解釋。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
This is an API for scheduling various types of jobs against the framework that will be
executed in your application's own process.
See JobInfo for more description of the types of jobs that can be run and how to construct them.
You will construct these JobInfo objects and pass them to the JobScheduler with schedule(JobInfo).
When the criteria declared are met, the system will execute this job on your application's JobService.
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

描述的非常清晰,就是說。
JobScheduler是framework層裏用來安排各種各樣的將要執行在app自己進程裏的任務的機制。
我們需要創建各種Job的描述類JobInfo。並且通過JobScheduler傳遞給系統。當我們描述的條件或者標準滿足了,系統
將執行app的JobService。


同樣看下JobScheduler提供的API。


schedule()

定義:安排一個Job任務。


enqueue()
定義:安排一個Job任務,但是可以將一個任務排入隊列。


cancel()
定義:取消一個執行ID的Job。


cancelAll()
定義:取消該app所有的註冊到JobScheduler裏的任務。


getAllPendingJobs()
定義:獲取該app所有的註冊到JobScheduler裏未完成的任務列表。


getPendingJob()
定義:按照ID檢索獲得JobScheduler裏未完成的該任務的JobInfo信息。


上面還提到需要創建JobInfo對象,實際要通過JobInfo.Builder類利用建造者模式創建出JobInfo對象。


JobInfo.Builder裏有很多設置Job條件的方法。


我們選取幾個代表性的API看看。

Builder()
定義:JobInfo.Builder的內部類構造函數。
注意:參數之一ID必須是APP UID內唯一的,如果APP和別的APP共用了UID,那麼要防止該ID和別的APP裏有衝突。

setOverrideDeadline()
定義:設置job被立即執行的最大延遲期限。
注意:即便其他條件沒滿足此期限到了也要立即執行

setRequiresDeviceIdle()
定義:是否需要在IDLE狀態下運行該Job。

setRequiredNetworkType()
定義:設置需要何種網絡類型條件。

JobService,JobScheduler以及JobInfo三大塊的API我們都已經有些瞭解了。

那我們先寫個簡單的JobService跑起來試試。


步驟1.首先創建JobService實現類;

 onCreate() 簡單打個Log
 onStartJob() 模擬業務邏輯,返回true
 onStopJob() 期待被再次執行,返回true
 onDestroy()簡單打個log
 注意:Manifest文件裏JobService的聲明裏必須請求android:permission="android.permission.BIND_JOB_SERVICE"的權限


步驟2.在UI端安排JobInfo進任務隊列

 獲取系統的JobSchedulerService的代理對象
 新建JobInfo.Builder對象,並傳入JobService實現類的ComponentName和ID;
 通過JobInfo.Builder對象設置Job執行的條件,這裏設置條件爲簡單的1s deadline;
 通過JobInfo.Builder對象創建出JobInfo對象;
 通過JobSchedulerService代理對象將JobInfo發送到JobScheduler機制中去;


步驟3.UI端模擬任務完成,通知JobService


對應的代碼


JobService端

public class EllisonsJobService extends JobService {
  public static final int ELLISONS_JOB_ID = 0;
  public static final int ELLISONS_JOB_OVERDIDE_DEADLINE = 1000;

  @Override
  public void onCreate() {
  super.onCreate();
  Log.w(TAG, "EllisonsJobService onCreate()");
  }

  @Override
  public void onDestroy() {
  super.onDestroy();
  Log.w(TAG, "EllisonsJobService destroyed.");
  }

  @Override
  public boolean onStartJob(JobParameters params) {
  Log.w(TAG, "EllisonsJobService onStartJob()");

  Helpers.doHardWork(this, params);

  return true;
  }

  @Override
  public boolean onStopJob(JobParameters params) {
  Log.w(TAG, "EllisonsJobService stopped & wait to restart params:" + params + " reason:" + params.getStopReason());
  return false;
  }
}


UI端

添加四個按鈕:用於schedule,cancel,finish和enqueue job。
代碼如下:


public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
  Log.w(TAG, "MainActivity onCreate() PID:" + android.os.Process.myPid() + " TID:" + android.os.Process.myTid());
setContentView(R.layout.activity_main);
  }

  public void onClick_Schedule(View view) {
  Log.w(TAG, "MainActivity onClick_Schedule()");
  Helpers.schedule(this);
  }

  public void onClick_Finished(View view) {
  Log.w(TAG, "MainActivity onClick_Finished()");
  Helpers.jobFinished();
  }

  public void onClick_Cancel(View view) {
  Log.w(TAG, "MainActivity onClick_Cancel()");
  Helpers.cancelJob(this);
  }

  public void onClick_Enqueue(View view) {
  Log.w(TAG, "MainActivity onClick_Enqueue()");
  Helpers.enqueueJob();
  }

  @Override
  public void onDestroy() {
  super.onDestroy();
  Log.w(TAG, "MainActivity onDestroy()");
  }
}


控制端


public class Helpers {
  private static JobService mJob;
  private static JobParameters mJobParams;

  public static void schedule(Context context) {
  Log.w(TAG, "Helpers schedule()");

  final JobScheduler scheduler = context.getSystemService(JobScheduler.class);
  final JobInfo.Builder builder = new JobInfo.Builder(EllisonsJobService.ELLISONS_JOB_ID,
  new ComponentName(context, EllisonsJobService.class));

builder.setOverrideDeadline(EllisonsJobService.ELLISONS_JOB_OVERDIDE_DEADLINE);
  scheduler.schedule(builder.build());
  }

  public static void cancelJob(Context context) {
  Log.w(TAG, "Helpers cancelJob()");
  final JobScheduler scheduler = context.getSystemService(JobScheduler.class);
  scheduler.cancel(EllisonsJobService.ELLISONS_JOB_ID);
  }

  public static void jobFinished() {
  Log.w(TAG, "Helpers jobFinished()");
  mJob.jobFinished(mJobParams, false);
  }

  public static void enqueueJob() {
  Log.w(TAG, "Helpers enqueueJob()");
  }

  public static void doHardWork(JobService job, JobParameters params) {
  Log.w(TAG, "Helpers doHardWork()");
  mJob = job;
  mJobParams = params;
  }
}


DEMO的主界面




點擊schedule的button。通過log看到JobService啓動了。

01-31 17:59:23.110 13813 13813 W Ellison : MainActivity onClick_Schedule()
01-31 17:59:23.111 13813 13813 W Ellison : Helpers schedule()
01-31 17:59:23.119 13813 13813 W Ellison : EllisonsJobService onCreate()
01-31 17:59:23.121 13813 13813 W Ellison : EllisonsJobService onStartJob()
01-31 17:59:23.121 13813 13813 W Ellison : Helpers doHardWork()


點擊finish的button。通過log看到JobService結束了。

01-31 17:59:35.582 13813 13813 W Ellison : MainActivity onClick_Finished()
01-31 17:59:35.582 13813 13813 W Ellison : Helpers jobFinished()
01-31 17:59:35.595 13813 13813 W Ellison : EllisonsJobService destroyed.


點擊schedule和cancel的button。通過log看到JobService執行後被停止了。

01-31 17:59:48.599 13813 13813 W Ellison : MainActivity onClick_Schedule()
01-31 17:59:48.599 13813 13813 W Ellison : Helpers schedule()
01-31 17:59:48.608 13813 13813 W Ellison : EllisonsJobService onCreate()
01-31 17:59:48.611 13813 13813 W Ellison : EllisonsJobService onStartJob()
01-31 17:59:48.611 13813 13813 W Ellison : Helpers doHardWork()

01-31 17:59:55.039 13813 13813 W Ellison : MainActivity onClick_Cancel()
01-31 17:59:55.039 13813 13813 W Ellison : Helpers cancelJob()
01-31 17:59:55.040 13813 13813 W Ellison : EllisonsJobService stopped & wait to restart params:android.app.job.JobParameters@ac7bfd7 reason:0★
01-31 17:59:55.049 13813 13813 W Ellison : EllisonsJobService destroyed.
★處顯示被停止的原因值爲0。
而據JobParameters.java裏關於stop reason的定義如下。
/** @hide */
  public static final int REASON_CANCELED = 0;
可以看到被取消的Job的reason數值確實爲0。

*關於enqueue的邏輯,後續再添加。


如何查看自己的JobService的運行?


那除了自己加log的形式,有沒有別的方式查看自己的JobService了呢?
答案是有的。

使用adb shell service list命令得到如下信息。

47 jobscheduler: [android.app.job.IJobScheduler]

只能看到JobSchedulerService的信息,看不到自己的Job Service。


但是adb給我們提供了另外一種方式查看JobService。
adb shell dumpsys jobscheduler | grep packagename

我們將packagename換成我們的包名"com.example.TimeApiDemo",得到以下信息。

註冊到JobScheduler裏的JobService的屬性記錄

 

JOB #u0a174/0: 1beb0fa com.example.timeapidemo/.EllisonsJobService
  u0a174 tag=*job*/com.example.timeapidemo/.EllisonsJobService
  Source: uid=u0a174 user=0 pkg=com.example.timeapidemo
  JobInfo:
  Service: com.example.timeapidemo/.EllisonsJobService
  Requires: charging=false batteryNotLow=false deviceIdle=false
  Max execution delay: +1s0ms
  Backoff: policy=1 initial=+30s0ms
  Has late constraint
  Required constraints: DEADLINE
  Satisfied constraints: DEADLINE APP_NOT_IDLE DEVICE_NOT_DOZING
  Unsatisfied constraints:
  Tracking: TIME
  Enqueue time: -36s216ms
  Run time: earliest=none, latest=-35s216ms
  Ready: false (job=true user=true !pending=true !active=false !backingup=true comp=true)

正在運行的JobService的信息

Active jobs:
  ...
  Slot #3: 1beb0fa #u0a174/0 com.example.timeapidemo/.EllisonsJobService
  Running for: +36s215ms, timeout at: +9m23s798ms
  u0a174 tag=*job*/com.example.timeapidemo/.EllisonsJobService
  Source: uid=u0a174 user=0 pkg=com.example.timeapidemo
  Required constraints: DEADLINE
  Tracking: TIME
  Enqueue time: -36s216ms
  Run time: earliest=none, latest=-35s216ms
  Evaluated priority: 40
  Active at -36s213ms, pending for +2ms

JobService自啓動


一開始的時候說到Job條件不滿足的時候,JobScheduler會強制停止該Job,並在條件滿足的時候再次啓動該Job。
我們來驗證下。


IDLE狀態下Job停止的例子


我們目前的demo裏在創建JobInfo的時候並沒有調用setRequiresDeviceIdle()。而這個函數的默認值爲false,即意味着該Job不需要在IDLE狀態下運行。
那麼等同於如果系統進入了IDLE狀態,那麼該Job的條件應該不滿足,會被停止。當不是IDLE狀態了,條件滿足了,Job又會被執行。

 再次點擊schedule的button,確保我們的Job開始了。

        使用如下命令使得設備強制進入IDLE狀態。

        adb shell dumpsys battery unplug 將USB充電停止


        adb shell dumpsys battery 查看電池狀態確保充電狀態關閉

Current Battery Service state:
  (UPDATES STOPPED -- use 'reset' to restart)
  AC powered: false

        

         adb shell dumpsys deviceidle enable 將IDLE狀態許可

Deep idle mode enabled
Light idle mode enable

        

         adb shell dumpsys deviceidle force-idle 強制進入IDLE狀態

Now forced in to deep idle mode

        

         這時候查看log,發現我們的JobService被停止和銷燬了。

01-31 18:39:31.064 15504 15504 W Ellison : MainActivity onClick_Schedule()
01-31 18:39:31.065 15504 15504 W Ellison : Helpers schedule()
01-31 18:39:31.096 15504 15504 W Ellison : EllisonsJobService onCreate()
01-31 18:39:31.104 15504 15504 W Ellison : EllisonsJobService onStartJob()
01-31 18:39:31.104 15504 15504 W Ellison : Helpers doHardWork()
01-31 18:39:38.870 15504 15504 W Ellison : EllisonsJobService stopped & wait to restart params:android.app.job.JobParameters@1a480b9 reason:4★
01-31 18:39:38.880 15504 15504 W Ellison : EllisonsJobService destroyed.
        ★處顯示被停止的原因值爲4。
        而據JobParameters.java裏關於stop reason的定義。
public static final int REASON_DEVICE_IDLE = 4;

        可以看到進入IDLE狀態後Job被停止後的stop reason數值確實爲4。


        這時候我們使用如下命令將設備走出IDLE狀態。
        adb shell dumpsys deviceidle disable

Deep idle mode disabled
Light idle mode disabled
        再次查看log,發現我們的JobService並沒有被重新啓動。

        哪裏出了問題呢?


        查閱官方文檔,我們發現了答案。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

boolean onStopJob (JobParameters params)
...
Returns
boolean True to indicate to the JobManager whether you'd like to reschedule this
job based on the retry criteria provided at job creation-time. False to drop
the job. Regardless of the value returned, your job must stop executing.

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

原來在條件不滿足的時候系統會強制停止該Job並回調onStopJob()。onStopJob()裏執行停止本地任務的邏輯。如果希望該Job在條件滿足的時候被重新啓動,應該將返回值置爲true。


那我們將onStopJob()的返回值改爲true,再試一下。

public class EllisonsJobService extends JobService {
  ...
  @Override
  public boolean onStopJob(JobParameters params) {
  Log.w(TAG, "EllisonsJobService stopped & wait to restart params:" + params + " reason:" + params.getStopReason());
  return true;
  }
}


再次執行上面的步驟。

    adb shell dumpsys battery unplug
    adb shell dumpsys deviceidle enable
    adb shell dumpsys deviceidle force-idle
    adb shell dumpsys deviceidle disable


得到如下Log:

01-31 18:49:22.822 15745 15745 W Ellison : MainActivity onCreate() PID:15745 TID:15745
01-31 18:49:23.925 15745 15745 W Ellison : MainActivity onClick_Schedule()
01-31 18:49:23.926 15745 15745 W Ellison : Helpers schedule()
01-31 18:49:23.938 15745 15745 W Ellison : EllisonsJobService onCreate()
01-31 18:49:23.941 15745 15745 W Ellison : EllisonsJobService onStartJob()
01-31 18:49:23.941 15745 15745 W Ellison : Helpers doHardWork()
01-31 18:49:32.005 15745 15745 W Ellison : EllisonsJobService stopped & wait to restart params:android.app.job.JobParameters@1a480b9 reason:4
01-31 18:49:32.007 15745 15745 W Ellison : EllisonsJobService destroyed.
01-31 18:50:19.190 15745 15745 W Ellison : EllisonsJobService onCreate()
01-31 18:50:19.197 15745 15745 W Ellison : EllisonsJobService onStartJob()
01-31 18:50:19.198 15745 15745 W Ellison : Helpers doHardWork()
果然,onStopJob()的返回值改爲true後,離開IDLE狀態後系統可以將Job再次啓動起來。

我們再驗證另外一種情況,如果Job需要網絡條件,那麼斷網後是否也能夠停止Job,開網後是否能夠再次啓動Job?


網絡條件下執行Job的例子


修改的代碼如下:

public class Helpers {
  ...
  public static void schedule(Context context) {
  ...
  builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
  // builder.setOverrideDeadline(EllisonsJobService.ELLISONS_JOB_OVERDIDE_DEADLINE);
  scheduler.schedule(builder.build());
  }
}


首先開網並點擊schedule的button,可以看到service開始運行。

01-31 19:00:56.239 16043 16043 W Ellison : MainActivity onCreate() PID:16043 TID:16043
01-31 19:01:00.943 16043 16043 W Ellison : MainActivity onClick_Schedule()
01-31 19:01:00.943 16043 16043 W Ellison : Helpers schedule()
01-31 19:01:00.952 16043 16043 W Ellison : EllisonsJobService onCreate()
01-31 19:01:00.954 16043 16043 W Ellison : EllisonsJobService onStartJob()
01-31 19:01:00.954 16043 16043 W Ellison : Helpers doHardWork()


我們關閉網絡,可以看到service停止運行了。

01-31 19:01:13.182 16043 16043 W Ellison : EllisonsJobService stopped & wait to restart params:android.app.job.JobParameters@8394280 reason:1★
01-31 19:01:13.184 16043 16043 W Ellison : EllisonsJobService destroyed.
★處顯示被停止的原因值爲1。
而據JobParameters.java裏關於stop reason的定義。
  public static final int REASON_CONSTRAINTS_NOT_SATISFIED = 1;
可以看到Job在條件不滿足時候被停止的stop reason數值確實爲1。


我們再次開啓網絡,發現service自己起來了。 

01-31 19:01:43.203 16043 16043 W Ellison : EllisonsJobService onCreate()
01-31 19:01:43.209 16043 16043 W Ellison : EllisonsJobService onStartJob()
01-31 19:01:43.209 16043 16043 W Ellison : Helpers doHardWork()

可以看到,網絡條件的Job運行過程和IDLE例子結果完全一致。

我們發現JobService是如此的靈活。可以滿足很多特定場景的要求。


自行取消Job後能否自啓動?


這時候,我們思考一個問題,如果自己cancel了的job,如果onStopJob()返回true,是否也能夠將其自動啓動?

這個問題不需要修改代碼,只需要做如下操作。


點擊schedule和cancel的button。

01-31 19:02:48.917 16043 16043 W Ellison : MainActivity onClick_Schedule()
01-31 19:02:48.918 16043 16043 W Ellison : Helpers schedule()
01-31 19:02:48.923 16043 16043 W Ellison : EllisonsJobService onCreate()
01-31 19:02:48.936 16043 16043 W Ellison : EllisonsJobService onStartJob()
01-31 19:02:48.936 16043 16043 W Ellison : Helpers doHardWork()

01-31 19:02:55.956 16043 16043 W Ellison : MainActivity onClick_Cancel()
01-31 19:02:55.956 16043 16043 W Ellison : Helpers cancelJob()
01-31 19:02:55.961 16043 16043 W Ellison : EllisonsJobService stopped & wait to restart params:android.app.job.JobParameters@4634857 reason:0
01-31 19:02:55.963 16043 16043 W Ellison : EllisonsJobService destroyed.
在cancel完之後等待了很長時間,service也沒有自動啓動起來。
這個是不是和上面的官方說明矛盾啊。
不是說返回true,系統就會再次啓動Job嗎?

其實並不矛盾。
首先從邏輯上講,APP自行取消的Job,系統是不需要爲你再次啓動的。
只有因外部條件不滿足了等場合被強制的Job纔有再次啓動的可能性。
後期我們將從源碼角度探究JobSecheduler如此設計的證據。

那如果說我們收到要求,不管是系統自動結束的我們Job還是我們自行Cancel了Job,
我們都希望Job能夠再次啓動。
那該怎麼辦?


其實很簡單,我們可以在onStopJob()或onDestroy()裏再次schedule我們的jobservice。
這裏以onStopJob()爲例,我們將代碼做下修改:

public class EllisonsJobService extends JobService {
  ...
  @Override
  public boolean onStopJob(JobParameters params) {
  Log.w(TAG, "EllisonsJobService stopped & wait to restart params:" + params + " reason:" + params.getStopReason());
  Helper.schedule(this);
  return false;
  }
}


繼續點擊點擊schedule和cancel的button。

01-31 19:20:02.615 16589 16589 W Ellison : MainActivity onClick_Schedule()
01-31 19:20:02.615 16589 16589 W Ellison : Helpers schedule()
01-31 19:20:02.632 16589 16589 W Ellison : EllisonsJobService onCreate()
01-31 19:20:02.636 16589 16589 W Ellison : EllisonsJobService onStartJob()
01-31 19:20:02.636 16589 16589 W Ellison : Helpers doHardWork()

01-31 19:20:08.248 16589 16589 W Ellison : MainActivity onClick_Cancel()
01-31 19:20:08.248 16589 16589 W Ellison : Helpers cancelJob()
01-31 19:20:08.250 16589 16589 W Ellison : EllisonsJobService stopped & wait to restart params:android.app.job.JobParameters@cd62c5f reason:0
01-31 19:20:08.250 16589 16589 W Ellison : Helpers schedule()
01-31 19:20:08.262 16589 16589 W Ellison : EllisonsJobService destroyed.
01-31 19:20:08.264 16589 16589 W Ellison : EllisonsJobService onCreate()
01-31 19:20:08.267 16589 16589 W Ellison : EllisonsJobService onStartJob()
01-31 19:20:08.267 16589 16589 W Ellison : Helpers doHardWork()
通過log發現JobService cancel之後立馬又被系統重新創建並啓動了。


總結


JobService被意外終止之後如何自啓動的方案有兩種。

1.JobService的onStopJob()返回值設置爲true。
  注意:對於自行cancel了的Job無效。
2.JobService的onStopJob()或onDestroy()裏強制再次schedule我們的jobservice。

注意

JobService綁定成功後,系統的JobServiceContext都會給該JobService創建和持有WakeLock,直到JobService銷燬的時候才釋放WakeLock對象。
也就是說,除非JobService執行結束或意外中止,系統一直會保持運轉以保證JobService的正常運行。
所以,如果JobService保持自啓動的話,最好不要無限循環自啓動,這樣會導致系統一直無法休眠,加速電量的損耗。



我們將目前的嘗試結果做下總結,總結那些JobService使用中應當知道的規則。


JobService規則


規則一

Manifest文件裏JobService的聲明裏必須請求android:permission="android.permission.BIND_JOB_SERVICE"的權限。
不然的話,在schdule或者enqueue job的時候會拋出如下的IllegalArgumentException。
"Error: requested job be persisted without holding RECEIVE_BOOT_COMPLETED permission."

規則二

JobInfo創建的時候必須設置一個條件。
不然的話,在創建JobInfo對象時會拋如下的IllegalArgumentException。
"You're trying to build a job with no constraints, this is not allowed."

規則三

同一個UID的進程裏只能有唯一一個Job的ID。
不然的話,新生成的Job會搶佔已經運行的Job,導致該Job被異常終止。

規則四

JobService因爲運行條件變化後被強制停止後想自啓動的話,需要將onStopJob()返回true。

規則五

JobService不論何種原因被停止了都希望能自動啓動的話,需要在onStopJob()或
onDestroy()裏強制再次schedule我們的jobservice。

規則六

如果自行cancel了Job,即便onStopJob()裏返回true系統也不會將該Job再度啓動。


規則七

如果自行finished了Job,那麼onStopJob()將得不到回調,將只回調onDestroy()。


規則八

Job如果要執行長時間任務的話,onStartJob()應當返回true。不然onStartJob()剛回調結束,
Job就會被停止。


後續


JobService使用的大體內容就是這些,後續將補充如下內容。

一 enqueue API的相關使用說明。


二 JobService和Service的區別。


三 源碼層面探究JobScheduler如何實現cancel後的job即便onStopJob()返回true也不能再次啓動。


四 源碼層面探究JobScheduler的大體原理。







 





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章