Как остановить и перезапустить активность в тесте инструментов 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