JobScheduler之晕头转向

This is an API for scheduling various types of jobs against the framework that will be executed in your application's own process.
这是官方API对JobSchedule的解释,在你自己应用程序进程中对各种类型作业进行调度。这么说大概大家脑海里面有那么点感觉了吧,好比线程池的调度或者AlarmManager的使用等。那既然java里面或者原先android里面就已经有作业调度,为什么Google又推出JobSchedule?

官方文档在描述这个框架的时候,特意介绍了一个场景:若你不指定作业运行截止时间的话,这个作业会由JobSchedule内部队列决定在哪一个时刻运行。这什么意思呢?简单的来说就是它既可以在某一段时间后执行,又可以在某一个特殊场景下执行,比如充电、网络状态、设备空闲。这样来看线程池或者AlarmManager就不满足上述的需求了,JobSchedule既满足多任务执行的功能,同时也可以降低电池电量的消耗。

整体流程很简单,但是我发现我难以驾驭它。。。我们一步一步的来学习,希望高手能指点一二

创建项目

JobService是android5.0之后才加入的,所以compileSdkVersion一定要21及以上才行

创建Job Service

JobService继承于Service,他是JobScheduler回调的入口点,它的回调方法运行在主线程上。onStartJob(JobParameters)与onStopJob(android.app.job.JobParameters),这2个方法一定要实现。

public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(final JobParameters params) {
        return false;
    }
    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }
}

当作业开始之后,会先执行onStartJob方法。onStartJob的返回值有所区别:
(1) false:框架认为你作业已经执行完毕了,那么下一个作业就立刻展开了
(2) true:框架将作业结束状态交给你去处理。因为我们可能会异步的通过线程等方式去执行工作,这个时间肯定不能放在主线程里面去控制,这时候需要手动调用jobFinished(JobParameters params, boolean needsReschedule)方法去告诉框架作业结束了,其中needsReschedule表示是否重复执行
这边很奇怪,我在编写过程中并没有发现区别在哪里,因为最终都是执行的,还需请高人赐教
当你使用cancel()或者cancelAll()的话会执行onStopJob方法。有个地方要注意,如果你onStartJob返回的是false的话,系统会因为认为工作已经结束而不再产生onStopJob回调
这里我就演示一下消息(Message)的收发过程,使用Messenger也是为了方便Activity与Service是用同一个Handler对象进行数据传输

private void sendMessage(int messageId, JobParameters params) {
    Message message=new Message();
    message.arg1=messageId;
    message.what=params.getJobId();
    message.obj=params.getExtras().getString(MyJobService.WORK_DURATION_KEY);
    try {
        messenger.send(message);
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

看看具体触发的方法,通过onStartCommand将Activity的Messenger传入,作业触发发射MSG_COLOR_START,作业完成发射MSG_COLOR_PROCESS,作业取消发射并结束MSG_COLOR_STOP

public static final String MESSENGER_INTENT_KEY="MESSENGER_INTENT_KEY";
public static final String WORK_DURATION_KEY="WORK_DURATION_KEY";
public static final int MSG_COLOR_START=1;
public static final int MSG_COLOR_PROCESS=3;
public static final int MSG_COLOR_STOP=2;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent!=null) {
        messenger=intent.getParcelableExtra("MESSENGER_INTENT_KEY");
    }
    return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onStartJob(final JobParameters params) {
    sendMessage(MSG_COLOR_START, params);
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            sendMessage(MSG_COLOR_PROCESS, params);
            jobFinished(params, false);
        }
    }, 3000);
    return true;
}
@Override
public boolean onStopJob(JobParameters params) {
    sendMessage(MSG_COLOR_STOP, params);
    return false;
}

至此Service部分完成

权限声明


创建JobScheduler对象进行交互

使用Context.getSystemService(Context.JOB_SCHEDULER_SERVICE)去创建JobScheduler对象。然后使用JobInfo.Builder去配置JobScheduler调度工作的参数

JobScheduler service= (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder=new JobInfo.Builder(10, new ComponentName(getPackageName(), MyJobService.class.getName()));

JobInfo.Builder可配置的参数比较多,我具体罗列一下

  1. setPeriodic 重复执行作业的时间间隔
  2. setExtras 为该作业添加额外参数
  3. setMinimumLatency 设置作业延迟执行的时间,与setPeriodic不可同时执行
  4. setOverrideDeadline 设置作业最大延迟执行时间
  5. setPersisted 设置是否在设备重启之后继续执行作业。这么我发现貌似没有效果
  6. setRequiredNetworkType 设置作业只有在满足指定的网络条件时才会被执行
/** 默认条件,不管是否有网络这个作业都会被执行 */
public static final int NETWORK_TYPE_NONE = 0;
/** 任意一种网络这个作业都会被执行 */
public static final int NETWORK_TYPE_ANY = 1;
/** 不是蜂窝网络( 比如在WIFI连接时 )时作业才会被执行 */
public static final int NETWORK_TYPE_UNMETERED = 2;
/** 不在漫游时作业才会被执行 */
public static final int NETWORK_TYPE_NOT_ROAMING = 3;
  1. setRequiresCharging 设置作业是否在设备充电时才会被执行
  2. setRequiresDeviceIdle 设置作业是否在设备空闲时才会被执行

最后就是运行了

int result=service.schedule(builder.build());

result返回1是成功,0是失败
整个代码是这样的

service= (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
Intent intent=new Intent(this, MyJobService.class);
Messenger messenger=new Messenger(handler);
intent.putExtra(MyJobService.MESSENGER_INTENT_KEY, messenger);
startService(intent);
final Random random=new Random();
addJob(random.nextInt(1000)+100);
new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        addJob(random.nextInt(1000)+100);
    }}, 500);
private void addJob(int jobId) {
    PersistableBundle bundle=new PersistableBundle();
    bundle.putString(MyJobService.WORK_DURATION_KEY, "HELLO");
    JobInfo.Builder builder=new JobInfo.Builder(jobId, new ComponentName(getPackageName(), MyJobService.class.getName()));
//        builder.setPeriodic(3000);
    builder.setMinimumLatency(5000);
//        builder.setOverrideDeadline(OverrideDeadline);
    builder.setExtras(bundle);
    builder.setPersisted(true);
    builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
    int result=service.schedule(builder.build());
    Log.d("MainActivity", "result:" + result);
}

注意这种写法,虽然我没有看源码,但是我想工作入队列这个肯定需要一定时间去处理,如果直接add而不添加一定的延时,那么执行的顺序就不会是依次执行这种排列规则了。并且不同的工作不同的策略也可能产生与之前不同的效果,这边我也有点乱。。。

结果

再来看下终止的过程

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        service.cancelAll();
    }}, 6000);

在第6s的时候终止全部工作,看看运行结果,很明显第5s开始执行工作,第6s产生onStopJob回调,随后就是handler完成。这里可以试着在onStopJob中将onStartJob产生的handler结束,留给读者自行完成。这里由于另外一个工作还没有进行,还在队列中,所以就被直接取消了


JobScheduler之晕头转向_第1张图片
结果

这里我还是建议大家,对不同的工作采取相同的策略,并且添加工作的时候带一点延迟,暂时这样才能达到预期的效果

参考文章

在Android 5.0中使用JobScheduler

你可能感兴趣的:(JobScheduler之晕头转向)