使用AlarmManager、IntentService和PendingIntent相互配合,创走周期性的后台任务,实现一个完全可用的后台服务还需要手动执行以下操作。
计划一个周期性任务
检查周期性任务的运行状态
检查网络是否可用
在实际场景下,还有更多想法需要实现,例如请求失败,是否还需要稍后重试机制。或者是只允许应用使用不限量的网络连接...
在系统控制方面,本章实现的后台服务也存在一些问题,它无法在某种情况停下来,除非手动停止。
JobScheduler:除了实现常规后台任务之外,JobScheduler还支持按场景、按条件运行后台服务。
JobScheduler的使用:
创建一个类继承JobService,并覆盖onStartJob(JobParameters parms)方法和onStopJob(JobParameters params)。
public class PollService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
Android准备好执行任务时,服务就会启动,此时会在主线程上收到onStartJob()方法调用。该方法返回false结果表示:"交代的任务我已全力去做,现在做完了。”返回 true 结果则表示:“任务收到,正在做,但是还没有做完。”
JobService在执行的时候需要单开线程,可以使用AsyncTask按如下方式创建新线程。
private PollTask mCurrentTask; @Override public boolean onStartJob(JobParameters parms){ mCurrentTask = new PollTask(); mCurrentTask.execute(parms); return true; } private class PollTask extends AsyncTask<JobParameters,Void,Void> { @Override protected Void doInBackground(JobParameters... params) { JobParameters jobParams = params[0]; //执行任务的逻辑 jobFinished(jobParams, false); return null; } }
任务执行完毕后,就可以调用jobFinished(JobParameters, boolean)方法通知结果,如果该方法的第二个参数传入true的话,就等于说:“事情这次做不完了,请计划在下次某个时间继续吧。”
onStopJob(JobParameters)方法适合在中断任务时调用,用户通常需要服务在有WIFI连接时才运行,如果在调用JobFinished()之前(任务完成之前),手机就没了Wifi,onStopJob(...) 方法就会被调用,也就是说,一切任务就立即停止了。
@Override public boolean onStopJob(JobParameters params) { if (mCurrentTask != null) { mCurrentTask.cancel(true); } return true; }
调用 onStopJob(...) 方法就是表明,服务马上就要停掉了。不要抱有幻想,请立即停止手头上的一切事情。这里,返回 true 表示:“任务应该计划在下次继续。”返回 false 表示:“不管怎样,事情就到此结束吧,不要计划下次了。”
使用JobService,必须在Manifest配置清单中添加权限:
<service android:name=".PollService" android:permission="android.permission.BIND_JOB_SERVICE" //添加的权限控制只有JobScheduler才能运行它。 android:exported="true"/>
通过JobScheduler检查是否已计划好了任务:
final int JOB_ID = 1; JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); boolean hasBeenScheduled = false; for (JobInfo jobInfo : scheduler.getAllPendingJobs()) { if (jobInfo.getId() == JOB_ID) { hasBeenScheduled = true; } }
PoolService的运行:
final int JOB_ID = 1; JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo jobInfo = new JobInfo.Builder(JOB_ID, new ComponentName(context, PollService.class)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setPeriodic(1000 * 60 * 15) .setPersisted(true) .build();
scheduler.schedule(jobInfo);
上述代码计划任务每15分钟运行一次,但前提条件是有Wi-Fi或有可用的不限流量网络。调用 setPersisted(true) 方法可保证服务在设备重启后也能按计划运行。