Active: какво е, състояние Active в жизнения цикъл на iOS

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

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

Основни

  • Active — приложение на преден план, UIResponder получава събития на допир, приложението е напълно интерактивно
  • applicationDidBecomeActive — основният метод, сигнализиращ за преход в Active на iOS
  • ScenePhase.active — еквивалент за SwiftUI, проследяван чрез Environment values
  • Връщане от Inactive — след повикване, известие или Control Center приложението отново става Active
  • Ресурси — в състояние Active приложението има най-висок приоритет по памет и процесор

Active: какво е това състояние

Active — състояние на жизнения цикъл на мобилно приложение, в което то се намира на преден план, показва се на екрана на устройството и активно взаимодейства с потребителя. В това състояние приложението получава всички събития на допир, натискания на клавиши, данни от акселерометъра и жироскопа, както и има пълен достъп до графичния процесор за рендиране на интерфейса.

На iOS състоянието Active е част от петсъстоятелния модел на жизнения цикъл: Not Running → Inactive → Active → Inactive → Background → Suspended → Not Running. На Android аналогът е състоянието на Activity след извикване на onResume, когато Activity се намира на върха на стека и приема потребителски вход. Active е единственото състояние, в което UI е напълно интерактивен и реагира на жестове, скрол, кликвания и анимации.

Системата предоставя на приложението в Active максимален приоритет по процесор и RAM. Това означава, че системата няма да прекрати такова приложение при недостиг на ресурси — първо ще бъдат разтоварени фоновете и спрените процеси. Приложението обаче трябва да използва ресурсите ефективно, за да не разрежда батерията и да не предизвиква throttling на CPU.

За потребителя Active е нормалното състояние на работа с приложението. Потребителят вижда интерфейса, може да натиска бутони, да попълва формуляри, да скролира фийда. Всяко прекъсване на това състояние (повикване, известие, плъзгане нагоре за Control Center) прехвърля приложението в Inactive, след което то може да се върне в Active или да отиде в Background.

Как системата определя, че приложението е Active

iOS използва UIApplicationMain за управление на състоянието. При преход в Active системата извиква applicationDidBecomeActive. За SwiftUI аналогичният механизъм е наблюдение на scenePhase чрез Environment. Android използва onResume като индикатор за активност на Activity на преден план. И двата подхода гарантират, че приложението получава известие за промяна на състоянието и може да адаптира поведението си.

ПлатформаМетод/събитиеSwift (UIKit)SwiftUIAndroid (Kotlin)
iOSПреход в ActiveapplicationDidBecomeActivescenePhase == .active
iOSИзлизане от ActiveapplicationWillResignActivescenePhase == .inactive
AndroidПреход в ActiveonResume()
AndroidИзлизане от ActiveonPause()

Active в iOS: Swift, UIKit и SwiftUI

В iOS състоянието Active се обработва чрез UIApplicationDelegate. Основният метод — applicationDidBecomeActive(_:). Той се извиква при първото стартиране на приложението и при връщане от Inactive. Този метод е идеалното място за възобновяване на задачи, които са били спрени при прехода в Inactive: стартиране на анимации, възобновяване на таймери, рестартиране на сензори, проверка на актуализации на данни на сървъра.

UIKit: AppDelegate и SceneDelegate

От iOS 13 Apple представи UISceneDelegate за поддръжка на множество прозорци на iPad. В този случай applicationDidBecomeActive се заменя с sceneDidBecomeActive за всяка сцена. Приложенията, поддържащи само един екран, могат да продължат да използват UIApplicationDelegate. И двата подхода се извикват в момента, когато приложението или сцената стане активна.

swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // Приложението стана активно — възобновяваме задачите
    func applicationDidBecomeActive(_ application: UIApplication) {
        resumeAnimations()
        restartTimers()
        refreshDataIfNeeded()
        startObservingSensors()
    }

    // Приложението губи активност — спираме
    func applicationWillResignActive(_ application: UIApplication) {
        pauseAnimations()
        stopTimers()
        saveDraftData()
    }

    private func resumeAnimations() {
        UIView.animate(withDuration: 0.3) {
            // Възобновяване на UI анимации
        }
    }

    private func refreshDataIfNeeded() {
        let lastRefresh = UserDefaults.standard.object(forKey: "lastRefresh") as? Date ?? .distantPast
        if Date().timeIntervalSince(lastRefresh) > 300 {
            fetchDataFromServer()
        }
    }
}

Кодът показва правилната обработка на Active в UIKit. applicationDidBecomeActive възобновява анимации, таймери и проверява дали е необходима актуализация на данни. applicationWillResignActive спира всичко, което може да консумира ресурси, и запазва чернови. Такава двойка методи гарантира, че приложението реагира правилно на промяна на състоянието.

SwiftUI: scenePhase

В SwiftUI няма AppDelegate — управлението на състоянието става чрез Environment<ScenePhase>. Стойността .active се задава, когато сцената е на преден план и е интерактивна. SwiftUI автоматично рестартира анимациите и актуализациите при връщане в Active. Разработчикът трябва само да се абонира за onChange за изпълнение на странични ефекти.

swift
import SwiftUI

@main
struct ActiveDemoApp: App {
    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { oldPhase, newPhase in
            switch newPhase {
            case .active:
                print("Сцената стана активна")
                resumeWork()
            case .inactive:
                print("Сцената стана неактивна")
                pauseWork()
            case .background:
                print("Сцената отиде във фонов режим")
                saveState()
            @unknown default:
                break
            }
        }
    }

    private func resumeWork() {
        // Възобновяване на мрежови заявки, анимации
    }

    private func pauseWork() {
        // Спиране на чувствителни към време задачи
    }

    private func saveState() {
        // Запазване на състоянието на приложението
    }
}

В SwiftUI scenePhase е единственият източник на истина за състоянието на приложението. onChange позволява изпълнение на действия при всеки преход. Важно е да запомните, че scenePhase е достъпен само на iOS 14+ и в SwiftUI Lifecycle. За UIKit приложения с SwiftUI екрани използвайте подхода с UIApplicationDelegate.

Преходи в състояние Active

Active може да бъде достигнато по няколко начина. Първият и очевиден — студен старт: потребителят натиска иконата, приложението преминава от Not Running през Inactive в Active. Вторият — връщане от фон: потребителят се връща в приложението чрез App Switcher, приложението преминава през Inactive и става Active. Третият — връщане от временно прекъсване: потребителят приключва повикване, затваря Control Center или отговаря на известие — приложението се връща от Inactive в Active.

Верига от преходи в Active

Not Running → Inactive → Active — студен старт. Background → Inactive → Active — връщане от фон. Inactive → Active — връщане от временно прекъсване. Във всеки случай applicationDidBecomeActive се извиква, но контекстът може да е различен. При студен старт преди Active се извиква didFinishLaunchingWithOptions, при връщане от фон — willEnterForeground. Разработчикът може да използва тези разлики за избор на стратегия за възстановяване на състоянието.

СценарийПът на преходCallback-и iOSCallback-и Android
Студен стартNot Running → ActivedidFinishLaunching → didBecomeActiveonCreate → onStart → onResume
Връщане от фонBackground → ActivewillEnterForeground → didBecomeActiveonRestart → onStart → onResume
Връщане от SuspendedSuspended → ActivewillEnterForeground → didBecomeActiveonRestart → onStart → onResume
След прекъсванеInactive → ActivedidBecomeActiveonResume

Важна забележка: при връщане от Suspended iOS не извиква didFinishLaunchingWithOptions, тъй като приложението вече е било заредено в паметта. Това означава, че инициализационният код, поставен в този метод, не се изпълнява повторно. Разработчиците често забравят за това и преместват критичната логика в applicationWillEnterForeground или applicationDidBecomeActive и за двата сценария.

Active в Android: жизнен цикъл на Activity

В Android аналогът на Active е състоянието на Activity след извикване на onResume(). Activity се счита за активно, когато е на преден план и приема потребителски вход. Това състояние съответства на върха на стека от Activity. Ако друго Activity се появи отгоре (дори частично), текущото Activity преминава в състояние onPause — аналог на iOS Inactive.

Ключовата разлика на Android — множество Activity могат да бъдат активни едновременно в multi-window режим (split screen, freeform). В този случай Activity, с което потребителят взаимодейства, се счита за активно, а съседното — за спряно (onPause). iOS не поддържа multi-window на iPhone, само на iPad чрез UIScene.

kotlin
class MainActivity : AppCompatActivity() {

    override fun onResume() {
        super.onResume()
        // Приложението стана активно — възобновяваме задачите
        resumeCameraPreview()
        startLocationUpdates()
        activateSensors()
    }

    override fun onPause() {
        super.onPause()
        // Приложението губи активност — освобождаваме ресурси
        releaseCamera()
        stopLocationUpdates()
        deactivateSensors()
    }

    private fun resumeCameraPreview() {
        // Стартиране на преглед на камерата (изисква разрешение)
        cameraProvider?.unbindAll()
        cameraProvider?.bindToLifecycle(
            this,
            cameraSelector,
            preview,
            imageAnalyzer
        )
    }

    private fun startLocationUpdates() {
        val locationRequest = LocationRequest.Builder(
            Priority.PRIORITY_HIGH_ACCURACY, 5000
        ).build()
        locationClient.requestLocationUpdates(
            locationRequest,
            locationCallback,
            Looper.getMainLooper()
        )
    }
}

Кодът показва обработката на Active в Android чрез onResume/onPause. onResume възобновява работата с камерата, геолокацията и сензорите — ресурси, които трябва да са активни само когато приложението е видимо за потребителя. onPause освобождава тези ресурси, за да не разрежда батерията. CameraX lifecycle-aware API автоматично спира прегледа при onPause.

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

Първо правило — не изпълнявайте тежки операции в applicationDidBecomeActive или onResume. Зареждане на данни, парсване на JSON, работа с база данни — всичко това трябва да бъде асинхронно и да не блокира основната нишка. Използвайте GCD (DispatchQueue) в iOS и Coroutines в Kotlin за фонови задачи. Основната нишка трябва само да актуализира UI и да стартира асинхронни операции.

Второ правило — синхронизирайте състоянието при всяко връщане в Active. Потребителят може да е променил настройки в системното приложение, да е получил push известие или да е актуализирал данни в друго приложение. Проверявайте актуалността на кеша при преход в Active — може би данните са остарели по време на отсъствието на потребителя.

Трето правило — не разчитайте на Active като единствено състояние. Приложението може да пропусне Active и да премине директно от Not Running в Background (ако е пуснато във фонов режим). На iOS това се случва при стартиране чрез push известие с опция content-available. На Android — при стартиране чрез BroadcastReceiver. Винаги проверявайте текущото състояние преди изпълнение на UI операции.

Четвърто правило — използвайте Activity Result API на Android вместо onActivityResult. Това позволява обработка на резултата от извикване на камера, галерия или разрешения директно в състояние Active без загуба на данни при повторно създаване на Activity. За iOS използвайте async/await с UIApplication.shared.open за системни диалози.

swift
import UIKit

final class ActiveStateManager {
    static let shared = ActiveStateManager()
    private var isActive = false

    func setActive(_ active: Bool) {
        isActive = active
        if active {
            NotificationCenter.default.post(name: .appDidBecomeActive, object: nil)
        }
    }

    func performWhenActive(_ block: @escaping () -> Void) {
        if isActive {
            block()
        } else {
            // Отложи изпълнението до връщане в Active
            NotificationCenter.default.addObserver(
                forName: .appDidBecomeActive,
                object: nil,
                queue: .main
            ) { _ in
                block()
            }
        }
    }
}

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

Кодът показва мениджър на състояние Active, който позволява на други компоненти на приложението да проверяват текущото активно състояние. performWhenActive или изпълнява блока незабавно (ако приложението е активно), или отлага изпълнението до връщане в Active. Това е полезно за услуги, които трябва да изпълнят действие, след като потребителят се върне в приложението.

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

Колко често се извиква applicationDidBecomeActive?

Методът се извиква всеки път, когато приложението преминава в активно състояние: при първо стартиране, при връщане от фон, след затваряне на Control Center или Notification Center, след приключване на повикване. В нормална сесия може да бъде извикан 5–10 пъти в зависимост от действията на потребителя. Не поставяйте еднократна инициализация в този метод.

Каква е разликата между Active и Visible на iOS?

Visible — неофициален термин, означаващ, че приложението е видимо на екрана, но може да не приема събития (например частично покрито от друг прозорец на iPad). Active — официално състояние, в което приложението е едновременно видимо и интерактивно. На iPhone Visible приложението винаги е Active, на iPad е възможна ситуация Visible + Inactive.

Какво е didBecomeActive vs willEnterForeground?

willEnterForeground се извиква при връщане от фон, но приложението все още не е активно — то е в Inactive. didBecomeActive се извиква, след като приложението е станало напълно интерактивно. Ако трябва да изпълните действие, преди потребителят да види интерфейса — използвайте willEnterForeground. Ако след показване — didBecomeActive.

Може ли приложение да бъде Active без видим UI?

Не. Active предполага, че приложението е на преден план и се показва на екрана. Без видим UI приложението може да бъде в Background или Suspended. Изключение — iPad multi-window, където един прозорец може да бъде активен, а друг не, но и двата са видими. VoiceOver и диктофон не променят това правило.

Как да тестваме прехода в Active на симулатора?

На iOS симулатора натиснете Cmd+Shift+H за отиване на началния екран (приложението преминава в Background), след това кликнете отново върху иконата на приложението. Използвайте Cmd+L за заключване на екрана (willResignActive) и отключване (didBecomeActive). За тестване на Inactive извикайте Control Center (Cmd+Shift+; за macOS клавиатура) или Notification Center.

Резюме

  • Active — състояние на приложение на преден план с пълен достъп до потребителски вход и максимален приоритет на ресурсите
  • iOS UIKit — applicationDidBecomeActive за възобновяване на анимации, таймери и сензори
  • SwiftUI — scenePhase .active чрез Environment, onChange за странични ефекти
  • Android — onResume/onPause като аналог на Active/Inactive, с поддръжка на multi-window
  • Преходи — Active се достига от Not Running (студен старт), Background и Inactive
  • Ресурси — тежки операции в didBecomeActive трябва да бъдат асинхронни, да не блокират основната нишка
  • Синхронизация — проверка на актуалността на кеша и данните при всяко връщане в Active

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

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

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

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