本指南讨论如何使用 Android 作业计划程序 API (在运行 Android 5.0 (API 级别 21) 和更高版本的 Android 设备上提供)计划后台工作。

使 Android 应用程序对用户进行响应的最佳方式之一是确保在后台执行复杂的或长时间运行的工作。 但重要的是,后台工作不会对用户对设备的体验产生负面影响。

例如,后台作业可能每三或四分钟轮询一次网站,以查询特定数据集的更改。 这似乎是良性的,但会对电池寿命产生灾难性影响。 应用程序将重复唤醒设备,将 CPU 提升到较高的电源状态,启动无线电收发器,使网络请求,然后处理结果。 这种情况更糟,因为设备不会立即断电并返回到低功耗空闲状态。 计划不良的后台工作可能会意外地使设备处于一种不必要和过多电源要求的状态。 此看似合法的活动 (轮询网站) 会使设备在相对较短的时间内不可用。

Android 提供以下 Api,可帮助在后台执行工作,但其本身并不是用于智能作业计划的。

  • 意向服务 –意向服务非常适合用于执行工作,但他们不提供计划工作的方式。
  • AlarmManager –这些 api 只允许计划工作,但不能实际执行工作。 此外,AlarmManager 只允许基于时间的约束,这意味着在特定时间或经过一段时间后发出警报。
  • 广播接收 方– Android 应用可设置广播接收器来执行工作,以响应系统范围内的事件或意向。 但是,广播接收器不提供对作业运行时间的任何控制。 同时,Android 操作系统中的更改将限制广播接收方的工作时间或它们可以响应的工作类型。
  • 可以通过两个主要功能有效地执行后台工作 (有时称为 后台作业 作业 ) :

  • 智能地计划工作 –当应用程序在后台执行工作时,这一点非常重要。 理想情况下,应用程序不应要求运行作业。 相反,应用程序应指定在作业可以运行时必须满足的条件,然后使用满足条件时将执行工作的操作系统计划该作业。 这允许 Android 运行作业,以确保设备上的最高效率。 例如,可能会批处理网络请求同时运行全部,以充分利用网络所涉及的开销。
  • 封装工作 -用于执行后台工作的代码应封装在独立于用户界面的离散组件中,如果由于某种原因无法完成工作,则可以相对容易地重新计划。
  • Android 作业计划程序是一种内置于 Android 操作系统的框架,可提供 Fluent API 来简化计划后台工作。 Android 作业计划程序包含以下类型:

  • Android.App.Job.JobScheduler 是一个系统服务,用于计划、执行并代表 Android 应用程序取消作业。
  • Android.App.Job.JobService 是一个抽象类,必须使用将在应用程序的主线程上运行作业的逻辑进行扩展。 这意味着 JobService ,负责如何以异步方式执行工作。
  • Android.App.Job.JobInfo 对象包含在作业应运行时指导 Android 的条件。
  • 若要计划使用 Android 作业计划程序,Xamarin Android 应用程序必须在扩展 JobService 类的类中封装代码。 JobService 有三种可以在作业的生存期内调用的生命周期方法:

  • Bool OnStartJob (JobParameters 参数) –此方法由 调用以执行工作,并在应用程序的主线程上运行。 负责 JobService 异步执行工作,并在剩余工作时返回,或 false 在工作完成后返回 true

    JobScheduler 当调用此方法时,它将在作业期间请求并保留 Android 的 wakelock。 完成该作业后,就会 JobService 通过调用 JobFinished 下一) 所述 (方法来判断 JobScheduler 此事实的原因。

  • JobFinished (JobParameters 参数,Bool needsReschedule) –必须通过 调用此方法来告知 JobScheduler 完成了工作。 如果 JobFinished 未调用, JobScheduler 将不会删除 wakelock,从而导致不必要的电池排出。

  • Bool OnStopJob (JobParameters 参数) –当作业在 Android 停止后被调用。 如果应根据重试条件重新计划作业,则它应返回 true (详细信息) 。

    可以指定 约束 触发器 ,以便控制作业的运行时间和运行时间。 例如,可以限制作业,使其仅在设备充电时运行,或在拍摄照片时启动作业。

    本指南将详细讨论如何实现 JobService 类并使用对 JobScheduler 其进行安排。

    Android 作业计划程序需要 android API 级别 21 (Android 5.0) 或更高版本。

    使用 Android 作业计划程序

    使用 Android JobScheduler API 有三个步骤:

  • 实现 JobService 类型以封装工作。
  • JobInfo.Builder 使用对象创建 JobInfo 一个对象,该对象将包含用于运行作业的条件 JobScheduler
  • 使用 JobScheduler.Schedule 计划作业。
  • 实现 JobService

    Android 作业计划程序库执行的所有工作都必须在一个扩展 Android.App.Job.JobService 抽象类的类型中完成。 JobService 创建非常类似于使用 Android framework 创建 Service

  • JobService 扩展类。
  • 使用 ServiceAttribute 修饰子类,并将参数设置 Name 为由包名称和类名称组成的字符串 (参见下面的示例) 。
  • Permission 将的 ServiceAttribute 属性设置为字符串 android.permission.BIND_JOB_SERVICE
  • OnStartJob 重写方法,并添加用于执行工作的代码。 Android 将在应用程序的主线程上调用此方法以运行作业。 需要在线程上执行几毫秒时间,以避免阻塞应用程序的工作。
  • 完成工作后, JobService 必须调用 JobFinished 方法。 此方法说明 JobScheduler 了完成此工作的方式 JobService 。 如果调用 JobFinished 失败,将导致 JobService 对设备施加不必要的需求,缩短电池寿命。
  • 最好还重写 OnStopJob 方法。 此方法由 Android 在作业完成之前关闭,并且提供 JobService 了正确释放任何资源的机会。 如果需要重新计划作业,或者 false 如果不需要重新运行作业,则此方法应返回 true
  • 下面的代码是应用程序的最简单 JobService 示例,使用 TPL 异步执行一些工作:

    [Service(Name = "com.xamarin.samples.downloadscheduler.DownloadJob", 
             Permission = "android.permission.BIND_JOB_SERVICE")]
    public class DownloadJob : JobService
        public override bool OnStartJob(JobParameters jobParams)
            Task.Run(() =>
                // Work is happening asynchronously
                // Have to tell the JobScheduler the work is done. 
                JobFinished(jobParams, false);
            // Return true because of the asynchronous work
            return true;  
        public override bool OnStopJob(JobParameters jobParams)
            // we don't want to reschedule the job if it is stopped or cancelled.
            return false; 
    

    创建 JobInfo 以计划作业

    Xamarin Android 应用程序不能直接实例化 JobService ,而是将对象传递 JobInfoJobSchedulerJobScheduler将实例化所请求 JobService 的对象,按照中 JobInfo 的元数据计划和运行 JobServiceJobInfo对象必须包含以下信息:

  • JobId –这是 用于标识作业 JobScheduler 的值。 重复使用此值将更新所有现有作业。 对于应用程序,该值必须是唯一的。
  • JobService –此参数是一个 ,它显式标识应用于运行作业的类型 JobScheduler
  • 此扩展方法演示如何使用 Android Context 创建 JobInfo.Builder ,例如活动:

    public static class JobSchedulerHelpers
        public static JobInfo.Builder CreateJobBuilderUsingJobId<T>(this Context context, int jobId) where T:JobService
            var javaClass = Java.Lang.Class.FromType(typeof(T));
            var componentName = new ComponentName(context, javaClass);
            return new JobInfo.Builder(jobId, componentName);
    // Sample usage - creates a JobBuilder for a DownloadJob and sets the Job ID to 1.
    var jobBuilder = this.CreateJobBuilderUsingJobId<DownloadJob>(1);
    var jobInfo = jobBuilder.Build();  // creates a JobInfo object.
    

    Android 作业计划程序的一项强大功能是能够控制作业的运行时间或在什么条件下运行作业。 下表介绍了中 JobInfo.Builder 的一些方法,这些方法允许应用在作业运行时影响:

    SetBackoffCriteria 尝试再次运行作业之前应等待的时间 JobScheduler 提供了一些指导。 回退条件有两个部分:默认值为30秒 (默认值为30秒的延迟时间(以毫秒为单位)) 和应使用的备份类型 (有时称为 回退策略重试策略) 。 这两个策略封装在枚举中 Android.App.Job.BackoffPolicy

  • BackoffPolicy.Exponential –指数回退策略会在每次发生故障后以指数方式增加初始回退值。 第一次作业失败时,库将等待在重新计划作业之前指定的初始间隔–示例30秒。 第二次作业失败时,库将等待至少60秒,然后再尝试运行作业。 第三次尝试失败后,库将等待120秒,依此类推。 这是默认值。
  • BackoffPolicy.Linear –此策略是一种线性回退,应将作业重新安排为按设置的时间间隔运行 (直到成功) 。 线性回退最适用于必须尽快完成的工作,或者用于快速解决自身问题的问题。
  • 有关创建 JobInfo 对象的更多详细信息,请阅读 JobInfo

    通过 JobInfo 将参数传递给作业

    通过创建 PersistableBundleJob.Builder.SetExtras 方法一起传递的来将参数传递给作业:

    var jobParameters = new PersistableBundle();
    jobParameters.PutInt("LoopCount", 11);
    var jobBuilder = this.CreateJobBuilderUsingJobId<DownloadJob>(1)
                         .SetExtras(jobParameters)
                         .Build();
    

    PersistableBundle可从 Android.App.Job.JobParameters.Extras 的方法 JobServiceOnStartJob 的属性访问:

    public override bool OnStartJob(JobParameters jobParameters)
        var loopCount = jobParams.Extras.GetInt("LoopCount", 10);
        // rest of code omitted
    

    若要计划作业,Xamarin Android 应用程序将获取对 JobScheduler 系统服务的引用,并使用上一步中创建的 JobInfo 对象调用 JobScheduler.Schedule 方法。 JobScheduler.Schedule 将立即返回以下两个整数值之一:

  • JobScheduler. ResultSuccess –已成功安排作业。
  • JobScheduler. ResultFailure –无法计划作业。 这通常是由参数冲突 JobInfo 引起的。
  • 此代码是计划作业并向用户通知计划尝试结果的示例:

    var jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
    var scheduleResult = jobScheduler.Schedule(jobInfo);
    if (JobScheduler.ResultSuccess == scheduleResult)
        var snackBar = Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_success, Snackbar.LengthShort);
        snackBar.Show();
        var snackBar = Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_failure, Snackbar.LengthShort);
        snackBar.Show();
    

    可以取消已计划的所有作业,或者只是使用 JobsScheduler.CancelAll() 方法或 JobScheduler.Cancel(jobId) 方法的单个作业:

    // Cancel all jobs
    jobScheduler.CancelAll(); 
    // to cancel a job with jobID = 1
    jobScheduler.Cancel(1)
    

    本指南讨论了如何使用 Android 作业计划程序在后台智能地执行工作。 本文介绍了如何封装要作为 JobService 执行的工作,以及如何使用 JobScheduler 来计划该工作、使用指定条件 JobTrigger 以及如何使用 RetryStrategy 来处理失败。

  • 智能作业-计划
  • JobScheduler API 参考
  • 使用 JobScheduler 按 pro 安排作业
  • Android 电池和内存优化-Google i/o 2016 (视频)
  • Android JobScheduler-René Ruppert
  •