JobScheduler之晕头转向

作者: 皮球二二 | 来源:发表于2017-01-11 17:42 被阅读6042次

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部分完成

权限声明

<service android:name=".service.MyJobService" android:permission="android.permission.BIND_JOB_SERVICE"></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结束,留给读者自行完成。这里由于另外一个工作还没有进行,还在队列中,所以就被直接取消了


结果

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

参考文章

在Android 5.0中使用JobScheduler

相关文章

  • JobScheduler之晕头转向

    This is an API for scheduling various types of jobs again...

  • SparkStreaming源码之JobScheduler

    SparkStreaming源码之JobScheduler篇 首先看下JobScheduler这个类是在什么时候被...

  • JobScheduler

    JobScheduler JobScheduler是Android L(API21)新增的特性,用于定义满足某些条...

  • 从JobScheduler到WorkManager

    JobScheduler介绍 JobScheduler是一个任务调度的类。它与AlarmManager不同的是这个...

  • Android省电的秘密之JobScheduler

    JobScheduler是Android L版本新引入的API,JobScheduler,顾名思义,是用来调度工作...

  • JobScheduler

    什么是jobScheduler jobscheduler是 android 在5.0上针对降低功耗而提出的一种策略...

  • Android上保持Socket长连接

    0.Thanks 性能优化十六之Wake_Lock唤醒锁以及JobScheduler使用安卓 java 判断soc...

  • JobScheduler

    概述 JobScheduler是安卓5.0版本推出的API,允许开发者在符合某些条件时创建执行在后台的任务。在An...

  • JobScheduler

    JobScheduler简介 JobScheduler在api 21被引入,作为一个系统服务,它可以用于统一的调度...

  • jobscheduler精华

    参考源码: JobInfo 以及 JobScheduler

网友评论

  • 刘北袭:您好~我在5.0的机器上测试是没问题的 但是在6.0以上的机器上就没效果了 想问下作者在6.0以上的机器使用jobscheduler 是没有问题的吗?
    皮球二二: @刘北袭 当时测试5s还是3s内收不到
    刘北袭: @r17171709 真实场景我试过了,6.0以上跟7.0的机器如果设置的时间间隔太短的话,系统不一定会准时触发的,但是肯定是会触发,只是时间不知道什么时候,感觉还挺好用
    皮球二二: @刘北袭 这玩意我有点乱,真实场景还没用过

本文标题:JobScheduler之晕头转向

本文链接:https://www.haomeiwen.com/subject/txtlbttx.html