Как остановить и перезапустить активность в тесте инструментов Android?

Я пытаюсь написать тест инструментария активности Android, который останавливается (onPause(), затем onStop()) и возобновляет текущую активность. Я старался

activity.finish();
activity = getActivity();

... но это, кажется, не работает должным образом.

Цель теста - подтвердить, что данные формы хранятся во время onPause() метод и перечитать во время onStart() метод. Это работает, когда вы делаете это вручную, но тест не проходит, из чего я делаю вывод, что activity.finish() кажется, неправильный способ остановить и возобновить деятельность.


Изменить: Моя главная проблема, кажется, была проблема синхронизации. После перезапуска упражнения тестировщик не дождался завершения всех обработчиков событий. Следующая строка останавливает выполнение теста до тех пор, пока действие не будет бездействующим:

getInstrumentation().waitForIdleSync()

Кроме того, взгляните на принятый ответ для получения более ценной информации о жизненном цикле.

6 ответов

Решение

При вызове (или вызвать изменение ориентации экрана):

activity.finish(); // old activity instance is destroyed and shut down.
activity = getActivity(); // new activity instance is launched and created.

Причинение деятельности пройти полный жизненный цикл отдыха:

onPause() -> onStop() -> onDestroy() -> onCreate()

Что вам нужно это:

onPause() -> onStop() -> onRestart()

Недавно я познакомился с API инструментария и обнаружил множество интересных триггерных методов жизненного цикла действия callActivityOnXXX(). Следующая строка кода должна помочь:

MyActivity myActivity = getActivity();
// make activity falling into restart phase:
getInstrumentation().callActivityOnRestart(myActivity);

Цитирование диаграммы жизненного цикла активности из официального руководства разработчика:

Я попытался вызвать.finish(), setActivity(null), getActivity(), и он перезапускает действие, но для меня это не восстановление состояния. Я опробовал все остальные ответы на SO, и все другие способы сделать это я мог найти в Интернете, и ни один из них не работал для меня. После долгих экспериментов я нашел следующие работы (примечание: требуется уровень API 11+):

    getInstrumentation().runOnMainSync(new Runnable() {
        @Override
        public void run() {
            activity.recreate();
        }
    });
    setActivity(null);
    activity = getActivity();

Когда я делаю это, создается новый экземпляр Activity, и также создается новый экземпляр фрагмента, который я прикрепил к активности ранее в тесте, и и активность, и фрагмент восстанавливают свое состояние ожидаемым образом.

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

Изменить: позже я выяснил, как это работает. getActivity() работает через регистрацию хуков, которые получают новые создаваемые действия, которые перехватывают новое действие, созданное Activity.recreate(). setActivity(null) потребовалось очистить внутренний кеш, поддерживающий getActivity, иначе он вернет старый и не будет искать новый.

Вы можете увидеть, как это работает, изучив исходный код для различных классов тестовых примеров, из которых один расширяется.

Хороший способ протестировать события жизненного цикла - это изменение ориентации экрана. По моему опыту, это удобный способ защиты от взлома шаблона onPause / onStart.

Измените свой код следующим образом:

mActivity.finish();
    setActivity(null);
    mActivity = this.getActivity();

Полное объяснение можно найти в этом вопросе

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

ActivityScenario.recreate()кажется, работает нормально. Я не думаю, что другие сложные решения больше не нужны.

Учитывая этот тест

      @Test
fun activity_is_recreated() {
  activityScenario = ActivityScenario.launch(TestingLifecycleActivity::class.java)

  activityScenario.onActivity {
      Timber.d("inside onActivity $it")        
      //do assertions   
  }

  Timber.d("pre recreate")
  activityScenario.recreate()
  Timber.d("post recreate")

  activityScenario.onActivity {
      Timber.d("inside onActivity $it")
      //do assertions
  }
}

Это журналы, связанные с жизненным циклом

      Lifecycle status change: TestingLifecycleActivity@e34cfb7 in: PRE_ON_CREATE
Lifecycle status change: TestingLifecycleActivity@e34cfb7 in: CREATED
Lifecycle status change: TestingLifecycleActivity@e34cfb7 in: STARTED
Lifecycle status change: TestingLifecycleActivity@e34cfb7 in: RESUMED
inside onActivity TestingLifecycleActivity@e34cfb7
pre recreate
Schedule relaunch activity: TestingLifecycleActivity
Lifecycle status change: TestingLifecycleActivity@e34cfb7 in: PAUSED
Lifecycle status change: TestingLifecycleActivity@e34cfb7 in: STOPPED
Lifecycle status change: TestingLifecycleActivity@e34cfb7 in: DESTROYED

//new activity instance is launched
Lifecycle status change: TestingLifecycleActivity@ac46813 in: PRE_ON_CREATE
Lifecycle status change: TestingLifecycleActivity@ac46813 in: CREATED
Lifecycle status change: TestingLifecycleActivity@ac46813 in: STARTED
Lifecycle status change: TestingLifecycleActivity@ac46813 in: RESUMED
post recreate
inside onActivity TestingLifecycleActivity@ac46813
Finishing activity: TestingLifecycleActivity@ac46813
Другие вопросы по тегам