在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”。
点击(此处)折叠或打开
- [Service(Name = "JobScheduleSample.FibonacciJob", Permission = "android.permission.BIND_JOB_SERVICE")]
- public class FibonacciJob : JobService
- {
- public override bool OnStartJob(JobParameters jobParams)
- {
- // Called by the operating system when starting the service.
- // Start up a thread, do work on the thread.
- return true;
- }
-
- public override bool OnStopJob(JobParameters jobParams)
- {
- // Called by Android when it has to terminate a running service.
- return false; // Don't reschedule the job.
- }
- }
- [Service(Name = "JobScheduleSample.FibonacciJob", Permission = "android.permission.BIND_JOB_SERVICE")]
为了安排工作,应用程序需要使用JobInfo.JobBuilder来创建一个JobInfo对象。 JobInfo.JobBuilder有一个流畅的接口,用于收集元数据,例如要实例化的JobService的类型以及在作业运行之前应该满足的任何条件。 这段代码展示了如何创建一个JobInfo类来运行FibonacciJob(从上面的例子),但只有当设备连接到“未计量”(免费)的网络。 工作不应该比预定的时间快一秒钟,但应该在五秒内运行:
点击(此处)折叠或打开
- Java.Lang.Class javaClass = Java.Lang.Class.FromType(typeof(FibonacciJob);
- ComponentName component = new ComponentName(context, javaClass);
-
- JobInfo.Builder builder = new JobInfo.Builder(context, component)
- .SetMinimumLatency(1000) // Wait at least 1 second
- .SetOverrideDeadline(5000) // But no longer than 5 seconds
- .SetRequiredNetworkType(NetworkType.Unmetered);
- JobInfo jobInfo = builder.Build();
在前面的例子中,上下文是任何Android上下文,比如一个Activity。 该参数是一个唯一的整数,用于标识JobScheduler的作业服务。
下面的C#扩展方法应该有助于为给定的JobService子类创建一个ComponentName:
点击(此处)折叠或打开
- public static ComponentName GetComponentNameForJob<T>(this Context context) where T : JobService, new()
- {
- Class javaClass = Class.FromType(typeof(T));
- return new ComponentName(context, javaClass);
- }
点击(此处)折叠或打开
- JobScheduler jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
- int result = jobScheduler.Schedule(jobInfo);
- if (result == JobScheduler.ResultSuccess)
- {
- // The job was scheduled.
- }
- else
- {
- // Couldn't schedule the job.
- }
点击(此处)折叠或打开
- // Bundle up parameters
- var jobParameters = new PersistableBundle();
- extras.PutLong("some_long_value", 10L);
-
- // Put the Bundle with the parameters into the jobInfo.
- JobInfo.Builder builder = new JobInfo.Builder(context, component)
- .SetExtras(extras);
- JobInfo jobInfo = builder.Build();
点击(此处)折叠或打开
- public override bool OnStartJob(JobParameters jobParams)
- {
- long theValue = jobParams.Extras.GetLong("some_long_value", -1);
-
- // Job does something with the value.
- }
最后,当一个JobService完成了它的工作(不管工作在哪个线程上),它应该调用它自己的JobFinished()方法。 调用此方法非常重要,因为它告诉JobScheduler工作已经完成,并且首先释放为JobService获取的任何唤醒锁定是安全的。 此图说明了JobService方法如何相互关联以及如何使用它们:
现在您已经看到了JobScheduler API的基础知识,请尝试在您的Xamarin.Android应用程序中使用它来替换在后台服务中完成的任务。 这是一个很好的机会,可以增强用户对应用程序的体验,并一次性更新到Android Oreo 8.0!
您可以在GitHub上找到一个显示JobScheduler API的小示例。 该示例计算作业中的斐波那契数字,然后将该数字传递回活动。