JobScheduler: контроль за задержкой от ограничений, связанных с выполняемым заданием
Я использую JobScheduler для планирования заданий. В основном я использую его для метода .setRequiredNetworkType()
, который позволяет указать, что вы хотите, чтобы задание планировалось только тогда, когда установлено сетевое соединение (или, более конкретно, неконтролируемое соединение).
Я использую следующий довольно простой код для планирования моих заданий:
PersistableBundle extras = new PersistableBundle();
extras.putInt("anExtraInt", someInt);
int networkConstraint = useUnmetered ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
ComponentName componentName = new ComponentName(context, MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(jobId, componentName)
.setRequiredNetworkType(networkConstraint)
.setExtras(extras)
.build();
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);
Таким образом, на планирование есть только одно ограничение: сетевое соединение (которое может быть "any" или "unmetered" ).
Краткая версия вопроса
Как указать максимальную задержку из всех выполняемых ограничений и фактически выполнить задание, например. "Запустите задание в течение 2 секунд после подключения к сети"?
Более длинная версия (с разбивкой)
Проблема
То, что я нахожу, это то, что на некоторых устройствах, если задание запланировано в течение периода, когда сетевое ограничение уже выполнено, задание будет выполняться немедленно (или достаточно быстро, чтобы оно воспринималось пользователем).
Но на других устройствах, даже если подходящее сетевое соединение уже доступно (чтобы задание могло работать сразу), перед его запуском существует значительная задержка. Так что, если это происходит в ответ на действие пользователя, создается впечатление, что ничего не произошло и приложение не работает.
Теперь, я хорошо знаю, что это, вероятно, намерение с JobScheduler
... чтобы оно соответствовало системе, чтобы запланировать работу, чтобы она соответствовала другим требованиям, и что нет гарантии, что работа будет выполняться немедленно, когда все ограничения будут выполнены.
Но было бы неплохо иметь некоторый контроль над ним, где это необходимо. Таким образом, для заданий, которые происходят по расписанию, без участия пользователя, предоставление системе полного контроля над точным временем является прекрасным и хорошим.
Но когда задание выполняется в ответ на действие пользователя, я хочу, чтобы задание выполнялось без задержки... при условии, что есть сетевое соединение. (Если соединение отсутствует, может отображаться сообщение о том, что действие будет выполняться при восстановлении сетевого соединения, а затем JobScheduler
будет следить за тем, чтобы задание выполнялось при восстановлении сети.)
setOverrideDeadline() не является решением?
Я вижу, что JobInfo.Builder
имеет setOverrideDeadline()
, что почти то, что я хочу. Но это указывает максимальную задержку , когда запланировано задание (т.е. Запустите задание за 10 секунд, даже если все ограничения не выполнены), а не , когда все ограничения выполнены (т.е. запустите задание в течение 10 секунд после выполнения всех ограничений).
РЕДАКТИРОВАТЬ: и, кажется, есть раздражающая ошибка, которая может привести к тому, что задание выполняется дважды при использовании setOverrideDeadline()
: см. здесь и .
Как насчет Firebase JobDispatcher?
Я вижу, что Firebase JobDispatcher имеет Trigger.NOW
trigger ( "означает, что задание должно выполняться, как только выполняются его ограничения по времени выполнения" ). Возможно, что путь, если JobScheduler
не поддерживает это изначально? Я был отложен Firebase JobDispatcher, потому что кажется, что он использует кувалду, чтобы взломать гайку... и похоже, что Firebase - это облачная передача сообщений и т.д., Которая очень далека от локального планирования задач (что должно быть полностью локальный интерес). И, похоже, для этого требуются сервисы Google Play, что опять же кажется совершенно ненужным для локального планирования задач. Кроме того, если сразу запустить Firebase, и Firebase просто использует JobScheduler
для Android L +, то, возможно, это возможно сделать непосредственно с помощью JobScheduler
, не полагаясь на Firebase?
EDIT: я сейчас пробовал это, и даже Trigger.NOW
не гарантирует немедленного ответа... на самом деле я нахожу, что на моем устройстве существует почти ровно 30 секунд, что нечетно.
В противном случае...
В настоящее время единственный способ убедиться в немедленном выполнении (если ограничения выполняются) - не использовать JobScheduler
.
Или, возможно, сначала проверьте исходные ограничения и запустите задание с setOverrideDeadline()
из 0, если все ограничения выполнены, в противном случае выполните его без setOverrideDeadline()
.
Казалось бы, гораздо предпочтительнее просто иметь возможность контролировать время самого JobScheduler
, немного похожее на setWindow()
метода AlarmManager
.
Ответы
Ответ 1
Планировщик заданий должен планировать задания: запускать периодически, с задержкой или с ограничениями для других заданий.
Если вы хотите немедленно запустить задание, его не нужно планировать, просто запустите его.
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnectedOrConnecting()) {
// If there is connectivity, Launch the job directly here
} else {
PersistableBundle extras = new PersistableBundle();
extras.putInt("anExtraInt", someInt);
int networkConstraint = useUnmetered ?
JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
ComponentName componentName = new ComponentName(context,MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(jobId, componentName)
.setRequiredNetworkType(networkConstraint)
.setExtras(extras)
.build();
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);
}