Как проверить работу JobDispatcher для Firebase (которая запускается ежедневно) [дублировать]

Я считаю, что наиболее полезно использовать Runnable для всех упомянутых причин, но иногда мне нравится продлить Thread, поэтому я могу создать свой собственный метод остановки потока и вызвать его непосредственно на созданном мной потоке.

29
задан greg7gkb 11 August 2016 в 17:31
поделиться

4 ответа

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

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

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

  • Настройки
  • Зарегистрировано XX Задания
  • Связь
  • Сигнализация
  • Idle
  • Аккумулятор
  • AppIdle
  • Содержание
  • История заданий
  • Ожидающая очередь

Вы, скорее всего, заинтересованы в категории Зарегистрировано XX Задания . Это говорит о том, сколько заданий запланировано на устройстве. Например, ваше имя_файла 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, чтобы быстро отфильтровать список.

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

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. Он предоставляет API, совместимый с JobScheduler, который работает во всех последних версиях Android (API уровня 9+), в которых установлены сервисы Google Play.

Надеюсь, это помогло.

Спасибо

54
ответ дан tim 18 August 2018 в 18:12
поделиться
  • 1
    Хорошее резюме! Я просто хотел добавить, что все, что вы написали, относится к Android 7 и выше. JobScheduler находится на борту с Android 5, там выход отличается. Просто, если кто-то задается вопросом. – Henning 16 February 2017 в 09:34
  • 2
    В моем случае Firebase JobDispatcher использовал GcmNetworkManager для планирования заданий, даже на Android O, вместо платформы, доступной JobScheduler, поэтому я не мог использовать эту команду для принудительного выполнения задания. Пришлось переключиться на андроид-работу Evernote, которая использует платформу JobScheduler на api 21+. – Vibin 1 September 2017 в 14:58
  • 3
    На выходе написано Running job [FORCED], но задание не выполняется. Протестировано на эмуляторе с Android O. – Muhammad Babar 26 September 2017 в 10:21

С помощью команды 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.

12
ответ дан Henning 18 August 2018 в 18:12
поделиться
  • 1
    Хеннинг: ссылка на «Android 6» кода, который вы на самом деле указываете на ветвь lollipop-release, которая немного отличается от выхода ветви зефира. – hopia 16 May 2018 в 19:16
  • 2
    изменено на "android 5" благодаря – Henning 24 May 2018 в 14:03

Это работает для меня, без необходимости использовать команды 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;
  }
}
-1
ответ дан Maragues 18 August 2018 в 18:12
поделиться
  • 1
    Для периодических заданий не будет scheduler.getPendingJob () всегда возвращает ненулевое значение? – hopia 16 March 2018 в 02:02
  • 2
    возможно, так, я не использую это прямо сейчас, поэтому не могу сказать. Может быть, есть способ определить, является ли это новой JobInfo? Я не знаю, будут ли равные выполнять эту работу. – Maragues 16 March 2018 в 10:42
  • 3
    Пожалуйста, не используйте Thread.sleep (), поскольку это приводит к множеству рисков, в том числе к тому, что вы будете спать в основном потоке. Предпочтение откладывать задержанное Runnable, а затем при необходимости использовать Runnable re-post. – greg7gkb 30 March 2018 в 17:50
  • 4
    Это тестовый класс, мы хотим заставить основной поток спать. – Maragues 31 March 2018 в 09:57

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

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

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

12
ответ дан p4u144 18 August 2018 в 18:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: