介绍
这是一个API,用于根据将在应用程序自己的进程中执行的框架计划各种类型的作业,该工具集成了常见的几种运行条件,开发者只需添加少数几行代码,即可完成原来要多种组件配合的工作。
概要
- 常数:RESULT_FAILURE(失败int0)、RESULT_SUCCESS(成功int1)
- 公共建设者:JobScheduler()
- 公开方法:cancel(int jobId)取消指定的作业、cancelAll()取消调用应用程序安排的所有作业、enqueue(JobInfo job, JobWorkItem work)与相似schedule(JobInfo),但允许您将工作加入新工作或现有 工作、getAllPendingJobs()检索由调用应用程序安排的所有作业、getPendingJob(int jobId)检索由调用应用程序安排的所有作业、schedule(JobInfo job)计划要执行的作业。
- 继承的方法(继承自Object):
官方Demo详解
清单文件。
<manifest>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application>
<service
android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/>
</application>
</manifest>
MyJobService.java
public class MyJobService extends JobService {
private static final String TAG = MyJobService.class.getSimpleName();
private Messenger mActivityMessenger;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "服务已创建");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "服务已销毁");
}
/**
* 创建应用程序的MainActivity时,它将启动此服务. 这样活动和服务就可以来回通信. See "setUiCallback()"
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mActivityMessenger = intent.getParcelableExtra(MESSENGER_INTENT_KEY);
return START_NOT_STICKY;
}
@Override
public boolean onStartJob(final JobParameters params) {
// 这个服务“做”的工作只是等待一段时间然后完成
// 作业(在另一个线程上)。
sendMessage(MSG_COLOR_START, params.getJobId());
long duration = params.getExtras().getLong(WORK_DURATION_KEY);
// 使用处理程序延迟jobFinished()的执行。
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
sendMessage(MSG_COLOR_STOP, params.getJobId());
jobFinished(params, false);
}
}, duration);
Log.i(TAG, "on start job: " + params.getJobId());
// 返回真的,因为有更多的工作要做这项工作。
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
// 停止跟踪这些作业参数,因为我们已“完成”执行。
sendMessage(MSG_COLOR_STOP, params.getJobId());
Log.i(TAG, "停止工作: " + params.getJobId());
// Return false放弃工作。
return false;
}
private void sendMessage(int message, @Nullable Object params) {
// 如果此服务是由JobScheduler启动的,则不存在回调Messenger。它
// 仅当MainActivity使用Intent中的回调调用startService()时才存在。
if (mActivityMessenger == null) {
Log.d(TAG, "服务已绑定,未启动。没有要向其发送消息的回调.");
return;
}
Message m = Message.obtain();
m.what = message;
m.obj = params;
try {
mActivityMessenger.send(m);
} catch (RemoteException e) {
Log.e(TAG, "将服务对象传递回活动时出错.");
}
}
}
activity下的使用
//定义
public static final int MSG_UNCOLOR_START = 0;
public static final int MSG_UNCOLOR_STOP = 1;
public static final int MSG_COLOR_START = 2;
public static final int MSG_COLOR_STOP = 3;
public static final String MESSENGER_INTENT_KEY= BuildConfig.APPLICATION_ID + ".MESSENGER_INTENT_KEY";//进程通讯
public static final String WORK_DURATION_KEY =BuildConfig.APPLICATION_ID + ".WORK_DURATION_KEY";//工作时间
private ComponentName mServiceComponent;//MyJobService的启动
private int mJobId = 0;//任务数量
private IncomingMessageHandler mHandler;//Handler
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...布局加载
mServiceComponent = new ComponentName(this, MyJobService.class);
mHandler = new IncomingMessageHandler(this);
}
// 启动服务并为其提供与此类通信的方式。
@Override
protected void onStart() {
super.onStart();
Intent startServiceIntent = new Intent(this, MyJobService.class);
Messenger messengerIncoming = new Messenger(mHandler);
startServiceIntent.putExtra(MESSENGER_INTENT_KEY, messengerIncoming);
startService(startServiceIntent);
}
// 服务可以“启动”和或“绑定”. 在本例中,它由该活动“启动”并“绑定”到JobScheduler(也被JobScheduler称为“调度”)。对stopService()的调用不会阻止处理计划的作业。但是,未能调用stopService()将使它无限期地保持活动状态。
@Override
protected void onStop() {
stopService(new Intent(this, MyJobService.class));
super.onStop();
}
/**
* 当用户单击计划作业时执行。
*/
private void scheduleJob(){
JobInfo.Builder builder = new JobInfo.Builder(mJobId++, mServiceComponent);
String delay = mDelayEditText.getText().toString();//延迟时机:默认0
if (!TextUtils.isEmpty(delay)) {
//设置至少延迟多久后执行,单位毫秒.
builder.setMinimumLatency(Long.parseLong(delay) * 1000);
}
String deadline = mDeadlineEditText.getText().toString();//延迟截止日期:默认15
if (!TextUtils.isEmpty(deadline)) {
//设置最多延迟多久后执行,单位毫秒。
builder.setOverrideDeadline(Long.parseLong(deadline) * 1000);
}
boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked();//连通性WIFI
boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked();//连通性任何默认任何
if (requiresUnmetered) {
//设置需要的网络条件,有三个取值:
//JobInfo.NETWORK_TYPE_NONE(无网络时执行,默认)、
//JobInfo.NETWORK_TYPE_ANY(有网络时执行)、
//JobInfo.NETWORK_TYPE_UNMETERED(网络无需付费时执行)
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
} else if (requiresAnyConnectivity) {
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
}
//是否在空闲时执行
builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked());//闲置:默认不需要插入设备
//是否在充电时执行
builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked());//充电:默认充电为不需要插入设备
// 额外费用,工作时间。
PersistableBundle extras = new PersistableBundle();
String workDuration = mDurationTimeEditText.getText().toString();
if (TextUtils.isEmpty(workDuration)) {
workDuration = "1";
}
extras.putLong(WORK_DURATION_KEY, Long.parseLong(workDuration) * 1000);
builder.setExtras(extras);
// 计划作业
Log.d(TAG, "调度作业");
JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
tm.schedule(builder.build());
}
/**
*完成最后一个任务
*/
private void finishJob() {
JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
List<JobInfo> allPendingJobs = jobScheduler.getAllPendingJobs();
if (allPendingJobs.size() > 0) {
// 完成最后一个
int jobId = allPendingJobs.get(0).getId();
jobScheduler.cancel(jobId);
Toast.makeText(MainActivity.this, String.format("取消的作业 %d", jobId), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "没有要取消的作业", Toast.LENGTH_SHORT).show();
}
}
/**
*取消全部任务
*/
private void cancelAllJobs(){
JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
tm.cancelAll();
}
/**
* 处理程序允许您发送与线程关联的消息.Messenger使用此处理程序从MyJobService进行通信. 它还用于使start和stop视图在短时间内闪烁。
*/
private static class IncomingMessageHandler extends Handler {
// 用弱参考防止可能的泄漏。
private final WeakReference<MainActivity> mActivity;
IncomingMessageHandler(MainActivity activity) {
super(/* default looper */);
this.mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity mainActivity = mActivity.get();
if (mainActivity == null) {
// 活动不再可用,请退出。
return;
}
View showStartView = mainActivity.findViewById(R.id.onstart_textview);
View showStopView = mainActivity.findViewById(R.id.onstop_textview);
Message m;
switch (msg.what) {
case MSG_COLOR_START://当作业到达应用程序时,接收来自服务的回调。打开指示灯并在一秒钟后发送消息将其关闭。
// 开始接收,打开指示灯并显示文本。
showStartView.setBackgroundColor(getColor(R.color.start_received));
updateParamsTextView(msg.obj, "started");
// 一秒钟后发送消息将其关闭。
m = Message.obtain(this, MSG_UNCOLOR_START);
sendMessageDelayed(m, 1000L);
break;
case MSG_COLOR_STOP://当以前降落在应用程序上的作业必须停止执行时,接收来自服务的回调。打开指示灯,并在两秒钟后发送消息将其关闭。
// 停止接收,打开指示灯并显示文本。
showStopView.setBackgroundColor(getColor(R.color.stop_received));
updateParamsTextView(msg.obj, "stopped");
// 一秒钟后发送消息将其关闭。
m = obtainMessage(MSG_UNCOLOR_STOP);
sendMessageDelayed(m, 2000L);
break;
case MSG_UNCOLOR_START:
showStartView.setBackgroundColor(getColor(R.color.none_received));
updateParamsTextView(null, "");
break;
case MSG_UNCOLOR_STOP:
showStopView.setBackgroundColor(getColor(R.color.none_received));
updateParamsTextView(null, "");
break;
default:
break;
}
}
private void updateParamsTextView(@Nullable Object jobId, String action) {
TextView paramsTextView = (TextView) mActivity.get().findViewById(R.id.task_params);
if (jobId == null) {
paramsTextView.setText("");
return;
}
String jobIdText = String.valueOf(jobId);
paramsTextView.setText(String.format("Job ID %s %s", jobIdText, action));
}
private int getColor(@ColorRes int color) {
return mActivity.get().getResources().getColor(color);
}
}
- setRequiredNetworkType:设置需要的网络条件,有三个取值:JobInfo.NETWORK_TYPE_NONE(无网络时执行,默认)、JobInfo.NETWORK_TYPE_ANY(有网络时执行)、JobInfo.NETWORK_TYPE_UNMETERED(网络无需付费时执行)
setPersisted:重启后是否还要继续执行,此时需要声明权限RECEIVE_BOOT_COMPLETED,否则会报错“java.lang.IllegalArgumentException: Error: requested job be persisted without holding RECEIVE_BOOT_COMPLETED permission.”而且RECEIVE_BOOT_COMPLETED需要在安装的时候就要声明,如果一开始没声明,而在升级时才声明,那么依然会报权限不足的错误。 - etRequiresCharging:是否在充电时执行
- setRequiresDeviceIdle:是否在空闲时执行
- setPeriodic:设置时间间隔,单位毫秒。该方法不能和
- setMinimumLatency、setOverrideDeadline这两个同时调用,否则会报错“java.lang.IllegalArgumentException: Can’t call 6. setMinimumLatency() on a periodic job”,或者报错“java.lang.IllegalArgumentException: Can’t call setOverrideDeadline() on a periodic job”。
- setMinimumLatency:设置至少延迟多久后执行,单位毫秒。
- setOverrideDeadline:设置最多延迟多久后执行,单位毫秒。
- setBackoffCriteria: 退避策略 , 可以设置等待时间以及重连策略
- build:完成条件设置,返回构建好的JobInfo对象。
声明MyJobService并将jobinfo加入, 执行
就是上面代码的最后两句了, 这里也可以看到JobScheduler 的本质其实就是系统的服务。