Планировщик заданий Android
В этом руководстве описано, как спланировать фоновую работу с помощью API планировщика заданий Android, который доступен на устройствах Android под управлением ОС Android 5.0 (уровень API 21) и более поздних версий.
Обзор
Один из лучших способов поддерживать хорошую отзывчивость приложения Android — выполнять сложную или длительную работу в фоновом режиме. При этом важно, чтобы фоновая работа не влияла негативно на взаимодействие пользователя с устройством.
Например, фоновое задание может опрашивать веб-сайт каждые три или четыре минуты, чтобы получать изменения в определенном наборе данных. Это кажется пустяком, но это может повлиять на время работы аккумулятора. Приложение будет раз за разом выводить устройство из спящего режима, повышать уровень энергопотребления ЦП, включать беспроводную связь, выполнять сетевые запросы и обрабатывать результаты. Все усложняется тем, что устройство не будет немедленно выключаться и возвращаться в режим ожидания с низким энергопотреблением. Плохо спланированная фоновая работа может привести к тому, что устройство самопроизвольно и без необходимости будет переходить в режим повышенного энергопотребления. На первый взгляд безобидное действие (опрос веб-сайта) довольно быстро сделает устройство непригодным для использования.
Android предоставляет приведенные ниже API для выполнения работы в фоновом режиме, но их недостаточно для интеллектуального планирования заданий.
- Службы намерений — службы намерений отлично подходят для выполнения работы, однако они не предоставляют никаких способов планирования работы.
- AlarmManager — эти API позволяют планировать работу только, но не предоставляют возможности фактически выполнять работу. Кроме того, AlarmManager поддерживает только ограничения на основе времени, то есть создает оповещение в определенное время или по истечении определенного времени.
- Широковещательные приемники — приложение Android может настроить широковещательные приемники для выполнения работы в ответ на системные события или намерения. При этом широковещательные приемники не позволяют управлять временем выполнения заданий. Кроме того, изменения в операционной системе Android в будущем ограничат возможность выполнять широковещательные приемники, а также типы работы, на которую они могут реагировать.
Существуют два ключевых аспекта эффективного выполнения фоновой работы (иногда называемой фоновым заданием или просто заданием):
- Интеллектуальное планирование работы — важно, чтобы, когда приложение выполняет работу в фоновом режиме, что делает это как хороший гражданин. В идеале приложение не должно требовать выполнения задания. Вместо этого оно должно указать условия, при которых задание может быть выполнено, а затем запланировать в операционной системе задание, которое выполнит нужную работу при выполнении этих условий. Это позволяет Android самостоятельно управлять заданием, повышая эффективность устройства. Например, сетевые запросы могут собираться в пакет и выполняться одновременно, чтобы оптимизировать затраты на работу с сетью.
- Инкапсулируя работу. Код для выполнения фоновой работы должен быть инкапсулирован в дискретном компоненте, который может выполняться независимо от пользовательского интерфейса и будет относительно легко перепланировать работу, если работа не завершится по какой-то причине.
Планировщик заданий Android — это платформа, встроенная в операционную систему Android, которая предоставляет гибкий 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 parameters) — этот метод вызывается
JobScheduler
для выполнения работы и выполняется в основном потоке приложения. ИменноJobService
отвечает за асинхронное выполнение работы и возвращаетtrue
, если еще осталась невыполненная работа, иfalse
по завершении этой работы.Когда
JobScheduler
вызывает этот метод, он запрашивает и сохраняет блокировку в режиме бодрствования для Android на время выполнения задания. По завершении заданияJobService
должен сообщить об этом вJobScheduler
, вызвав методJobFinished
(см. далее).JobFinished(Параметры JobParameters, bool needsReschedule) — этот метод должен вызываться методом
JobService
, чтобы сообщить,JobScheduler
что работа выполнена. ЕслиJobFinished
не вызывается,JobScheduler
не удалит блокировку в режиме бодрствования, что приведет к быстрой разрядке аккумулятора.bool OnStopJob (параметры JobParameters) — это вызывается, когда задание преждевременно остановлено Android. Он должен возвращать
true
, если нужно запланировать задание повторно в соответствии с критериями повтора (подробнее описано ниже).
Есть возможность указать ограничения или триггеры, которые будут контролировать время выполнения задания. Например, можно ограничить задание так, чтобы оно выполнялось только во время зарядки устройства, или запускать задание при съемке фото.
В этом руководство подробно описано, как реализовать класс JobService
и запланировать его выполнение в JobScheduler
.
Требования
Для планировщика заданий Android требуется Android с уровнем API 21 (Android 5.0) или более поздней версии.
Использование планировщика заданий Android
Использование API JobScheduler для Android состоит из трех этапов:
- Реализуйте тип JobService и включите в него нужную работу.
- Используйте объект
JobInfo.Builder
, чтобы создать объектJobInfo
, который будет содержать критерии, по которымJobScheduler
выполнит задание. - Отправьте это задание с помощью
JobScheduler.Schedule
.
Реализация JobService
Вся работа, выполняемая планировщиком заданий Android, должна быть выполнена в типе, расширяющем абстрактный класс Android.App.Job.JobService
. Создание JobService
очень похоже на создание Service
с помощью платформы Android.
- Расширьте класс
JobService
. - Включите в подкласс
ServiceAttribute
и задайте параметруName
строковое значение, которое состоит из имени пакета и имени класса (см. следующий пример). - Для свойства
Permission
элементаServiceAttribute
укажите строковое значениеandroid.permission.BIND_JOB_SERVICE
. - Переопределите метод
OnStartJob
, добавив код для выполнения работы. Android будет вызывать этот метод в основном потоке приложения, чтобы выполнить задание. Если работа требует больше времени, чем несколько миллисекунд, ее нужно выполнять в отдельном потоке, чтобы избежать блокировки приложения. - По завершении работы
JobService
должен вызвать методJobFinished
. С помощью этого методаJobService
сообщаетJobScheduler
о том, что работа выполнена. Отсутствие вызоваJobFinished
приведет к тому, чтоJobService
сохранит уже ненужные требования к устройству и сократит время его автономной работы. - Мы также рекомендуем переопределить метод
OnStopJob
. Этот метод вызывается Android, если нужно остановить задание до его выполнения, что позволяетJobService
корректно освободить ресурсы. Этот метод должен возвращатьtrue
, если нужно заново запланировать задание, илиfalse
, если повторное выполнение не требуется.
Следующий код является примером простейшего 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
напрямую, а вместо этого передают объект JobInfo
в JobScheduler
. JobScheduler
создаст экземпляр запрошенного объекта JobService
, чтобы запланировать и запустить JobService
в соответствии с метаданными в JobInfo
. Объект JobInfo
должен содержать следующие сведения:
- JobId — это
int
значение, используемое для идентификации заданияJobScheduler
. Повторное использование этого значения приведет к обновлению существующего задания. Это значение должно быть уникальным для каждого приложения. - JobService — этот параметр является
ComponentName
явным образом идентифицирует тип, которыйJobScheduler
должен использоваться для запуска задания.
Этот метод расширения демонстрирует создание JobInfo.Builder
в Android с помощью объекта Context
, например действия:
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
, которые позволяют приложению влиять на выполнение задания.
Метод | Description |
---|---|
SetMinimumLatency |
Указывает задержку (в миллисекундах), которая должна соблюдаться перед выполнением задания. |
SetOverridingDeadline |
Объявляет, что задание должно быть завершено до истечения указанного времени (в миллисекундах). |
SetRequiredNetworkType |
Указывает требования к сетевому подключению для выполнения задания. |
SetRequiresBatteryNotLow |
Задание может выполняться, только если устройство не отображает пользователю предупреждение о низком уровне заряда. |
SetRequiresCharging |
Задание может выполняться только во время зарядки аккумулятора. |
SetDeviceIdle |
Задание запускается только во время работы устройства. |
SetPeriodic |
Задание должно выполняться регулярно. |
SetPersisted |
Задание должно сохраняться даже после перезагрузки устройства. |
SetBackoffCriteria
предоставляет некоторые рекомендации о том, как долго JobScheduler
будет ожидать перед повторной попыткой выполнить задание. Критерий откладывания разделяется на две части: задержка в миллисекундах (по умолчанию 30 секунд) и используемый тип откладывания (иногда называется политикой откладывания или политикой повтора). В перечислении Android.App.Job.BackoffPolicy
инкапсулируются две политики:
BackoffPolicy.Exponential
— Экспоненциальная политика обратной передачи увеличит начальное значение обратной передачи экспоненциально после каждого сбоя. После первой неудачной попытки библиотека выдерживает паузу, длительность которой определяется заданным начальным периодом (например, 30 секунд), а затем повторно назначает задание. При второй неудаче библиотека будет ожидать не менее 60 секунд перед попыткой повторного запуска. После третьей неудачной попытки библиотека будет ждать 120 секунд и т. д. Это значение по умолчанию.BackoffPolicy.Linear
— Эта стратегия представляет собой линейную обратную передачу, которую задание должно быть перепланировано для выполнения с заданными интервалами (до тех пор, пока задание не будет выполнено успешно). Линейная задержка лучше всего подходит для работы, которая должна быть выполнена как можно скорее, или при наличии проблем, которые быстро исчезают сами по себе.
Дополнительные сведения о создании объекта JobInfo
см. в документации Google по классу JobInfo.Builder
.
Передача параметров в задание через JobInfo
Параметры передаются в задание путем создания PersistableBundle
, который передается вместе с методом Job.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
метода OnStartJob
класса JobService
.
public override bool OnStartJob(JobParameters jobParameters)
{
var loopCount = jobParams.Extras.GetInt("LoopCount", 10);
// rest of code omitted
}
Планирование задания
Чтобы запланировать задание, приложение Xamarin.Android получает ссылку на системную службу JobScheduler
и вызывает метод JobScheduler.Schedule
для объекта JobInfo
, который был создан на предыдущем шаге. 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();
}
else
{
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
.