onResume — это метод жизненного цикла Android, который вызывается, когда Activity или Fragment выходит на передний план и получает фокус ввода. В этом состоянии экран готов к взаимодействию с пользователем: все события касания, нажатия клавиш и жесты направляются данному компоненту. onResume — рабочее состояние Activity, в котором приложение проводит большую часть времени. Именно здесь открывают камеру, запускают видеовоспроизведение, начинают распознавание речи и регистрируют сенсорные слушатели, требующие монопольного доступа. Подробнее о полном жизненном цикле Activity читайте в статье Activity Lifecycle.
Главное
onResume — третий метод жизненного цикла Activity, вызываемый после onStart, который сигнализирует о готовности экрана к полноценному взаимодействию с пользователем. В этот момент Activity находится на вершине стека задач (back stack), система направляет ему все события ввода, и приложение может начинать любые операции, требующие активного участия пользователя: видеозвонки, игры, аудиозапись, рисование на Canvas.
onResume входит в «срок жизни на переднем плане» (foreground lifetime) — промежуток между onResume и onPause. Это наиболее активный период работы Activity, когда приложение потребляет максимум ресурсов: процессор для обработки касаний, GPU для рендеринга анимаций, камеру и микрофон для видеозахвата. Понимание этого уровня жизненного цикла критически важно для оптимизации энергопотребления — ресурсы, открытые в onResume, должны быть немедленно закрыты в onPause.
По данным Google I/O 2025, среднее время, которое Activity проводит в состоянии onResume за одну сессию, составляет 2–5 минут для новостных приложений и 15–30 минут для игр и мессенджеров. Всё остальное время Activity находится в состояниях onPause, onStop или onDestroy. Это означает, что оптимизация именно onResume-кода даёт наибольший выигрыш в производительности и времени работы от батареи.
В Activity метод onResume вызывается каждый раз, когда экран получает фокус ввода — при первом запуске, при возврате из другого Activity, при закрытии диалогового окна, при разблокировке устройства. Это «горячий» метод, который может вызываться много раз за сессию, и его реализация должна быть максимально лёгкой.
class CameraActivity : AppCompatActivity() {
private var cameraProvider: ProcessCameraProvider? = null
private var preview: Preview? = null
override fun onResume() {
super.onResume()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
cameraProvider = cameraProviderFuture.get()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding?.viewFinder?.surfaceProvider)
}
try {
cameraProvider?.unbindAll()
cameraProvider?.bindToLifecycle(
this, cameraSelector, preview
)
} catch (e: Exception) {
Log.e("Camera", "Failed to bind camera", e)
}
}, ContextCompact.getMainExecutor(this))
}
override fun onPause() {
super.onPause()
cameraProvider?.unbindAll()
preview = null
}
}
Пример с CameraX демонстрирует классическое использование onResume/onPause: камера — монопольный ресурс, который может использовать только одно приложение в момент времени. Привязка камеры к жизненному циклу через bindToLifecycle автоматически закрывает камеру в onPause, но явный вызов unbindAll гарантирует немедленное освобождение. Это особенно важно при переключении между Activity: камера должна быть освобождена до того, как другое Activity попытается её открыть.
onResume во Fragment вызывается после того, как содержащая его Activity получила onResume. Однако из-за особенностей FragmentManager и ViewPager момент вызова onResume для Fragment может быть отсрочен относительно Activity. Например, Fragment в ViewPager с offscreenPageLimit = 1 получает onResume только когда становится текущей страницей, а не при старте Activity.
class VideoPlayerFragment : Fragment() {
private var exoPlayer: ExoPlayer? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
exoPlayer = ExoPlayer.Builder(requireContext()).build()
binding?.playerView?.player = exoPlayer
}
override fun onResume() {
super.onResume()
exoPlayer?.play()
if (userVisibleHint) {
startBiometricAuth()
}
}
override fun onPause() {
exoPlayer?.pause()
stopBiometricAuth()
super.onPause()
}
}
Проверка userVisibleHint в Fragment.onResume актуальна для ViewPager: Fragment может получить onResume, но быть скрытым соседней страницей (например, при анимированном переходе). В таких случаях запуск видео или биометрии в onResume без проверки видимости приведёт к неожиданному поведению. Начиная с Fragment 1.5.0, рекомендуется использовать FragmentTransaction.setMaxLifecycle() для точного контроля жизненного цикла фрагментов в ViewPager2.
Разработчики часто путают onStart и onResume, помещая код в неподходящий метод. Главное правило: onStart — для ресурсов, работающих при видимости; onResume — для ресурсов, требующих фокуса ввода. Рассмотрим конкретные сценарии и правильный выбор метода.
| Операция | Метод | Обоснование |
|---|---|---|
| Подписка на геолокацию | onStart / onStop | GPS может работать при частичной видимости |
| Открытие камеры | onResume / onPause | Камера — монопольный эксклюзивный ресурс |
| BroadcastReceiver | onStart / onStop | Системные события не требуют фокуса |
| Видеовоспроизведение | onResume / onPause | Видео должно быть видно пользователю |
| Bluetooth-сканирование | onStart / onStop | Сканирование может идти в фоне |
| Диктофон (MediaRecorder) | onResume / onPause | Запись требует активного UI |
| Сенсорные слушатели | onResume / onPause | Датчики для игр и жестов |
| Обновление данных | onStart | Свежие данные нужны при появлении |
Практическое правило: если операция должна прерываться при появлении диалогового окна — используйте onResume/onPause. Если операция может продолжаться при частичном перекрытии экрана — используйте onStart/onStop. Например, видеоплеер должен ставить видео на паузу при открытии диалога (onPause), а геолокация может продолжать обновляться (остаётся в onStart).
Эксклюзивные ресурсы — это компоненты устройства, которые могут использоваться только одним приложением в конкретный момент времени. Камера, микрофон, видеовыход (MediaProjection), NFC-адаптер в режиме чтения, USB-устройства в режиме accessory — все эти ресурсы должны открываться в onResume и освобождаться в onPause.
MediaRecorder используется для записи аудио и видео. Запрос разрешений и подготовка MediaRecorder выполняется в onCreate, а старт записи — в onResume. If пользователь переключается на другое приложение, onPause приостанавливает запись, а onResume возобновляет. Это стандартное поведение для диктофонов и приложений видеозаписи.
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false
override fun onResume() {
super.onResume()
if (isRecording) {
mediaRecorder?.resume()
}
}
override fun onPause() {
if (isRecording) {
mediaRecorder?.pause()
}
super.onPause()
}
Биометрическая аутентификация (BiometricPrompt) должна вызываться только когда Activity находится в onResume. Если вызвать её в onCreate или onStart, диалог биометрии может появиться до того, как Activity завершит инициализацию, что приведёт к некорректной обработке результата. Вызов в onResume гарантирует, что окно биометрии будет показано в правильном контексте.
Рассмотрим три проверенных паттерна работы с onResume, которые применяются в коммерческих проектах: сброс таймера неактивности, обновление видимых данных и интеграция с Jetpack Navigation.
В приложениях с конфиденциальными данными (банкинг, медицинские карты) onResume используют для сброса таймера автоматического выхода. Если пользователь активно взаимодействует с приложением, onResume вызывается при каждом переходе между экранами, и таймер сбрасывается. Если пользователь свернул приложение, onPause останавливает таймер, а onResume при возврате либо сбрасывает его, либо запрашивает повторную аутентификацию.
Список, который должен отображать актуальные данные при каждом возврате на экран, обновляют в onResume. Например, если пользователь создал новую запись в другом Activity и вернулся назад, onResume перезагружает список из локальной базы данных или из кэша ViewModel. Это обеспечивает консистентность данных без ручного вызова notifyDataSetChanged.
override fun onResume() {
super.onResume()
// ActivityResultLauncher вернул результат — обновляем список
viewModel.refreshList()
// Сброс таймера неактивности
inactivityTimer.reset()
}
В Jetpack Navigation onResume фрагмента вызывается при каждом возврате к нему через обратную навигацию. Это свойство используют для сброса состояния UI: скрыть клавиатуру, очистить поля поиска, обновить заголовок тулбара. OnBackPressedCallback в связке с onResume даёт полный контроль над навигацией без дублирования кода.
Часто задаваемые вопросы
onStart — экран виден. onResume — экран активен и готов к взаимодействию. Представьте: вы смотрите телевизор (onStart), но берёте пульт в руки (onResume). Телевизор виден всегда, но взаимодействие начинается только с пультом. Если кто-то закрывает телевизор шторкой — экран перестаёт быть видимым (onStop). Если у вас забирают пульт — взаимодействие прекращается (onPause), но телевизор всё ещё виден.
onResume вызывается каждый раз, когда Activity получает фокус ввода. Минимальное количество — один раз (при запуске). Максимальное зависит от сценариев использования: переключение между экранами, открытие диалогов, быстрая блокировка и разблокировка устройства — каждый такой сценарий вызывает onResume при возврате на экран.
Камера — эксклюзивный ресурс, доступный только одному приложению в момент времени. Если открыть камеру в onCreate или onStart, она останется заблокированной для других приложений даже когда ваше приложение неактивно. onResume гарантирует, что камера открыта только когда Activity на переднем плане, а onPause немедленно её закрывает. Это стандарт Android-разработки, закреплённый в документации CameraX и Camera2 API.
Да, onResume может не наступить, если Activity перекрывается другим Activity сразу после появления. Например, Activity A запускает Activity B в методе onCreate или onStart. В этом случае A получает onStart → onPause → onStop, минуя onResume. Система не вызывает onResume, потому что Activity A никогда не получала фокус ввода.
В onResume нельзя выполнять длительные синхронные операции: загрузка больших данных из сети, сложные SQL-запросы, обработка изображений. Метод onResume работает в UI-потоке, и любая блокировка дольше 100–200 мс приводит к задержке отклика интерфейса. Все тяжёлые операции должны быть асинхронными — через корутины, RxJava или WorkManager. Также не рекомендуется вызывать finish() в onResume без проверки — это может привести к бесконечному циклу пересоздания.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также