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", "Неуспешно свързване на камерата", 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. Ако потребителят превключи към друго приложение, 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 ms води до забавяне на отговора на интерфейса. Всички тежки операции трябва да бъдат асинхронни — чрез корутини, RxJava или WorkManager. Също така не се препоръчва извикването на finish() в onResume без проверка — това може да доведе до безкраен цикъл на пресъздаване.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също