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已经完成了任务。

注意,该方法调用导致的Job结束并不会回调onStopJob(),只会回调onDestroy()。

・onStopJob() Job中止的时候回调。当JobScheduler发觉该Job条件不满足的时候,或者Job被抢占的时候强制回调该方法。
注意,如果想让这种意外中止的Job重新开始,复写该函数返回true。

另外还有父类Service的基础方法,可以覆写来实现一些辅助作用。

・onCreate() Service被初始化后的回调,可以在这里设置BroadcastReceiver或者ContentObserver等处理。

・onDestroy() Service被销毁前的回调。可以在这里注销BroadcastReceiver或者ContentObserver。

 

上面可以看出,JobService只是Job执行和中止时机的回调入口。
那如何将这个入口告诉系统,就需要用到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 API

我们选取几个代表性的API看看。

・Builder() JobInfo.Builder的内部类构造函数
注意,参数之一ID必须是APP UID内唯一的,如果APP和别的APP共用了UID,那么要防止该ID和别的APP里有冲突

・setOverrideDeadline() 设置job被立即执行的最大延迟期限
注意:即便其他条件没满足此期限到了也要立即执行

・setRequiresDeviceIdle() 是否需要在IDLE状态下运行该Job

・setRequiredNetworkType() 设置需要何种网络类型条件


至此,JobService,JobScheduler以及JobInfo三大块的API我们都已经有些了解了,那我们先写个简单的JobService跑起来试试。

 

JobService DEMO

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的如下定义可以看到,确实是因为取消导致的Job中止。

/** @hide */
  public static final int REASON_CANCELED = 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状态。

1. adb shell dumpsys battery unplug 将USB充电停止

2. adb shell dumpsys battery 查看电池状态确保充电状态关闭

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

3. adb shell dumpsys deviceidle enable 将IDLE状态许可

Deep idle mode enabled
Light idle mode enable

4. 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的如下定义得知确实是因为进入IDLE状态后Job被中止。

public static final int REASON_DEVICE_IDLE = 4;

5.这时候我们使用如下命令将设备走出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。
同样根据stop reason的定义得知Job是在条件不满足时候被中止的。

  public static final int REASON_CONSTRAINTS_NOT_SATISFIED = 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是如此的灵活,可以满足很多特定场景的要求。

这时候,我们思考一个问题,如果自己cancel了的job,同时onStopJob()里返回true,是否也能够自动再启动?

 

自行取消Job后能否自启动

这个问题不需要修改代码,只需要做如下操作。

点击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.

③ 唯一ID

同一个UID的进程里只能有唯一一个Job的ID。
不然的话,新生成的Job会抢占已经运行的Job,导致该Job被异常终止。

④ 自启动

JobService因为运行条件变化后被强制停止后想自启动的话,需要将onStopJob()返回true。

⑤ 强行自启动

JobService不论何种原因被停止了都希望能自动启动的话,需要在onStopJob()或
onDestroy()里强制再次schedule我们的jobservice。

⑥ 取消Job的注意点

如果自行cancel了Job,即便onStopJob()里返回true系统也不会将该Job再度启动。

➆ 手动结束Job的注意点

如果自行finished了Job,那么onStopJob()将得不到回调,将只回调onDestroy()。

⑧ 耗时任务的注意点

Job如果要执行长时间任务的话,onStartJob()应当返回true。不然onStartJob()刚回调结束,Job就会被停止。
 

后续

JobService使用的大体内容就是这些,后续将补充如下内容。

● enqueue API的相关使用说明。

● JobService和Service的区别。

● 源码层面探究JobScheduler如何实现cancel后的job即便onStopJob()返回true也不能再次启动。

● 源码层面探究JobScheduler的大体原理。


原创不易,如果本篇文章引起你的思考和兴趣,欢迎点赞和关注。如果想要了解更多更全信息,扫码关注博主公众号TechMerger


 

 

 

 

 

 

 


 




 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐