Inactive — същност, преходно състояние между Active и Background

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

Inactive — преходно състояние на жизнения цикъл на приложението между Active и Background, при което приложението е видимо на екрана, но не получава събития на докосване. Обясняваме как възниква Inactive на iOS и Android, кои методи на делегата отговарят за него и как правилно да обработваме прекъсванията — обаждания, известия и системни жестове.

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

  • Inactive — приложението е видимо на екрана, но не приема touch-събития поради системно прекъсване
  • applicationWillResignActive — основният метод, сигнализиращ прехода в Inactive на iOS
  • Временен характер — Inactive продължава от части от секундата до няколко секунди, след което следва преход в Active или Background
  • Причини — входящо обаждане, Control Center, Notification Center, системен алерт, Apple Pay, Siri
  • SwiftUI — scenePhase .inactive е еквивалентен на Inactive в UIKit

Inactive — същност на преходното състояние

Inactive — междинно състояние на жизнения цикъл на мобилното приложение, което възниква при прехода между Active и Background. В това състояние приложението все още е на преден план и е видимо за потребителя, но не получава събития на докосване, натискания на клавиши и други UI събития. Системата блокира предаването на събития към приложението, но UI остава на екрана и не се минимизира.

Природата на Inactive е временна. Това състояние продължава точно толкова, колкото продължава системното прекъсване: от 0.1 секунда при бързо затваряне на Control Center до няколко секунди при входящо обаждане с екран на обаждане. След края на прекъсването приложението или се връща в Active, или преминава в Background, ако потребителят е превключил на друго приложение. Inactive е единственото състояние, от което е възможен преход и в двете посоки: обратно в Active или по-нататък в Background.

На iOS Inactive се управлява автоматично от системата. Разработчикът не може да удължи или съкрати времето за престой в Inactive — то се контролира изцяло от UIApplication. Единственото нещо, което разработчикът може да направи, е правилно да обработи прехода в Inactive чрез applicationWillResignActive и връщането чрез applicationDidBecomeActive. На Android аналогът е onPause, въпреки че семантиката се различава: onPause се извиква дори при частично покриване на Activity от друг компонент.

Сравнение на Inactive на iOS и Android

На iOS Inactive е отделно състояние на жизнения цикъл на приложението (едно от петте: Not Running, Active, Inactive, Background, Suspended). На Android няма пряк аналог — onPause сигнализира, че Activity губи входния фокус, но може да остане видимо (например при отваряне на диалог). Ключова разлика: iOS Inactive е състояние на приложението като цяло, Android onPause е състояние на конкретно Activity. В multi-window режим на Android едно Activity може да бъде в onPause (без фокус), а друго в onResume (с фокус).

ХарактеристикаiOS InactiveAndroid onPause
UI видимДаДа (частично или изцяло)
Събития на докосванеНе приемаНе приема
ПродължителностДо края на прекъсванетоДо връщане на фокуса или преминаване в заден план
Следващо състояниеActive или BackgroundonResume или onStop
НивоПриложение (UIApplication)Activity
Multi-windowЕдна сцена активнаНяколко Activity в onPause

Кога възниква Inactive

Inactive на iOS възниква в няколко строго определени сценария. Потребителят извиква Control Center (плъзгане надолу от десния горен ъгъл на iPhone X+ или плъзгане нагоре на по-стари модели). Потребителят отваря Notification Center (плъзгане надолу от левия горен ъгъл). Пристига входящо обаждане — системата показва екрана на обаждане над приложението. Изисква се системно разрешение — геолокация, микрофон, камера, контакти. На iPad се стартира Slide Over или Split View — активната сцена става Inactive.

На Android onPause (аналог на Inactive) възниква в още по-широк спектър от ситуации. Отваряне на диалогов прозорец (AlertDialog, DialogFragment). Частично покриване на Activity от друго Activity (например прозрачно Activity за удостоверяване). Завъртане на екрана (Activity се пресъздава, последователност: onPause → onStop → onDestroy → onCreate → onStart → onResume). Multi-window режим — неактивният прозорец получава onPause. Всяко от тези събития изисква спиране на ресурсоемки операции за пестене на батерия и производителност.

swift
import UIKit

extension Notification.Name {
    static let systemInterruptionBegan = Notification.Name("systemInterruptionBegan")
    static let systemInterruptionEnded = Notification.Name("systemInterruptionEnded")
}

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func applicationWillResignActive(_ application: UIApplication) {
        // Приложението преминава в Inactive — системно прекъсване
        print("Прекъсване: Control Center, обаждане или системен алерт")

        // Спиране на чувствителни към време операции
        pauseVideoPlayback()
        stopContinuousDataCollection()
        hideSensitiveInformation()

        // Уведомяване на компоненти
        NotificationCenter.default.post(name: .systemInterruptionBegan, object: nil)
    }

    // Връщане от Inactive в Active
    func applicationDidBecomeActive(_ application: UIApplication) {
        resumeVideoPlayback()
        restartDataCollection()
        NotificationCenter.default.post(name: .systemInterruptionEnded, object: nil)
    }

    private func pauseVideoPlayback() {
        // Спиране на видеото, за да не се припокрива звукът
    }

    private func hideSensitiveInformation() {
        // Скриване на чувствителни данни при скрийншот на екрана
        // Control Center/App Switcher правят скрийншот на UI
    }
}

В кода е показана обработката на Inactive в UIKit. applicationWillResignActive спира видеото, спира събирането на данни и скрива чувствителна информация. Това е важно, защото при отваряне на Control Center или App Switcher системата прави скрийншот на текущия UI — потребителят може да види поверителни данни в прегледа. NotificationCenter позволява на компонентите на приложението да се абонират за събития на прекъсване.

Inactive на iOS: Swift и UIKit

На iOS Inactive се обработва от двойка методи: applicationWillResignActive (преход в Inactive) и applicationDidBecomeActive (връщане от Inactive). Тези методи са част от UIApplicationDelegate и се извикват за всеки преход през Inactive. От iOS 13 и UISceneDelegate към тях са добавени sceneWillResignActive и sceneDidBecomeActive за multi-window сценарии.

SceneDelegate и multi-window Inactive

На iPad с iOS 13+ приложението може да има няколко сцени (прозореца). Всяка сцена има собствен жизнен цикъл. Една сцена може да стане Inactive (потребителят е превключил на друга сцена), докато друга остава Active. Това е важна разлика в сравнение с iPhone, където Inactive е глобално състояние за цялото приложение. При разработка за iPad Inactive трябва да се обработва отделно за всяка сцена.

swift
import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    // Сцената става неактивна
    func sceneWillResignActive(_ scene: UIScene) {
        // На iPad тази сцена губи фокус, но други могат да бъдат активни
        print("Сцената губи активност")

        // Спиране на задачите на тази сцена
        pauseSceneSpecificOperations()
    }

    // Сцената става активна
    func sceneDidBecomeActive(_ scene: UIScene) {
        print("Сцената стана активна")
        resumeSceneSpecificOperations()
    }

    private func pauseSceneSpecificOperations() {
        // Спиране на операции, специфични за тази сцена
    }

    private func resumeSceneSpecificOperations() {
        // Възобновяване на операции при връщане на фокуса
    }
}

// AppDelegate остава входна точка, делегира на сцени
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(
        _ application: UIApplication,
        configurationForConnecting connectingSceneSession: UISceneSession,
        options: UIScene.ConnectionOptions
    ) -> UISceneConfiguration {
        return UISceneConfiguration(
            name: "Default Configuration",
            sessionRole: connectingSceneSession.role
        )
    }
}

В кода е показан SceneDelegate за обработка на Inactive на ниво сцена. sceneWillResignActive се извиква, когато конкретен прозорец губи фокус — това може да се случи при превключване между прозорци на iPad. AppDelegate конфигурира UISceneConfiguration за поддръжка на multi-window. Всяка сцена има независимо състояние и разработчикът трябва да ги обработва отделно.

Inactive на Android: onPause и видимост

На Android прекият аналог на iOS Inactive е методът onPause() на жизнения цикъл на Activity. Извиква се, когато Activity губи входния фокус, но може да остане видимо. Типични сценарии: отваряне на диалогов прозорец, стартиране на друго Activity в същото приложение, входящо обаждане, натискане на бутона Home или Recents. В onPause разработчикът трябва да спре ресурсоемки операции — анимации, възпроизвеждане на видео, работа с камерата.

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

kotlin
class VideoPlayerActivity : AppCompatActivity() {

    private var exoPlayer: ExoPlayer? = null
    private var currentPosition: Long = 0L

    override fun onPause() {
        super.onPause()
        // Приложението губи фокус — спираме видеото
        exoPlayer?.let { player ->
            if (player.isPlaying) {
                currentPosition = player.currentPosition
                player.pause()
            }
        }
        // Скриваме чувствителни данни (GDPR/банкови екрани)
        if (window.decorView.systemUiVisibility and
            View.SYSTEM_UI_FLAG_SECURE == 0
        ) {
            hideSensitiveOverlay()
        }
    }

    override fun onResume() {
        super.onResume()
        // Връщане на фокуса — възобновяваме възпроизвеждането
        exoPlayer?.seekTo(currentPosition)
        exoPlayer?.play()
        showSensitiveOverlay()
    }

    private fun hideSensitiveOverlay() {
        // Поставяме черен екран върху финансови данни
    }
}

В кода е показана правилната обработка на onPause за видео плейър. ExoPlayer се спира при загуба на фокус и позицията на възпроизвеждане се запазва. При връщане в onResume плейърът възобновява възпроизвеждането от запазената позиция. Допълнително е показан моделът за скриване на чувствителни данни — важен за финансови и медицински приложения, изискващи защита от скрийншотове при превключване.

Най-добри практики за обработка на Inactive

Първо правило — скривайте поверителни данни при преход в Inactive. Когато потребителят отваря Control Center или App Switcher, iOS прави скрийншот на текущия екран. На Android аналогично — системата показва преглед на последния Activity в Recents. Използвайте UIApplication.shouldSnapshotSecureApp (iOS 16+) или FLAG_SECURE (Android) за защита на поверителни екрани.

Второ правило — спирайте анимациите и медиите. Inactive не е най-доброто време за възпроизвеждане на видео или анимации, тъй като потребителят не ги вижда. Освен това възпроизвеждането на заден план може да доведе до припокриване на звуци със системни звуци (обаждане, известие). Спирайте AVPlayer, ExoPlayer и UIView.animate при преход в Inactive и възобновявайте при връщане в Active.

Трето правило — блокирайте въвеждането на данни. Ако приложението съдържа формуляри за въвеждане или чернови, блокирайте клавиатурата и полетата за въвеждане при преход в Inactive. Това предотвратява случайно въвеждане при връщане и защитава от прихващане на данни чрез системни наслагвания. На iOS изключвайте first responder (view.endEditing(true)), на Android — изчиствайте фокуса (currentFocus?.clearFocus()).

Четвърто правило — не изпълнявайте дълги операции в applicationWillResignActive или onPause. Тези методи трябва да завършват за части от секундата. Ако трябва да запазите голямо количество данни, започнете запазването в фонова нишка и го завършете в applicationDidEnterBackground или onStop. iOS дава 5 секунди за изпълнение на applicationWillResignActive, след което системата може принудително да прекрати приложението.

swift
import UIKit

final class SecureOverlayManager {
    private var blurView: UIVisualEffectView?

    func showBlurOverlay() {
        guard let window = UIApplication.shared.keyWindow,
              blurView == nil
        else { return }

        let blur = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
        blur.frame = window.bounds
        blur.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        window.addSubview(blur)
        blurView = blur
    }

    func removeBlurOverlay() {
        blurView?.removeFromSuperview()
        blurView = nil
    }
}

// Използване в AppDelegate
func applicationWillResignActive(_ application: UIApplication) {
    SecureOverlayManager().showBlurOverlay()
}

func applicationDidBecomeActive(_ application: UIApplication) {
    SecureOverlayManager().removeBlurOverlay()
}

В кода е показана имплементацията на безопасно наслагване за защита на данни при преход в Inactive. UIVisualEffectView с ефект на замъгляване (blur) се поставя върху целия UI при преход в Inactive и се премахва при връщане в Active. Това гарантира, че поверителните данни няма да бъдат видими на скрийншотове на App Switcher и Control Center. Аналогично може да се използва UIImageView с лого за брандирано наслагване.

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

Винаги ли Inactive предшества Background?

Да. Inactive е задължително междинно състояние преди преход в Background на iOS. Приложението не може да премине директно от Active в Background — първо става Inactive, след това Background. На Android аналогично: onPause винаги се извиква преди onStop. Това дава на разработчика възможност да подготви данни за запазване преди пълно преминаване на заден план.

Може ли приложението да получи Inactive без прекъсване?

Да. На iPad при стартиране на Slide Over или Split View активната сцена става Inactive, въпреки че не настъпва системно прекъсване — потребителят просто взаимодейства с друга сцена. Това е multi-window функция на iPadOS. На iPhone Inactive винаги се причинява от системно прекъсване — обаждане, известие, Control Center или Notification Center.

Колко дълго може приложението да остане в Inactive?

Обикновено от 0.1 до 2 секунди. При входящо обаждане с екран на обаждане — до 30 секунди (докато потребителят отговори или отхвърли обаждането). iOS не ограничава принудително времето в Inactive, но системата може да прекрати приложението, ако не реагира на събития (watchdog). На Android onPause няма времево ограничение, но се препоръчва работата да приключи в рамките на 200 ms.

Какво е scenePhase в SwiftUI при Inactive?

ScenePhase.inactive — стойност на enum ScenePhase, задавана когато сцената е на преден план, но не приема събития. В SwiftUI можете да я наблюдавате чрез @Environment(\.scenePhase) и да реагирате чрез onChange. При преход от .active към .inactive спирайте таймерите и анимациите. При връщане в .active — възобновявайте. При преход в .background — запазвайте състоянието.

Трябва ли да се скрива UI при Inactive за всички приложения?

Не, само за приложения, работещи с поверителни данни: банкови, медицински, корпоративни, месинджъри с частни чатове. За игри и развлекателни приложения скриването на UI не се изисква. Въпреки това спирането на играта и звука при Inactive е добра практика, за да се избегне припокриване на звуци със системни известия. Apple препоръчва скриване на чувствителни данни, но не го изисква.

Обобщение

  • Inactive — преходно състояние между Active и Background, приложението видимо но неинтерактивно
  • Причини — Control Center, Notification Center, входящо обаждане, системни разрешения, Siri, Apple Pay
  • iOS обработка — applicationWillResignActive за спиране на анимации, медии и скриване на чувствителни данни
  • SwiftUI — scenePhase .inactive чрез Environment, onChange за странични ефекти
  • Android — onPause като аналог, с поддръжка на multi-window и частично покриване на Activity
  • Сигурност — blur наслагване или FLAG_SECURE за защита от скрийншотове на App Switcher и Control Center
  • Временен характер — Inactive продължава до края на прекъсването, след това връщане в Active или преход в Background

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

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

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

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