JobScheduler 是将任务(Job)放到后台,当预制的条件被满足时,这些Job会在后台被执行。
通常情况下,我们会把一些不是特别紧急的任务放到更加合适的时机来批量处理,这样做不仅可以避免频繁的唤醒硬件模块,还避免了在不合适的时候执行一些耗电任务。
一、JobScheduler如何使用?
[第一步]
创建JobService类
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {
private Handler mHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.obj instanceof JobParameters) {
JobParameters params = (JobParameters) msg.obj;
jobFinished(params, false);
}
}
};
@Override
public boolean onStartJob(final JobParameters params) {
Message message = mHandler.obtainMessage();
message.obj = params;
mHandler.sendMessage(message);
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
JobService 本质上是Service,所以,需要在注册表中注册
<service android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
注意,必须要添加android.permission.BIND_JOB_SERVICE
权限,否则会报错。
[第二步]
创建JobInfo,通过builder设定Job的执行选项
JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(1, new ComponentName(this, MyJobService.class));
builder.setMinimumLatency(2000); // 最短延迟时间
builder.setOverrideDeadline(10000); // 最长延迟时间
JobInfo.Builder的第一个参数是jobId,由开发者指定。
setMinimumLatency
和 setOverrideDeadline
是预设的条件,setMinimumLatency
是最短延迟时间,setOverrideDeadline
是最长延迟时间。
[第三步]
获取JobScheduler服务执行任务
jobScheduler.schedule(builder.build());
二、Job的执行条件有哪些?
JobScheduler 是将任务(Job)放到后台,当预制的条件被满足时,这些Job会在后台被执行。
这些预制条件是由JobInfo指定的,那么有哪些预制条件呢?
builder.setMinimumLatency(2000);
可以设置最短延迟时间,即工作的最早执行时间是2秒。
-----------------------------
builder.setOverrideDeadline(10000);
可以设置最长延迟时间,即工作的最迟执行时间是10秒。
-----------------------------
builder.setBackoffCriteria(TimeUnit.SECONDS.toMillis(10), JobInfo.BACKOFF_POLICY_LINEAR);
触发重试,Job的执行总是会执行 onStartJob 方法,一旦触发重试,那么会重新执行 onStartJob 方法。
第一个参数是initialBackoffMillis,意思是:作业失败时最初等待的毫秒时间间隔。
第二个参数是backoffPolicy,意思是重试策略(重试方案),它定义了两种重试方案:
JobInfo.BACKOFF_POLICY_LINEAR:线性重试方案
公式为:retry_time(current_time, num_failures) = current_time + initial_backoff_millis * num_failures, num_failures >= 1
JobInfo.BACKOFF_POLICY_EXPONENTIAL:指数重试方案
公式为:retry_time(current_time, num_failures) = current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1
-----------------------------
Uri uri = Uri.parse("content://com.test.aaa/ccc");
ClipData clipData = ClipData.newUri(getContentResolver(), "URI", uri); // 将URI数据放到ClipData中
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setClipData(clipData, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
setClipData的主要目的是将剪切板数据授予URI权限。
setClipData的第二个参数为权限,这个权限只对URI数据有效(ClipData可以存储`字符串`、`Intent`、`URI`)。
第二个参数可以指定的权限有:FLAG_GRANT_READ_URI_PERMISSION、FLAG_GRANT_WRITE_URI_PERMISSION、FLAG_GRANT_PERSISTABLE_URI_PERMISSION、FLAG_GRANT_PREFIX_URI_PERMISSION
FLAG_GRANT_READ_URI_PERMISSION:URI读权限
FLAG_GRANT_WRITE_URI_PERMISSION:URI写权限
FLAG_GRANT_PERSISTABLE_URI_PERMISSION:URI权限授予可以坚持在设备重新启动直到明确撤销,用revokeuripermission
FLAG_GRANT_PREFIX_URI_PERMISSION:URI权限授予适用于任何前缀匹配不同于原始的授予的URI
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
builder.setEstimatedNetworkBytes(1000, 1000);
}
设置此作业将执行的网络流量的估计大小,单位为字节。
请注意,当设备的网络连接较差时,系统可能会选择使用较大的网络使用量估计来延迟作业,以节省电池和可能的网络成本。
-----------------------------
if (Build.VERSION.SDK_INT >= 31) {
builder.setExpedited(true);
}
setExpedited是Android 12(API 31)新增接口,如果设置为true,说明Job比较重要,需要加速执行。
-----------------------------
PersistableBundle extras = new PersistableBundle();
extras.putString("name", "value");
builder.setExtras(extras);
设置持久化数据,可以通过 `builder.build().getExtras()` 获取。
-----------------------------
builder.setPeriodic(1000);
设置周期时间,可以任意设置周期的时间,当前设置的是1000毫秒,每1秒执行一次Job。
`setPeriodic` 与 `setMinimumLatency` 、 `setOverrideDeadline` 冲突,不能同时存在。
在Android 7.0(API 24)开始,新增接口如下:
public Builder setPeriodic(long intervalMillis, long flexMillis)
intervalMillis是周期时间,flexMillis为弹性时间,并且将intervalMillis的最小时间设定为15分钟,将flexMillis的最小时间设定为5分钟。
Android 7.0(API 24)开始,如果您设置的周期时间小于15分钟,就默认设置为15分钟;如果您设置的弹性时间小于5分钟,就默认为5分钟。
-----------------------------
builder.setPersisted(true);
设置是否跨设备重新启动来持久化此作业。
如果为true,表示作业将被写入到磁盘,并在启动时加载。
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
builder.setPrefetch(true);
}
Android 9.0(API 28)新增接口。
将此值设置为true表示此Job旨在预取内容,以改善该设备的特定用户的体验。
例如,获取当前用户感兴趣的头条。
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
builder.setRequiredNetwork(NetworkRequest networkRequest);
}
设置一个网络请求对象,Android 9.0(API 28)新增接口。
-----------------------------
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE);
设置网络类型,可以设置的网络类型有
NETWORK_TYPE_NONE:无网络或者有网络的时候执行Job
NETWORK_TYPE_ANY:执行Job需要网络连接(无网络不执行)
NETWORK_TYPE_UNMETERED:执行Job需要未设置按流量计费的网络连接(按流量计费的网络:连接到此网络时,
某些应用可能具有不同的功能以减少数据使用,可以设置流量上限,以帮助控制在此网络上的数据使用量)
NETWORK_TYPE_NOT_ROAMING:执行Job需要未漫游的网络连接
NETWORK_TYPE_CELLULAR:执行Job需要蜂窝网络连接(蜂窝网络又称移动网络)
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setRequiresBatteryNotLow(true);
}
指定要运行此作业,设备的电池电量不能很低。
默认为false。如果为true,该作业只会在电池电量不低时运行,这通常是用户得到电池电量不足警告的点。
-----------------------------
builder.setRequiresCharging(true);
如果为true,执行此作业,设备必须是充电状态(或是连接到永久电源的非电池供电设备,如安卓电视设备)。
默认为false。
-----------------------------
builder.setRequiresDeviceIdle(true);
设置为true时,如果设备处于活动使用状态,此作业不会运行,当设备处于空闲状态时,会执行此作业。
默认状态是false,也就是说,即使有人在与设备交互,作业也可以运行。
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setRequiresStorageNotLow(true);
}
指定要运行此作业,设备的可用存储空间不能很低。
默认为false。
如果为true,则该作业将只在设备不处于低存储状态时运行,这通常是向用户提供低存储警告的点。
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Bundle bundle = new Bundle();
bundle.putString("key", "value");
builder.setTransientExtras(bundle);
}
设置临时数据(非持久化数据)
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.addTriggerContentUri(uri);
}
监听uri对应的数据发生改变,就会触发任务的执行。
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setTriggerContentMaxDelay(long duration);
}
设置Content发生变化一直到任务被执行中间的最大延迟时间
-----------------------------
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setTriggerContentUpdateDelay(long duration);
}
设置Content发生变化一直到任务被执行中间的延迟。如果在这个延迟时间内content发生了改变,延迟时间会重写计算。
三、Job的执行和结束
Job被执行时,JobService
的onStartJob
就会被执行,onStartJob
中执行任务,这个任务可能是耗时的,可以将耗时任务放在另一个线程执行。
onStartJob是有返回值的。
如果为false,那么说明Job执行完毕。
如果为true,说明Job还没有执行完成,此时的任务是放在另一个线程执行的耗时任务,当这个耗时任务执行完成时,应该主动jobFinished
方法,告诉系统该Job已经执行完成。
当执行 jobScheduler.cancel
或者 jobScheduler.cancelAll
时,并且该Job还没有执行完,那么 onStopJob
方法被执行。
onStopJob
的返回值如果为false时,表示不需要重试,为true时,表示需要重试。
[本章完...]
网友评论