主目录见::Android高级进阶知识(这是总目录索引)
[译]Using the JobScheduler API on Android Lollipop
谷歌官网的例子:JobScheduler
今天还是打算以上面一篇英文文章为基础,同时你也可以参考谷歌官网的JobScheduler例子来了解它的使用方式。JobScheduler作为系统服务的形式出现,任务的调配统一由系统在特定的条件下进行协调,是android 5.0及之后一个相对于AlarmManager+wakeLock而言比较节能的方案,也是谷歌推荐的一个做法。
一.目标
这篇文章作为电量优化的一个方案出现,我们有理由去了解怎么使用它还有它的原理,今天我们目标是:
1.了解JobScheduler的使用方法;
2.能在实际场景中使用JobScheduler。
二.JobScheduler
这篇教程里面,你将学会如何在 Android Lollipop中使用JobScheduler API
,JobScheduler
的API允许开发者在条件满足的情况下创建一些后台任务。
介绍
在Android开发中,在某些场景中,你可能希望在之后的某个时间节点或者在某些条件下执行你的任务,比如你的设备正在充电的情况下或者连到wifi网络的情况下。幸亏有了Android 21也就是Android Lollipop,谷歌提供了一个新的组件JobScheduler
来满足这些场景。
当一系列的前置条件被满足之后,JobScheduler API
就会执行你应用的某个操作。跟AlarmManager
不同的是,它的执行时间是不确定的。另外,JobScheduler API
会将任务打包一起执行。这允许你的应用执行某项任务的时候不需要考虑时间控制引起的电量消耗。
这篇文章中,你将通过执行一个简单的后台任务来学习更多关于JobScheduler API
和JobService
类的知识。这篇文章里面涉及的代码见GITHUB.
1.创建Job Service
首先,你需要创建一个基于最低版本为Android 21的Android工程,因为JobScheduler API
是在最新Android版本才被添加进来的,而且在写这篇文章的时候,还没有向后兼容的support 库。
这里假设你用的是Android Studio,当你点击完成创建新的工程,你将得到一个"Hello World"应用的骨架。第一步要做的就是你要在这个工程基础上创建一个新的Java 类。为了尽可能简单,这里就把这个类命名为JobSchedulerService
继承于JobService
类,而且需要创建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)
是用在任务开始执行的时候,因为这是系统用来触发已经计划执行的任务。你可以看到,这个方法返回一个boolean类型的值。如果你返回的是false
,那么系统就会认为要执行的任务耗费的时长不长,且在方法返回的时候已经完成了。如果返回的是true
,那么系统会认为要执行的任务需要的时长比较长,执行任务的重担也会落在你的身上,开发者就必须通过jobFinished(JobParameters params, boolean needsRescheduled)
方法来告诉系统你的任务是什么时候结束的。
当系统接收到cancel 的请求,那么onStopJob(JobParameters params)
方法就会被用来取消正在等待执行的任务。需要注意的是当onStartJob(JobParameters params)
方法返回为false
的时候,当接收到cancel 请求的时候,系统会任务当前没有任务正在执行,换句话说就是,onStopJob(JobParameters params)
不会被调用。
有一点需要特别注意的是你的 job service 是运行在主线程的,这就意味着你必须使用另外的线程,或者Handler,或者一个异步任务来执行耗时长的任务以避免阻塞主线程。因为多线程已经超出本教程的范围了,所以我们在JobSchedulerService
类中就简单地用一个Handler来执行我们的任务。
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)
方法并且在方法里执行你的代码逻辑。在这个例子中,我们尽量保持简单,只是弹出了一个Toast
消息,这个地方也就是你放自己代码逻辑的地方,比如同步数据。
当任务完成,你必须调用jobFinished(JobParameters params, boolean needsRescheduled)
来通知系统你已经完成了任务的执行并且可以执行下一个操作了。如果你不这么做的话,那么你的任务就会执行一次并且应用不会被允许执行额外的任务。
jobFinished(JobParameters params, boolean needsRescheduled)
方法中的两个参数,第一个参数JobParameters
是从JobService
类中的onStartJob(JobParameters params)
方法传递过来的,第二个参数的boolean值是让系统知道是否在原有的条件下重新执行任务。理解这个boolean值是很有用的,因为他决定了在某些情况下任务不能被执行完成应该怎么处理,比如网络请求失败。
当Handler
实例被创建, 你就可以继续实现onStartJob(JobParameters params)
方法和onStopJob(JobParameters params)
方法来控制你的任务。你会注意到,下面代码片段里onStartJob(JobParameters params)
方法返回了true
,这是因为你将使用Handler
实例来控制你的操作,也就意味着代码逻辑的执行会超过onStartJob(JobParameters params)
的结束。通过返回true
,你就可以让系统知道,你会自己调用jobFinished(JobParameters params, boolean needsRescheduled)
方法来结束任务。同时你注意到数字1被传递给Handler
实例,这是你用来标识任务的标记。
@Override
public boolean onStartJob(JobParameters params) {
mJobHandler.sendMessage( Message.obtain( mJobHandler, 1, params ) );
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
mJobHandler.removeMessages( 1 );
return false;
}
一旦完成了JobSchedulerService
类的java部分,你就必须在AndroidManifest.xml
中添加一个service节点来使你的应用有权限来绑定(bind)和使用(use)JobService
这个类。
2.创建Job Scheduler
当编写完JobSchedulerService
类之后,我们就可以来看你的应用是怎么和JobScheduler API
进行交互的,第一件事就是创建一个叫做mJobScheduler
的 JobScheduler
对象,并且通过获取系统服务JOB_SCHEDULER_SERVICE
来初始化它。 在例子里面,这步操作写在MainActivity
中。
mJobScheduler = (JobScheduler)
getSystemService( Context.JOB_SCHEDULER_SERVICE );
当你想要创建你的计划任务的时候,你必须通过JobInfo.Builder
来构建你的JobInfo
对象,然后传给你的JobScheduler
服务。为了创建JobInfo
对象,JobInfo.Builder
接收两个参数,第一个参数是为了标识你的任务的,第二个参数是service的组件名字(component name)。
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
方法返回一个integer,如果方法执行失败,方法就会返回0或者小于0的数, 如果执行成功的话,那么就会返回JobInfo.Builder
中设置的任务的唯一标识。
如果你要停止特定的一个任务或者所有的任务,你可以调用JobScheduler
对象中的cancel(int jobId)
方法和cancelAll()
方法:
mJobScheduler.cancelAll();
到这里,你应该会使用JobScheduler
API来批量执行你的任务和一些后台任务了。
总结
这篇文章中,你已经学会了如何实现JobService
的子类和用Handler
对象来执行一个后台任务了。而且你也学会了用JobInfo.Builder
来设置一些执行条件来决定任务的执行与否。掌握了这些之后,你就可以减少你应用程序执行所消耗的电量。