Android优化 —— JobScheduler

来源:互联网 发布:统计分析软件r 编辑:程序博客网 时间:2024/04/30 01:29

概述

在Android开发中,会遇到这种场景 : 需要在稍后的某个时间点或者当满足某个特定的条件时执行一个任务,例如当设备接通电源适配器或者连接到WIFI。幸运的是在API 21 ( Android 5.0,即Lollipop )中,google提供了一个新叫做JobScheduler的组件来处理这样的场景。

当一系列预置的条件被满足时,JobScheduler为应用执行一个操作,与AlarmManager不同的是这个执行时间是不确定的。除此之外,JobScheduler允许同时执行多个任务,这允许应用执行某些指定的任务时不需要考虑时机控制引起的电池消耗。

创建JobService

首先,需要创建一个API最低为21的Android项目,因为JobScheduler是最近的版本才加入Android的,目前它还没有兼容库支持。

当使用Android Studio创建了项目之后,会得到一个”Hello World”的应用骨架。这时要做的第一步就是创建一个新的java类。为了简单起见,假定创建一个继承自JobService且名字为 JobSchedulerService的类,这个类必须实现两个方法,分别是onStartJob(JobParameters params)onStopJob(JobParameters params)

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

当任务开始时会执行onStartJob(JobParameters params)方法,因为这是系统用来触发已经被执行的任务。不难看出,这个方法返回一个布尔值。如果返回值是false,系统就会判定这个方法已经执行完毕;如果返回值是 true,那么系统就会判定这个方法正要被执行,而方法的具体实现就需要开发者自己去实现了,当方法执行完毕时则需要调用jobFinished(JobParameters params, boolean needsRescheduled)来通知系统。

当系统接收到一个取消请求时,系统会调用onStopJob(JobParameters params)方法取消正在等待执行的任务。很重要的一点是如果onStartJob(JobParameters params)返回false,那么系统假定在接收到一个取消请求时已经没有正在运行的任务。换句话说,onStopJob(JobParameters params)在这种情况下不会被调用。

需要注意的是这个JobService运行在主线程,这意味着需要使用子线程、Handler或者一个异步任务来运行耗时的操作以防止阻塞主线程。因为多线程技术已经超出了这篇文章的范围,这里就简单实现一个Handlder来执行JobSchedulerService中定义的任务。

private Handler mJobHandler = new Handler( new Handler.Callback() {    @Override    public boolean handleMessage( Message msg ) {        Toast.makeText( getApplicationContext(),             "JobService task running", Toast.LENGTH_SHORT )            .show();        jobFinished( (JobParameters) msg.obj, false );        return true;    }} );

Handler中,需要实现handleMessage(Message msg)方法来处理任务逻辑。在这个例子中,为了尽量保证例子简单,因此只在handleMessage(Message msg)中显示了一个Toast,这里就是开发者需要自己去实现任务逻辑(比如耗时操作等)的地方。

当任务执行完毕之后,需要调用jobFinished(JobParameters params, boolean needsRescheduled)来让系统知道这个任务已经结束,系统可以将下一个任务添加到队列中。如果没有调用jobFinished(JobParameters params, boolean needsRescheduled),则任务只会执行一次,而应用中的其他任务就不会被执行。

jobFinished(JobParameters params, boolean needsRescheduled)的两个参数中的params参数是从JobServiceonStartJob(JobParameters params)的params传递过来的,needsRescheduled参数是让系统知道这个任务是否应该在最初的条件下被重复执行。这个布尔值很有用,因为它指明了如何处理由于其他原因导致任务执行失败的情况,例如一个失败的网络请求调用。

创建了Handler实例之后,就可以实现onStartJob(JobParameters params)onStopJob(JobParameters params)方法来控制任务了。在下面的代码片段中onStartJob(JobParameters params)返回了true,这是因为需要通过Handler实例来控制自定义操作,这意味着handleMessage(Message msg)的执行时间可能比onStartJob(JobParameters params)更长。返回true,则会让系统知道开发者会手动地调用jobFinished(JobParameters params, boolean needsRescheduled)方法。

@Overridepublic boolean onStartJob(JobParameters params) {    mJobHandler.sendMessage( Message.obtain( mJobHandler, 1, params ) );    return true;}@Overridepublic boolean onStopJob(JobParameters params) {    mJobHandler.removeMessages( 1 );    return false;}

一旦在Java部分做了上述工作之后,就需要到AndroidManifest.xml中添加一个service节点让应用拥有绑定和使用这个JobService的权限。

<service android:name=".JobSchedulerService"    android:permission="android.permission.BIND_JOB_SERVICE" />

创建一个JobScheduler对象

随着JobSchedulerService构建完毕,接下来需要研究应用如何与JobScheduler进行交互的。第一件要做的事就是需要创建一个JobScheduler对象,在实例代码的MainActivity中通过getSystemService( Context.JOB_SCHEDULER_SERVICE )初始化了一个叫做mJobScheduler的JobScheduler对象。

mJobScheduler = (JobScheduler)     getSystemService( Context.JOB_SCHEDULER_SERVICE );

当开发者想要创建一个定时任务时,可以使用JobInfo.Builder来构建一个JobInfo对象,然后传递给ServiceJobInfo.Builder接收两个参数,第一个参数是要运行的任务的标识符,第二个是这个Service组件的类名。

JobInfo.Builder builder = new JobInfo.Builder( 1,        new ComponentName( getPackageName(),             JobSchedulerService.class.getName() ) );

这个builder允许开发者设置很多不同的选项来控制任务的执行。下面的代码片段就是展示了如何设置以使得任务可以每隔三秒运行一次。

builder.setPeriodic(3000);

其它设置方法 :

  • setMinimumLatency(long minLatencyMillis):这个函数能设置任务的延迟执行时间(单位是毫秒),这个函数与setPeriodic(long time)方法不兼容,如果这两个方法同时调用了就会引起异常

  • setOverrideDeadline(long maxExecutionDelayMillis)
    这个方法可以设置任务最晚的延迟时间。如果到了规定的时间时其他条件还未满足,则任务也会被启动。与setMinimumLatency(long time)一样,这个方法也会与setPeriodic(long time),同时调用这两个方法会引发异常

  • setPersisted(boolean isPersisted)
    这个方法告诉系统当设备重启之后任务是否还要继续执行。

  • setRequiredNetworkType(int networkType)
    这个方法让任务只有在满足指定的网络条件时才会被执行。默认条件是JobInfo.NETWORK_TYPE_NONE,这意味着不管是否有网络这个任务都会被执行;另外两个可选类型,一种是JobInfo.NETWORK_TYPE_ANY,它表明需要任意一种网络才使得任务可以执行;另一种是 JobInfo.NETWORK_TYPE_UNMETERED,它表示设备不是蜂窝网络(比如在WIFI连接时)时任务才会被执行

  • setRequiresCharging(boolean requiresCharging)
    这个方法告诉应用,只有当设备在充电时这个任务才会被执行

  • setRequiresDeviceIdle(boolean requiresDeviceIdle)
    这个方法告诉任务只有当用户没有在使用该设备且有一段时间没有使用时才会启动该任务

需要注意的是setRequiredNetworkType(int networkType)setRequiresCharging(boolean requireCharging)setRequiresDeviceIdle(boolean requireIdle)这几个方法可能会使得任务无法执行,除非调用setOverrideDeadline(long time)设置了最大延迟时间,使得任务在未满足条件的情况下也会被执行。一旦预置的条件被设置,就可以构建一个JobInfo对象,然后通过如下所示的代码将它发送到JobScheduler中。

if( mJobScheduler.schedule( builder.build() ) <= 0 ) {    //If something goes wrong}

不难发现,这个schedule方法会返回一个整型。如果schedule方法失败了,它会返回一个小于0的错误码。否则它会返回在JobInfo.Builder中定义的标识id。

如果应用想停止某个任务,可以调用JobScheduler对象的cancel(int jobId)来实现;如果想取消所有的任务,则可以调用JobScheduler对象的cancelAll()来实现。

mJobScheduler.cancelAll();

到了这里,现在应该已经知道如何在应用中使用JobScheduler来执行批量任务和后台操作了。

参考链接
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0403/2685.html

0 0