使用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) 方法可保证服务在设备重启后也能按计划运行。