从Google Play要求所有应用最低的目标sdk版本为26开始,更改后台服务就被提上了日程。官方推荐的是使用JobScheduler,它可以根据指定的各种条件,更好的为用户处理网络相关的作业。当声明的条件满足时,由系统在应用进程中执行该工作。
JobScheduler+JobInfo+JobService
JobScheduler主要负责任务调度。JobInfo描述了任务的概要信息,传递给JobScheduler完全封装调度应用程序调度工作所需参数的数据容器。JobService则用来处理任务。JobScheduler是在API21中才有的,所以使用JobScheduler需要添加判断,在API>=21的时候,选择使用JobService的方式启动服务。具体的一些方法说明可以查阅官方文档,这里主要说明具体的用法。
创建JobInfo
/**
* 创建jobInfo
* @param jobId 任务的标识符 唯一
* @param componentName jobService类
* @param requestInterval 请求间隔
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public JobInfo buildJobInfo(int jobId, ComponentName componentName, long requestInterval)
{
//代表一个任务 使用建造者模式建造
JobInfo jobInfo;
// Android7上,设置周期执行时间,会强制按照getMinPeriodMills阈值执行,此时设置任务执行最小时间间隔解决该问题
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
{
android.util.Log.d("jobService", "buildJobInfo: minimum");
jobInfo = new JobInfo.Builder(jobId,componentName)
.setBackoffCriteria(requestInterval,JobInfo.BACKOFF_POLICY_LINEAR)//设置线性重试策略
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) //设置网络类型
.setMinimumLatency(requestInterval) //设置最小执行间隔
.setOverrideDeadline(requestInterval)//设置任务执行的最晚延迟时间
.setPersisted(true)//设置重启后任务是否保留
.build();
}else {
android.util.Log.d("jobService", "buildJobInfo: periodic");
jobInfo = new JobInfo.Builder(jobId, componentName)
.setBackoffCriteria(requestInterval, JobInfo.BACKOFF_POLICY_LINEAR)//设置线性重试策略
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) //设置网络类型
.setPeriodic(requestInterval) //设置执行周期
.setPersisted(true)//设置重启后任务是否保留
.build();
}
return jobInfo;
}
setBackoffCriteria
(long initialBackoffMillis, int backoffPolicy)设置后退/重试策略。
两种可选策略:
BACKOFF_POLICY_EXPONENTIAL: 时间呈指数形式增长,默认值。
BACKOFF_POLICY_LINEAR:时间呈线性形式增长setMinimumLatency
(long interval)设置最小的延迟时间和setOverrideDeadline
(long interval)设置最大延迟时间,这两个方法不能和setPeriodic
(long interval)一起使用
JobScheduler调度
/**
* 调度JobService
*/
public void scheduleJobService(long requestInterval)
{
ComponentName jobName = new ComponentName(mMyAppliction,
MonitorJobService.class);
JobInfo jobInfo = buildJobInfo(JOB_HIGH_ID, highJobName,
requestInterval);
if (mJobScheduler != null) {
mJobScheduler.schedule(jobInfo);
}
}
/**
* 通过jobId取消对应的JobService
* @param jobId
*/
public void cancelJobServiceById(int jobId)
{
if(mJobScheduler != null)
{
android.util.Log.d("jobService", "cancelJobServiceById: " + jobId);
mJobScheduler.cancel(jobId);
//mJobScheduler.cancelAll()取消所有正在运行的服务
}
}
实现JobService类
public class MonitorJobService extends JobService {
/**
* @param params Parameters specifying info about this job, including the extras bundle you
* optionally provided at job-creation time.
* @return True if your service needs to process the work (on a separate thread). False if
* there's no more work to be done for this job.
*/
@Override
public boolean onStartJob(JobParameters params) {
android.util.Log.d(TAG, "onStartJob: start");
//在这里写处理逻辑的代码,如果需要做耗时处理则需要开启线程,在线程中做处理
new MonitorAsyncTask().execute(params);
//返回true说明工作还未完成,工作完成后需要通过JobFinished方法来通知系统
return true;
}
/**
* @param params Parameters specifying info about this job.
* @return True to indicate to the JobManager whether you'd like to reschedule this job based
* on the retry criteria provided at job creation-time. False to drop the job. Regardless of
* the value returned, your job must stop executing.
*/
@Override
public boolean onStopJob(JobParameters params) {
android.util.Log.d(TAG, "onStopJob: running");
return false;
}
//AsyncTask处理耗时操作
private class MonitorAsyncTask extends AsyncTask<JobParameters,Void,String>{
private JobParameters mJobParameters;
/**
*
* @param jobParameters The parameters of the task.
* @return A result, defined by the subclass of this task.
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
@Override
protected String doInBackground(JobParameters... jobParameters) {
android.util.Log.d(TAG, "doInBackground: running");
mJobParameters = jobParameters[0];
//耗时操作
return null;
}
//完成之后的处理工作
@Override
protected void onPostExecute(String s) {
android.util.Log.d(TAG, "onPostExecute: running");
super.onPostExecute(s);
//如果不调用此方法,任务只会执行一次
jobFinished(mJobParameters,false);
}
}
}
JobFinished
(JobParameter params,boolean needsReschedule)
params:指定系统提供的有关此作业的信息,指向onStartJob(JobParameters)中的params.
needsReschedue:返回true表示工作应该根据选定的重试策略(在创建JobInfo时指定的BACK_OFF_POLICY,返回false,则不需要。
最后,不要忘记在AndroidManifest.xml文件对应jobService声明中添加BIND_JOB_SERVICE
的权限
<service
android:name=".service.MonitorJobServiceNormal"
android:enabled="true"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
其他方法及优秀的库推荐
JobIntentService
,JobScheduler,JobInfo,JobService的一套机制是比较繁琐的,而且只在API21上有用。所以官方又推出了JobIntentService来帮助我们简化步骤,实现兼容。Android8.0以上被当做普通的Intent使用startService()启动service来执行,8.0以上则用来作为Job来执行。但是复杂也有复杂的好处,我们可以指定service的相关条件,所有根据条件决定到底使用哪种方式。FireBase JobScheduler
:https://github.com/firebase/firebase-jobdispatcher-android
github上封装好的一个库,兼容到API14,但是需要Google Play的支持,比较适合国外开发的app使用。evernote/android-job
:https://github.com/evernote/android-job
同样的封装好的一个库,兼容到API14,不需要Google play的支持。