Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5436667
  • 博文数量: 895
  • 博客积分: 17977
  • 博客等级: 上将
  • 技术积分: 8691
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-26 09:59
个人简介

一个好老好老的老程序员了。

文章分类

全部博文(895)

文章存档

2021年(2)

2020年(10)

2019年(40)

2018年(88)

2017年(130)

2015年(5)

2014年(12)

2013年(41)

2012年(36)

2011年(272)

2010年(1)

2009年(53)

2008年(65)

2007年(47)

2006年(81)

2005年(12)

分类: Android平台

2017-12-04 22:02:30

在Android 8.0之前,即使应用程序在后台,Android应用程序也会启动几乎无限期运行的服务。 这项服务对于应用程序来说非常方便,开发人员也很容易实现,但是也会对用户的设备体验造成灾难性的影响。
作为一个例子,想象一下当一个设备插入充电时,许多应用程序想要执行工作的场景。 发生这种情况时,Android将调度android.intent.action.ACTION_POWER_CONNECTED意图。 所有已注册的应用程序都将启动,要求RAM,CPU时间和带宽。 发生这种情况时,这些同时发生的请求可能会超出设备上的可用空间,导致速度变慢。 在这一点上,用户都知道,他们插入设备,并开始表现出迟钝,反应迟钝的行为,并可能认为他们的手机有问题,或者他们需要购买更多的内存。

Android 8.0引入了新的后台执行限制,极大地改变了服务的工作方式。 当应用程序进入后台时,他们启动的任何服务将被授予几分钟时间,以在操作系统终止它们之前完成其工作。 Android Framework JobScheduler是解决Xamarin.Android应用程序针对Android 5.0(API级别21)或更高版本的更改的一种可能方式。
Android框架JobScheduler是一个API,用于在各种应用程序的后台运行不同的工作单元。 JobScheduler根据应用程序可以设置的条件安排哪些作业在适当的时间运行。 回到我们原来收取设备的例子,JobScheduler可能会安排这些工作,以便他们一个接一个地运行,而不是同时运行。

计划和排队作业的能力使JobScheduler完美适用于传统上由长时间运行的服务处理的任务,例如:

  • 正在下载文件,但仅在设备连接到未计量(免费)网络时。
  • 为设备充电时,请从一系列较大的图像中制作一系列缩略图。
  • 如果连接到网络,则在不成功的Web服务调用之间使用指数退避算法调用Web服务上的方法。

JobScheduler API中有三个重要的类:

  • JobScheduler: 系统服务将运行应用程序计划的作业。
  • JobService: 一个由应用程序扩展的类,包含作为作业一部分运行的代码。 每个作业的代码都包含在扩展JobService类并请求android.permission.BIND_JOB_SERVICE权限的类中。
  • JobInfo: 保存有关JobScheduler运行JobService所需的作业的信息。 JobInfo会告诉JobScheduler要使用哪个JobService类型,以及在作业运行之前必须满足哪些条件。 它还包含应用程序必须传递给JobService的所有参数。 JobInfo对象不是直接实例化的,而是使用JobInfo.Builder创建的。

JobService子类必须重写两个方法:

  • OnStartJob: 当作业开始并在应用程序的主线程上运行时系统调用的方法。 如果工作是一个小而简单的任务(小于16毫秒),它可能在主线程上运行。 但是,诸如磁盘访问或网络调用等冗长的任务必须异步运行。 OnStartJob应该在另一个线程上运行时返回“true”,而如果在OnStartJob本身中执行了所有的工作,则返回“false”。
  •  OnStopJob: 当系统必须提前终止作业并为JobService提供执行任何必要的清理的机会时调用此方法。 如果工作重新安排,将会返回“true”。

    点击(此处)折叠或打开

    1. [Service(Name = "JobScheduleSample.FibonacciJob", Permission = "android.permission.BIND_JOB_SERVICE")]
    2. public class FibonacciJob : JobService
    3. {
    4.    public override bool OnStartJob(JobParameters jobParams)
    5.    {
    6.       // Called by the operating system when starting the service.
    7.       // Start up a thread, do work on the thread.
    8.       return true;
    9.    }
    10.  
    11.    public override bool OnStopJob(JobParameters jobParams)
    12.    {
    13.       // Called by Android when it has to terminate a running service.
    14.       return false; // Don't reschedule the job.
    15.    }
    16. }

为了安排工作,应用程序需要使用JobInfo.JobBuilder来创建一个JobInfo对象。 JobInfo.JobBuilder有一个流畅的接口,用于收集元数据,例如要实例化的JobService的类型以及在作业运行之前应该满足的任何条件。 这段代码展示了如何创建一个JobInfo类来运行FibonacciJob(从上面的例子),但只有当设备连接到“未计量”(免费)的网络。 工作不应该比预定的时间快一秒钟,但应该在五秒内运行:

点击(此处)折叠或打开

  1. Java.Lang.Class javaClass = Java.Lang.Class.FromType(typeof(FibonacciJob);
  2. ComponentName component = new ComponentName(context, javaClass);
  3.  
  4. JobInfo.Builder builder = new JobInfo.Builder(context, component)
  5.                                      .SetMinimumLatency(1000) // Wait at least 1 second
  6.                                      .SetOverrideDeadline(5000) // But no longer than 5 seconds
  7.                                      .SetRequiredNetworkType(NetworkType.Unmetered);
  8. JobInfo jobInfo = builder.Build();

在前面的例子中,上下文是任何Android上下文,比如一个Activity。 该参数是一个唯一的整数,用于标识JobScheduler的作业服务。
下面的C#扩展方法应该有助于为给定的JobService子类创建一个ComponentName:

点击(此处)折叠或打开

  1. public static ComponentName GetComponentNameForJob<T>(this Context context) where T : JobService, new()
  2. {
  3.    Class javaClass = Class.FromType(typeof(T));
  4.    return new ComponentName(context, javaClass);
  5. }
创建JobInfo后,应用程序可以安排一项工作。 此代码片段将获得对JobScheduler服务的引用,并要求它安排在jobInfo对象中标识的作业:

点击(此处)折叠或打开

  1. JobScheduler jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
  2. int result = jobScheduler.Schedule(jobInfo);
  3. if (result == JobScheduler.ResultSuccess)
  4. {
  5.    // The job was scheduled.
  6. }
  7. else
  8. {
  9.    // Couldn't schedule the job.
  10. }
应用程序也可以将参数传递给服务,方法是将其打包到Bundle中,然后调用JobInfo.SetExtras方法。 Bundle包含在调用OnStartJob时传递给JobService的JobParameters对象中。 例如,这段代码将传递一个值给作业:

点击(此处)折叠或打开

  1. // Bundle up parameters
  2. var jobParameters = new PersistableBundle();
  3. extras.PutLong("some_long_value", 10L);
  4.  
  5. // Put the Bundle with the parameters into the jobInfo.
  6. JobInfo.Builder builder = new JobInfo.Builder(context, component)
  7.                                      .SetExtras(extras);
  8. JobInfo jobInfo = builder.Build();
要访问此值,JobService应读取JobParameter对象上的.Extras属性:

点击(此处)折叠或打开

  1. public override bool OnStartJob(JobParameters jobParams)
  2. {
  3.    long theValue = jobParams.Extras.GetLong("some_long_value", -1);
  4.  
  5.    // Job does something with the value.
  6. }

最后,当一个JobService完成了它的工作(不管工作在哪个线程上),它应该调用它自己的JobFinished()方法。 调用此方法非常重要,因为它告诉JobScheduler工作已经完成,并且首先释放为JobService获取的任何唤醒锁定是安全的。 此图说明了JobService方法如何相互关联以及如何使用它们:



The relationship of JobService method calls.

现在您已经看到了JobScheduler API的基础知识,请尝试在您的Xamarin.Android应用程序中使用它来替换在后台服务中完成的任务。 这是一个很好的机会,可以增强用户对应用程序的体验,并一次性更新到Android Oreo 8.0!
您可以在GitHub上找到一个显示JobScheduler API的小示例。 该示例计算作业中的斐波那契数字,然后将该数字传递回活动。

阅读(1632) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~