深入理解 JobScheduler 与 JobService 的使用
private void onJobStartClick() {JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);ComponentName componentName = new ComponentName(this, MyJobService.class);JobInfo jobinfo = new JobInfo.Builder(JOB_INFO_ID, componentName).setPeriodic(JOB_PERIODIC).build();}
周期 periodic 设置为 5 秒->运行,会发现 JobService 没有被启动,为什么? #####setPeriodic 的最小执行间隔 源码里来找答案:android/frameworks/base/core/java/android/app/job/JobInfo.java
/* Minimum interval for a periodic job, in milliseconds. /private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L; // 15 minutes/ Minimum flex for a periodic job, in milliseconds. */private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
/**
Specify that this job should recur with the provided interval, not more than once per
period. You have no control over when within this interval this job will be executed,
only the guarantee that it will be executed at most once within this interval.
Setting this function on the builder with {@link #setMinimumLatency(long)} or
{@link #setOverrideDeadline(long)} will result in an error.
@param intervalMillis Millisecond interval for which this job will repeat./public Builder setPeriodic(long intervalMillis) {return setPeriodic(intervalMillis, intervalMillis);}/*
Specify that this job should recur with the provided interval and flex. The job can
execute at any time in a window of flex length at the end of the period.
@param intervalMillis Millisecond interval for which this job will repeat. A minimum
@param flexMillis Millisecond flex for this job. Flex is clamped to be at least
*/public Builder setPeriodic(long intervalMillis, long flexMillis) {mIsPeriodic = true;mIntervalMillis = intervalMillis;mFlexMillis = flexMillis;mHasEarlyConstraint = mHasLateConstraint = true;return this;}
/**
Query the minimum interval allowed for periodic scheduled jobs. Attempting
to declare a smaller period that this when scheduling a job will result in a
job that is still periodic, but will run with this eff
ective period.*
@return The minimum available interval for scheduling periodic jobs, in milliseconds./public static final long getMinPeriodMillis() {return MIN_PERIOD_MILLIS;}/*
Set to the interval between occurrences of this job. This value is <b>not</b> set if the
job does not recur periodically.*/public long getIntervalMillis() {final long minInterval = getMinPeriodMillis();return intervalMillis >= minInterval ? intervalMillis : minInterval;}
总结几个要点:
可以看到系统默认设置了一个最小间隔时间 15 分钟,在获取执行间隔时,会先比较最小间隔时间和设置的间隔时间,取其中大的那个。所以 setPeriodic 设置时间小于 15 分钟是不会生效的。
flexMillis 参数是用来设置周期任务执行的活动时间的,这意味着 JobScheduler 规划的任务不是在精确的时间执行的。并且这个时间也是有最小值的,系统默认 5 分钟。
setMinimumLatency 和 setOverrideDeadline 不能同 setPeriodic 一起使用,会引起报错,另外还有一些其他规则,看源码:
/**
@return The job object to hand to the JobScheduler. This object is immutable.*/public JobInfo build() {// Allow jobs with no constraints - What am I, a database?if (!mHasEarlyConstraint && !mHasLateConstraint && mConstraintFlags == 0 &&mNetworkType == NETWORK_TYPE_NONE &&mTriggerContentUris == null) {throw new IllegalArgumentException("You're trying to build a job with no " +"constraints, this is not allowed.");}// Check that a deadline was not set on a periodic job.if (mIsPeriodic) {if (mMaxExecutionDelayMillis != 0L) {throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +"periodic job.");}if (mMinLatencyMillis != 0L) {throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +"periodic job");}if (mTriggerContentUris != null) {throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +"periodic job");}}if (mIsPersisted) {if (mTriggerContentUris != null) {throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +"persisted job");}if (!mTransientExtras.isEmpty()) {throw new IllegalArgumentException("Can't call setTransientExtras() on a " +"persisted job");}if (mClipData != null) {throw new IllegalArgumentException("Can't call setClipData() on a " +"persisted job");}}if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) {throw new IllegalArgumentException("An idle mode job will not respect any" +" back-off policy, so calling setBackoffCriteria with" +" setRequiresDeviceIdle is an error.");}JobInfo job = new JobInfo(this);....return job;}
####如何查看自己的 JobService 的运行? adb 给我们提供了 dumpsys 工具: adb shell dumpsys jobscheduler
JOB #u0a122/10001: 945a633 com.fantasy.android.demo/.android.job.MyJobServiceu0a122 tag=job/com.fantasy.android.demo/.android.job.MyJobServiceSource: uid=u0a122 user=0 pkg=com.fantasy.android.demoJobInfo:Service: com.fantasy.android.demo/.android.job.MyJobServicePERIODIC: interval=+1h0m0s0ms flex=+1h0m0s0msRequires: charging=false batteryNotLow=false deviceIdle=falseBackoff: policy=1 initial=+30s0msHas early constraintHas late constraintRequired constraints: TIMING_DELAY DEADLINESatisfied constraints: APP_NOT_IDLE DEVICE_NOT_DOZINGUnsatisfied constraints: TIMING_DELAY DEADLINETracking: TIMEEnqueue time: -5m38s906msRun time: earliest=+54m21s65ms, latest=+1h54m21s65ms
评论