Подтвердить что ты не робот

Какие инструменты доступны для тестирования JobScheduler?

Мы выполняем Job с помощью JobScheduler для фоновой загрузки данных. Работа будет срабатывать примерно раз в день. Какие инструменты доступны для тестирования этой функции (возможно, ADB)?

Случаи использования должны иметь возможность имитировать условия, необходимые для запуска Работы или просто сказать "Запуск этого задания" как часть нашего автоматизированного набора тестов.

4b9b3361

Ответ 1

Правильно.
Хеннинг и P4u144 поставили меня на правильный путь, чтобы ответить на этот вопрос более подробно.

Определить все зарегистрированные вакансии

Определите вашу задачу с помощью команды adb shell dumpsys jobscheduler.
Это даст вам огромный выход в следующих категориях.

  • настройки
  • Зарегистрированные XX Вакансии
  • связь
  • сигнализация
  • вхолостую
  • аккумулятор
  • AppIdle
  • содержание
  • История работы
  • Очередь в ожидании

Категория, в которой вы, скорее всего, заинтересованы, это зарегистрированные XX вакансии. Это говорит вам, сколько заданий было запланировано на устройстве.
Например, ваше имя пакета - com.foo.bar.application вы должны увидеть com.foo.bar.application запись:

JOB #u0a93/17: eec3709 com.foo.bar.application/com.evernote.android.job.v21.PlatformJobService
    u0a93 tag=*job*/com.foo.bar.application/com.evernote.android.job.v21.PlatformJobService
    Source: uid=u0a93 user=0 pkg=com.foo.bar.application
    JobInfo:
      Service: com.foo.bar.application/com.evernote.android.job.v21.PlatformJobService
      PERIODIC: interval=+15m0s0ms flex=+5m0s0ms
      PERSISTED
      Requires: charging=false deviceIdle=false
      Network type: 2
      Backoff: policy=1 initial=+30s0ms
      Has early constraint
      Has late constraint
    Required constraints: TIMING_DELAY DEADLINE UNMETERED
    Satisfied constraints: CONNECTIVITY NOT_ROAMING APP_NOT_IDLE DEVICE_NOT_DOZING
    Unsatisfied constraints: TIMING_DELAY DEADLINE UNMETERED
    Earliest run time: 07:23
    Latest run time: 12:23
    Ready: false (job=false pending=false active=false user=true)

Совет: используйте adb shell dumpsys jobscheduler | grep com.foo.bar.application adb shell dumpsys jobscheduler | grep com.foo.bar.application для быстрой фильтрации списка.

Теперь вы можете легко определить, была ли ваша работа зарегистрирована по правильным критериям.

FireBaseJobdispatcher

Если вы используете FirebaseJobDispatcher lib, вы можете использовать

adb shell dumpsys activity service GcmService | grep com.foo.bar.debug
    com.foo.bar.debug:0 v853
    u0|com.foo.bar.debug: 3
    (scheduled) com.foo.bar.debug/com.firebase.jobdispatcher.GooglePlayReceiver{u=0 tag="com.foo.bar.debug.job.FetchArticlesJob" trigger=window{start=10800s,end=11700s,earliest=10448s,latest=11348s} requirements=[NET_UNMETERED,DEVICE_IDLE] attributes=[PERSISTED,RECURRING] scheduled=-351s last_run=N/A jid=N/A status=PENDING retries=0 client_lib=FIREBASE_JOB_DISPATCHER-1}
    (scheduled) com.foo.bar.debug/com.firebase.jobdispatcher.GooglePlayReceiver{u=0 tag="com.foo.bar.debug.job.FetchNotificationGroupsJob" trigger=window{start=86400s,end=129600s,earliest=86048s,latest=129248s} requirements=[NET_CONNECTED,CHARGING] attributes=[PERSISTED,RECURRING] scheduled=-351s last_run=N/A jid=N/A status=PENDING retries=0 client_lib=FIREBASE_JOB_DISPATCHER-1}
    (scheduled) com.foo.bar.debug/com.firebase.jobdispatcher.GooglePlayReceiver{u=0 tag="com.foo.bar.debug.job.RemoveUnusedRealmArticlesJob" trigger=window{start=577980s,end=608400s,earliest=521961s,latest=552381s} requirements=[NET_ANY] attributes=[PERSISTED,RECURRING] scheduled=-56018s last_run=N/A jid=N/A status=PENDING retries=0 client_lib=FIREBASE_JOB_DISPATCHER-1}
    (finished) [com.foo.bar.debug/com.firebase.jobdispatcher.GooglePlayReceiver:com.foo.bar.debug.job.UpdateNotificationGroupJob,u0]
    (finished) [com.foo.bar.debug/com.firebase.jobdispatcher.GooglePlayReceiver:com.foo.bar.debug.job.UpdatePushTokenJob,u0]
    (finished) [com.foo.bar.debug/com.firebase.jobdispatcher.GooglePlayReceiver:com.foo.bar.debug.job.FetchArticlesJob,u0]

чтобы проверить, был ли ваш сервис запланирован или запущен.

Заставь свою задачу бежать

При создании Job вы получите JOB_ID.
Используйте этот JOB_ID для запуска задания.
Это можно сделать с помощью adb shell cmd jobscheduler run (требуется Android 7.1 или выше).

Например, ваше имя пакета - com.foo.bar.application а JOB_ID - 1. Теперь вы можете запустить задачу через adb

adb shell cmd jobscheduler run -f com.foo.bar.application 1

Не забудьте -f поскольку это заставляет задание выполняться, даже если установленные ограничения не выполняются.

Evernote Android Job Lib

Последнее, но не менее важное.
Используйте для этого замечательную библиотеку от Evernote.
Это позволяет легко JobScheduler на более низких уровнях API, используя JobScheduler, GcmNetworkManager или AlarmManager зависимости от уровня API.

Редактировать 24/08

Еще лучше использовать библиотеку диспетчера заданий Firebase.

Firebase JobDispatcher - это библиотека для планирования фоновых заданий в вашем приложении для Android. Он предоставляет JobScheduler-совместимый API, который работает на всех последних версиях Android (уровень API 9+), на которых установлены службы Google Play.

Я надеюсь, что это помогло.

Спасибо

Изменить 28/04/2019

И Evernote Android-Job, и Firebase JobDispatcher теперь находятся в режиме только обслуживания, и они оба предлагают использовать Jetpack WorkManager для таких задач.

Ответ 2

С помощью команды adb shell dumpsys jobscheduler вы получаете информацию о текущих и активных запланированных работах.

Я заметил, что выходные данные команды сильно различаются между Android 6 и 7. С устройством Android 5 вывод очень короткий и иногда загадочный. Интересная часть с зарегистрированными заданиями построена здесь и повторена ниже для удобства, которая должна помочь с расшифровкой:

@Override
public String toString() {
    return String.valueOf(hashCode()).substring(0, 3) + ".."
            + ":[" + job.getService()
            + ",jId=" + job.getId()
            + ",u" + getUserId()
            + ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
            + "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
            + ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
            + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
            + ",P=" + job.isPersisted()
            + (isReady() ? "(READY)" : "")
            + "]";
}

Устройства Android 7, с другой стороны, имеют очень длинный вывод с более подробной и удобочитаемой информацией. Также есть больше возможностей, таких как история. Недостатком является то, что вы должны сначала найти интересные детали.

Я не нашел способа заставить работу работать, хотя есть запрос на функцию. Смотрите ответ от p4u144.

Ответ 3

Начиная с Android 7.0, есть новая оболочка cmd для adb. И в 7.1 (только в предварительном просмотре прямо сейчас) adb shell cmd jobscheduler был добавлен как вы можете видеть здесь, чтобы заставить запустить JobScheduler. Помогает говорит:

Команды планировщика заданий (jobscheduler): help     Распечатайте этот текст справки.

run [-f | --force] [-u | --user USER_ID] ПАКЕТ JOB_ID     Запуск немедленного выполнения определенной запланированной работы.     Опции:       -f или --force: выполнять работу, даже если технические ограничения, такие как          связь в настоящее время не выполняется       -u или --user: указать, какое задание пользователя должно быть запущено; по умолчанию используется          основной или системный пользователь

Ответ 4

Это работает для меня, без необходимости использовать команды ADB. Требуется minSdk 21

@RunWith(AndroidJUnit4.class)
@TargetApi(VERSION_CODES.LOLLIPOP)
public abstract class BaseJobServiceTest {

  protected final Context context() {
    return InstrumentationRegistry.getTargetContext();
  }

  protected final void launchJobAndWait(JobInfo jobInfo) throws InterruptedException {
    JobScheduler scheduler = (JobScheduler) context().getSystemService(Context.JOB_SCHEDULER_SERVICE);

    scheduler.schedule(jobInfo);

    while (jobExecutionPending(scheduler, jobInfo)) {
      Thread.sleep(50);
    }
  }

  private boolean jobExecutionPending(JobScheduler scheduler, JobInfo jobInfo) {
    if (VERSION.SDK_INT >= VERSION_CODES.N) {
      return scheduler.getPendingJob(jobInfo.getId()) != null;
    }

    List<JobInfo> scheduledJobs = scheduler.getAllPendingJobs();
    for (int i = 0, size = scheduledJobs.size(); i < size; i++) {
      if (scheduledJobs.get(i).getId() == jobInfo.getId()) {
        return true;
      }
    }

    return false;
  }
}