WorkManager. Критерії запуску завдання.

WorkManager дає нам змогу задати критерії запуску завдання, наприклад - увімкнений інтернет на девайсі. Коли ви передасте таке завдання в WorkManager.enqueue, то буде виконана перевірка, що є інтернет. Якщо він є, то завдання запуститься. А якщо його немає, то завдання висітиме в статусі ENQUEUED, поки інет не з'явиться.

Якщо завдання запущене і інтернет з якихось причин зник, то завдання буде зупинено і знову заплановано (ENQUEUED).

Давайте розглянемо, які критерії ми можемо задати.

Для прикладу будемо використовувати таке завдання.

public class MyWorker extends Worker {
 
   static final String TAG = "workmng";
 
   @NonNull
   @Override
   public WorkerResult doWork() {
       Log.d(TAG, "doWork: start");
 
       try {
           for (int i = 0; i < 10; i++) {
               TimeUnit.SECONDS.sleep(1);
               Log.d(TAG, i + ", isStopped " + isStopped());
               if (isStopped()) return WorkerResult.FAILURE;
           }
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
 
       Log.d(TAG, "doWork: end");
 
       return WorkerResult.SUCCESS;
   }
 
   @Override
   public void onStopped() {
       super.onStopped();
       Log.d(TAG, "onStopped");
   }
 
}

Цикл із 10 пауз і логування статусу isStopped. Якщо завдання було зупинено, то виходимо зі статусом FAILURE.

Також логуємо метод onStopped.

В Activity код для відстеження статусу завдання:

WorkManager.getInstance()
       .getStatusById(myWorkRequest.getId())
       .observe(this, new Observer<WorkStatus>() {
           @Override
           public void onChanged(@Nullable WorkStatus workStatus) {
               Log.d(TAG, "onChanged: " + workStatus.getState());
           }
       });

setRequiresCharging(boolean requiresCharging)

Критерій: зарядний пристрій має бути підключений.

Код додавання критерію має такий вигляд:

Constraints constraints = new Constraints.Builder()
       .setRequiresCharging(true)
       .build();
 
OneTimeWorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
       .setConstraints(constraints)
           .build();
 
WorkManager.getInstance().enqueue(myWorkRequest);

У Constraints.Builder включаємо критерій setRequiresCharging, створюємо об'єкт Constraints і передаємо його в OneTimeWorkRequest.Builder у метод setConstraints.

Для тесту я запустив завдання при вимкненому зарядному пристрої, потім увімкнув зарядку, потім знову вимкнув зарядку.

21:06:40.077 onChanged: ENQUEUED
21:06:57.866 doWork: start
21:06:57.872 onChanged: RUNNING
21:06:58.867 0, isStopped false
21:06:59.868 1, isStopped false
21:07:00.869 2, isStopped false
21:07:01.871 3, isStopped false
21:07:02.266 onStopped
21:07:02.279 onChanged: ENQUEUED
21:07:02.872 4, isStopped true

21:06:40 Під час запуску завдання було поставлено в очікування, тому що критерії запуску не були виконані - зарядний пристрій не було підключено.

21:06:57 Я підключив зарядний пристрій і WorkManager запустив завдання. Вона почала виконуватися, статус isStopped = false.

21:07:02 Я відключив зарядний пристрій. Критерій не виконано, завдання зупинено (onStopped) і знову заплановано (ENQUEUED). Прапор isStopped тепер дорівнює true, ми це обробляємо і виходимо з циклу.

Зверніть увагу, що статус FAILURE нам не прийшов. Тобто під час зупинки завдання повністю ігнорується його результат.

Про всяк випадок нагадаю, що заплановане завдання ніяк не залежить від застосунку. Можна запустити завдання і закрити додаток. Потім через якийсь час увімкнути зарядник і завдання почне виконуватися.

Решта критеріїв встановлюються і поводяться аналогічно, тому я вже не буду наводити код, а тільки коротко опишу.

setRequiresBatteryNotLow (boolean requiresBatteryNotLow)

Критерій: рівень батареї не нижче критичного.

Я перевірив цей критерій на AVD емуляторі. Завдання починає виконуватися за рівня заряду понад 20, а зупиняється за менше ніж 16.

setRequiredNetworkType (NetworkType networkType)

Критерій: наявність інтернет.

Ми можемо вказати, який саме тип мережі інтернет (NetworkType) має бути під час запуску завдання:

  • CONNECTED - WiFi або Mobile Data
  • UNMETERD - тільки WiFi
  • METERED - тільки Mobile Data
  • NOT_ROAMING - інтернет має бути не роумінговий
  • NOT_REQUIRED - інтернет не потрібен

setRequiresDeviceIdle (boolean requiresDeviceIdle)

Критерій: девайс не використовується якийсь час і пішов у сплячку. Працює на API 23 і вище.

setRequiresStorageNotLow (boolean requiresStorageNotLow)

Критерій: на девайсі має бути вільне місце, не менше критичного порога. Не придумав, як це можна швидко протестувати, тому не можу підказати скільки це в мегабайтах.

addContentUriTrigger (Uri uri, boolean triggerForDescendants)

Критерій: завдання запуститься, коли оновиться вміст зазначеного Uri. Що означає прапор triggerForDescendants - я поки що не знаю. Щойно з'ясую, напишу. Працює на API 24 і вище.

Для одного завдання можна задавати відразу кілька критеріїв.