onStop — какво е, скриване на Activity в жизнения цикъл на Android

Автор: IT Sectr Публикувано: 2026-03-04 Време за четене: 9 мин

onStop — метод от жизнения цикъл на Activity в Android, извикван от системата, когато Activity престане да бъде видимо за потребителя. Activity преминава в състояние Stopped, след като ново Activity го покрие напълно, или при минимизиране на приложението. В метода onStop разработчикът е длъжен да спре анимациите, да освободи ресурсите на камерата и сензорите, да запази чернови на въведените данни. Според Android Vitals (Google, 2025), правилната обработка на onStop намалява броя на ANR (Application Not Responding) при минимизиране на приложението с 35%. След onStop системата може да извика onRestart (връщане на екрана) или onDestroy (пълно приключване). Документацията на Android Developers за жизнения цикъл на Activity описва onStop като граница между видимо и невидимо състояние.

Основни точки

  • onStop — метод, извикван при пълна загуба на видимост на Activity, но Activity все още се намира в паметта.
  • След onStop Activity преминава в състояние Stopped — живо в паметта, но не се вижда и не взаимодейства с потребителя.
  • Системата може да извика onRestart → onStart → onResume при връщане към Activity или onDestroy при приключване.
  • В onStop е необходимо да се освободят ресурси: да се спрат анимациите, да се изключат сензорите и камерата, да се запазят междинни данни.
  • Правилната имплементация на onStop — ключов фактор за стабилност на приложението при многозадачност и минимизиране.

Какво е onStop в Android?

onStop — е callback метод на класа AppCompatActivity (и неговия предшественик Activity), който се извиква от операционната система Android, когато Activity престане да бъде напълно видимо за потребителя. В този момент Activity е скрито от друго Activity, диалогов прозорец, системен стартер или заключен екран. От гледна точка на жизнения цикъл, onStop следва onPause и сигнализира, че Activity вече не се вижда на екрана, въпреки че самият обект Activity и неговото състояние остават в паметта.

Когато Activity премине в състояние Stopped (спряно), то запазва състоянието си в RAM паметта — всички полета, View йерархия и ViewModel остават достъпни. Това различава Stopped от унищоженото (Destroyed) състояние, където Activity се премахва напълно. System UI може да убие процеса на приложението, намиращо се в състояние Stopped, при недостиг на памет — това е така нареченият process death. Разработчикът е длъжен да запази критичните данни (чернови, позиция на скрол) в onSaveInstanceState(), който се извиква преди onStop, за да гарантира възстановяване при убиване на процеса.

Според спецификацията Android Compatibility Definition Document (CDD) за версия 14+, процес в състояние Stopped има по-нисък приоритет при убиване от OOM Killer — по-нисък от процесите във фаза Background, но по-висок от кешираните процеси. Според статистиката на Google, 68% от случаите на убиване на процеси се случват, когато Activity е в състояние Stopped, а не Paused.

Кога се извиква onStop: сценарии и ред

onStop се извиква при пълна загуба на видимост на Activity, независимо от причината: стартиране на ново Activity над текущото, минимизиране на приложението (натискане на Home), заключване на екрана, входящо повикване или отваряне на системен диалог. Във всички тези случаи Activity първо получава onPause (частична загуба на фокус), а след това onStop (пълна загуба на видимост).

Основни сценарии за извикване на onStop:

  • Стартиране на ново Activity над текущото — текущото Activity получава onPause, след това onStop; новото Activity преминава през onCreate → onStart → onResume.
  • Минимизиране на приложението (Home) — Activity преминава в onPause → onStop за 200–300 ms, остава в паметта в състояние Stopped.
  • Заключване на екрана — системата извиква onPause → onStop, тъй като заключеният екран напълно покрива Activity.
  • Входящо повикване — Activity на телефона (Dialer) се стартира отгоре, текущото Activity преминава в onStop.
  • Превключване към друго приложение (Recent Apps) — Activity се скрива, получава onStop, но остава в кеша на процесите.

Важно е да се разбере, че onStop не се извиква при завъртане на екрана — в този случай Activity се унищожава (onPause → onStop → onDestroy) и се създава отново (onCreate → onStart → onResume). Изключение — флагът android:configChanges="orientation" в манифеста, при който Activity не се пресъздава, а получава извикване на onConfigurationChanged().

onStop в жизнения цикъл на Activity

onStop заема централно място в последователността на жизнения цикъл на Activity между видимо и невидимо състояние. Пълна последователност: onCreate → onStart → onResume → (активно състояние) → onPause → onStop → onDestroy (или onRestart → onStart → onResume при връщане).

СъстояниеМетодВидимостВзаимодействиеПамет
CreatedonCreateНеНеРазпределена
StartedonStartЧастичнаНеПълна
ResumedonResumeПълнаДаПълна
PausedonPauseЧастичнаНеПълна
StoppedonStopНеНеПълна*
DestroyedonDestroyНеНеОсвободена

*В състояние Stopped Activity се съхранява в паметта, но може да бъде убито от системата при недостиг на ресурси. Приоритет на убиване на Stopped процеси — предпоследен, по-висок само от празните кеширани процеси.

onStop и onSaveInstanceState: Системата извиква onSaveInstanceState(Bundle) преди onStop за запазване на динамичното състояние на UI. Разработчикът презаписва този метод, за да запази в Bundle стойностите на полетата за въвеждане, позицията на RecyclerView, избраните елементи. Дори ако Activity не бъде унищожено (потребителят просто го е минимизирал и се е върнал), Bundle се предава на onCreate при конфигурационни промени. Google препоръчва запазване само на преходно UI състояние — не данни от хранилище или ViewModel, които живеят извън Activity.

Какви ресурси да освободите в onStop

В onStop разработчикът е длъжен да освободи всички ресурси, които не са необходими, когато Activity не е видимо. Това намалява натоварването на батерията, процесора и паметта, както и предотвратява ANR при връщане към активността.

Какво да освободите в onStop:

  • Анимации и transitions — спрете ObjectAnimator, ValueAnimator, ViewPropertyAnimator. Работеща анимация на невидимо Activity е загуба на GPU цикли.
  • Сензори (Sensors) — отпишете се от SensorManager (акселерометър, жироскоп, магнитометър). Сензорите консумират енергия дори когато Activity е скрито.
  • Камера и микрофон — освободете Camera2 или CameraX, спрете MediaRecorder. Оставянето на камерата активна при скрито Activity е забранено от политиката на Google Play.
  • LocationListener — отпишете се от FusedLocationProviderClient или LocationManager. Геолокацията е най-енергоемкият ресурс.
  • Network listeners — затворете WebSocket, отменете HTTP заявки, които не са необходими на заден фон.
  • MediaPlayer и ExoPlayer — поставете на пауза или спрете, ако възпроизвеждането не трябва да продължи на заден фон.

Какво да не правите в onStop: Не извършвайте дълги операции — запазване на големи данни в базата, мрежови заявки, сложни изчисления. onStop се изпълнява на основната нишка и блокира връщането към Activity. За дълги операции използвайте WorkManager със закъснение или корутини в viewModelScope. Не освобождавайте ресурси на ViewModel — ViewModel оцелява след onStop и ще бъде използван при връщане.

Разлика между onStop и onPause

onPause и onStop се различават по степен на загуба на видимост и обем на задължителните действия. onPause се извиква при частична загуба на фокус (например отваряне на диалогов прозорец или системно меню), onStop — при пълна загуба на видимост. Тази разлика е важна за избора кои ресурси да се освободят на всеки етап.

ХарактеристикаonPauseonStop
Степен на видимостЧастично видимоНапълно невидимо
ФокусИзгубенИзгубен
Време за изпълнениеДо 500 msДо 5 s (ANR timeout)
Ресурси за освобождаванеКритични (медия, камера)Всички невидими (сензори, анимации, location)
ВъзстановяванеonResumeonRestart → onStart → onResume
Приоритет на процесаВисок (Foreground)Среден (Background)

Общо правило: в onPause освобождавайте системни ресурси, които незабавно влияят на потребителското изживяване на друго приложение (камера, медиен плейър), в onStop — всички останали ресурси, които не са необходими при скрито Activity. Google препоръчва в onPause да запазвате критични потребителски данни (чернова на имейл, настройки), тъй като onStop може да не настъпи при бързо превключване.

onStop → onRestart: връщане на екрана

Когато потребителят се върне към скрито Activity, системата извиква onRestart → onStart → onResume. Методът onRestart сигнализира, че Activity се връща от състояние Stopped. Това е важен етап за възстановяване на UI и ресурси, които са били освободени в onStop.

Последователност на извикванията при връщане:

  • onRestart() — Activity се уведомява, че ще бъде показано отново. Типични действия: презареждане на данни, актуализиране на списъци.
  • onStart() — Activity става видимо, но все още не е активно. Тук повторно се инициализират ресурсите, освободени в onStop.
  • onResume() — Activity получава фокус и е готово за взаимодействие. Стартират се анимации, регистрират се сензори.

Ако процесът на приложението е бил убит от системата в състояние Stopped, onCreate се извиква вместо onRestart, а Bundle от onSaveInstanceState се предава за възстановяване на състоянието. Този сценарий (process death) — една от най-честите причини за грешки в Android приложения: разработчиците имплементират onRestart, но забравят да вземат предвид възстановяването чрез onCreate след убиване на процеса.

Примери за код с onStop в Kotlin

Пример 1: Основна имплементация на onStop с освобождаване на сензори

Показва правилно отписване от сензори и спиране на анимация при скриване на Activity. След връщане на екрана ресурсите се възстановяват в onStart.

kotlin
class MainActivity : AppCompatActivity() {
    private lateinit var sensorManager: SensorManager
    private var accelerometer: Sensor? = null
    private var rotationAnimator: ObjectAnimator? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    }

    override fun onStart() {
        super.onStart()
        accelerometer?.let {
            sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
        }
        rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
        rotationAnimator?.apply {
            duration = 3000
            repeatMode = ValueAnimator.RESTART
            repeatCount = ValueAnimator.INFINITE
            start()
        }
    }

    override fun onStop() {
        super.onStop()
        sensorManager.unregisterListener(sensorListener)
        rotationAnimator?.cancel()
    }

    override fun onRestart() {
        super.onRestart()
        Log.d("MainActivity", "Activity се връща от състояние Stopped")
    }

    private val sensorListener = SensorEventListener { event, _ ->
        Log.d("MainActivity", "Accel: x=${event.values[0]}, y=${event.values[1]}, z=${event.values[2]}")
    }
}

Кодът регистрира сензор за акселерометър и стартира безкрайна анимация на въртене в onStart. В onStop сензорът се изключва и анимацията се отменя — това предотвратява изразходването на батерия, когато Activity е скрито. След връщане чрез onRestart → onStart ресурсите се пресъздават.

Пример 2: onStop със запазване на състояние чрез SavedStateHandle

Съвременен подход с използване на ViewModel + SavedStateHandle. Данните от формуляра се запазват автоматично при onStop без ръчен Bundle.

kotlin
class FormViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    var email: String
        get() = savedStateHandle["email"] ?: ""
        set(value) { savedStateHandle["email"] = value }

    var message: String
        get() = savedStateHandle["message"] ?: ""
        set(value) { savedStateHandle["message"] = value }
}

class FormActivity : AppCompatActivity() {
    private val viewModel: FormViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_form)
        Log.d("FormActivity", "onCreate: email=${viewModel.email}")
    }

    override fun onStop() {
        super.onStop()
        Log.d("FormActivity", "onStop: данните запазени в SavedStateHandle")
    }
}

SavedStateHandle автоматично запазва стойностите в Bundle при onSaveInstanceState, който се извиква преди onStop. При завъртане на екрана или убиване на процеса данните се възстановяват без загуба. Google препоръчва SavedStateHandle за формуляри и чернови вместо директно onSaveInstanceState.

Пример 3: lifecycleScope за операции в onStop

Използване на lifecycleScope с корутини за асинхронно запазване на данни при преход към onStop. Корутината се стартира в IO диспечер, без да блокира основната нишка.

kotlin
class NoteActivity : AppCompatActivity() {
    private val noteRepository = NoteRepository()

    override fun onStop() {
        lifecycleScope.launch(Dispatchers.IO) {
            val text = findViewById<EditText>(R.id.note_content).text.toString()
            noteRepository.saveDraft(text)
            withContext(Dispatchers.Main) {
                Log.d("NoteActivity", "Черновата запазена в onStop")
            }
        }
        super.onStop()
    }
}

Корутината lifecycleScope.launch се отменя автоматично, ако жизненият цикъл на Activity приключи. Използването на Dispatchers.IO гарантира, че записът в базата данни или файл не блокира връщането към Activity. Според Google, корутините в lifecycleScope са предпочитаният начин за асинхронни операции в onStop.

Често задавани въпроси

Каква е разликата между onStop и onDestroy?

onStop — Activity престава да бъде видимо, но остава в паметта в състояние Stopped. Системата може да върне Activity чрез onRestart. onDestroy — Activity се унищожава, паметта се освобождава. След onDestroy връщането е възможно само чрез създаване на нов екземпляр на Activity (onCreate).

Задължително ли е да се извиква super.onStop()?

Да, задължително. super.onStop() осигурява правилната работа на системните компоненти: фрагменти, LoaderManager, ViewModelStore. Пропускането на super.onStop() може да доведе до изтичане на памет и неправилно възстановяване на фрагменти. Винаги извиквайте super.onStop() последно или първо — редът не е критичен, но извикването е задължително.

Как да проверите дали onStop е бил извикан?

Използвайте Log.d или Timber във всеки метод от жизнения цикъл. Включете филтър на logcat по тага на вашето Activity. За продукция използвайте Android Vitals — Google автоматично събира метрики на жизнения цикъл и показва аномалии в Play Console. Също така е наличен мониторинг на жизнения цикъл чрез ProcessLifecycleOwner.

Какво се случва, ако в onStop бъде хвърлено изключение?

Неуловено изключение в onStop причинява Force Close на приложението. Системата не улавя изключения в callback-ите на жизнения цикъл. Ако в onStop се изпълняват операции, които могат да хвърлят изключение (работа с файлове, мрежа), обвийте ги в try-catch и запишете грешката, без да прекъсвате изпълнението на super.onStop().

Трябва ли да освобождавам Bitmap в onStop?

Не, Bitmap в Activity ще бъде събран от GC, ако няма препратки към него. Принудителното освобождаване (recycle()) в onStop не е необходимо и дори е вредно — ако Activity се върне чрез onRestart, Bitmap ще трябва да се зареди отново. Използвайте Glide или Coil за зареждане на изображения — тези библиотеки автоматично управляват кеша и жизнения цикъл.

Обобщение

  • onStop — метод от жизнения цикъл на Activity, извикван при пълна загуба на видимост. Activity остава в паметта в състояние Stopped.
  • След onStop са възможни два сценария: onRestart (връщане на екрана) или onDestroy (унищожаване на Activity).
  • В onStop трябва да освободите сензори, анимации, камера, location-listener-и — всичко, което не е необходимо, когато Activity е невидимо.
  • onStop се различава от onPause по степен на видимост: onPause — частична, onStop — пълна загуба на видимост.
  • onSaveInstanceState се извиква преди onStop — използвайте го за запазване на преходно UI състояние.
  • Корутините lifecycleScope с Dispatchers.IO — предпочитаният начин за асинхронни операции в onStop.
  • Винаги извиквайте super.onStop() и обвивайте опасните операции в try-catch, за да избегнете Force Close.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също