Not Running — что это, начальное состояние жизненного цикла

Автор: IT Sectr Опубликовано: 2026-03-03 Время чтения: 11 мин

Not Running — начальное состояние жизненного цикла мобильного приложения, в котором оно ещё не запущено или уже завершило работу. Узнайте, как система iOS и Android управляют этим состоянием, какие события приводят к переходу из Not Running и как правильно обрабатывать запуск и завершение приложения в Swift и Kotlin.

Главное

  • Not Running — приложение не загружено в память и не выполняет код, это точка входа и выхода в жизненном цикле
  • Запуск — переход из Not Running происходит при тапе на иконку, через deep link или push-уведомление
  • Завершение — пользователь закрывает приложение свайпом, система выгружает его при нехватке памяти или происходит краш
  • Холодный старт — приложение стартует с нуля, все объекты создаются заново, состояние не восстанавливается из кеша
  • Горячий старт — приложение было в Suspended и возвращается в Active без полной инициализации

Not Running — что это за состояние

Not Running — это базовое состояние жизненного цикла мобильного приложения, в котором оно не загружено в оперативную память устройства и не потребляет системные ресурсы. В iOS и Android это состояние означает полное отсутствие процессов и потоков, связанных с приложением. Пользователь видит иконку приложения на рабочем столе, но само приложение не активно и не находится в списке недавних.

Когда пользователь нажимает на иконку, система создаёт новый процесс, загружает исполняемый код в память и инициализирует все необходимые структуры данных. Этот процесс называется холодным стартом (cold start) и является самым ресурсоёмким с точки зрения времени загрузки.

Система может переместить приложение в Not Running из любого другого состояния. Если приложение находится в фоне (Background) или приостановлено (Suspended), операционная система имеет право выгрузить его при нехватке оперативной памяти для более приоритетных задач — например, для активного приложения на переднем плане.

Разработчик должен учитывать, что приложение может быть завершено системой в любой момент, когда оно находится в фоне. Это означает, что все несохранённые данные могут быть потеряны. Поэтому критически важно сохранять состояние в key-value хранилища (UserDefaults, SharedPreferences) или в локальную базу данных на переходах из Active в Background.

Как система определяет, какое приложение выгрузить

iOS использует приоритеты на основе текущего состояния приложения: Active имеет наивысший приоритет, затем Inactive, Background, Suspended и, наконец, Not Running — минимальный приоритет. Android использует похожую иерархию процессов: Foreground процесс имеет приоритет OOM_ADJ = 0, Visible процесс = 100, Service процесс = 200, Background процесс = 300, Empty процесс = 400. Чем выше значение, тем больше вероятность, что процесс будет завершён при нехватке памяти.

ПлатформаСостояниеПриоритет выгрузкиОписание
iOSNot RunningНаивысшийПриложение не загружено — системный ресурс не потребляется
iOSSuspendedВысокийПриложение в памяти, но код не выполняется — первая цель для выгрузки
iOSBackgroundСреднийПриложение выполняет фоновую задачу — выгружается после таймаута
iOSActiveНизкийАктивное приложение — выгружается только при критической нехватке памяти
AndroidEmpty ProcessНаивысшийПроцесс без активных компонентов — удаляется первым
AndroidBackground ProcessВысокийФоновый процесс без видимого Activity
AndroidForeground ServiceНизкийСервис с уведомлением — редко завершается
AndroidForeground ProcessМинимальныйАктивное Activity — завершается в последнюю очередь

Холодный и горячий старт приложения

Холодный старт (cold start) происходит, когда приложение переходит из Not Running напрямую в Active. Система создаёт новый процесс, загружает классы, инициализирует статические поля, создаёт главный поток и запускает UI-фреймворк. На iOS это означает вызов application(_:didFinishLaunchingWithOptions:), на Android — вызов Application.onCreate() и Activity.onCreate(). Время холодного старта может составлять от 200 мс до нескольких секунд в зависимости от сложности приложения.

Горячий старт (warm start или hot start) — приложение было в состоянии Suspended и возвращается к работе без полной перезагрузки. Система восстанавливает последний UI-стек из памяти, и пользователь продолжает работу с того же места. Горячий старт существенно быстрее холодного, так как большая часть кода уже загружена в память. На iOS горячий старт не вызывает application(_:didFinishLaunchingWithOptions:), только applicationWillEnterForeground и applicationDidBecomeActive.

Разница между холодным и горячим стартом критична для пользовательского опыта. При холодном старте разработчик должен убедиться, что запуск происходит максимально быстро — ленивая инициализация модулей, отложенная загрузка тяжёлых ресурсов, минимизация работы в главном потоке на старте. Google рекомендует холодный старт не более 500 мс, Apple — не более 400 мс для iOS.

kotlin
// Измерение времени холодного старта в Android
class App : Application() {
    private var startTime: Long = 0L

    override fun onCreate() {
        super.onCreate()
        startTime = System.currentTimeMillis()
    }

    fun getStartupTime(): Long {
        return System.currentTimeMillis() - startTime
    }
}

// Запуск Activity с ленивой инициализацией
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by lazy {
        ViewModelProvider(this).get(MainViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Только необходимый минимум для первого кадра
        setupNavigation()
    }

    override fun onPostCreate(savedInstanceState: Bundle?) {
        super.onPostCreate(savedInstanceState)
        // Тяжёлая инициализация после отрисовки
        initializeHeavyModules()
    }
}

В примере показано измерение времени холодного старта в Android. Application.onCreate() вызывается при переходе из Not Running в Active. Метка времени фиксируется при старте процесса. Activity использует ленивую инициализацию через lazy-делегат, чтобы не блокировать первый кадр. onPostCreate — оптимальное место для инициализации тяжёлых модулей, так как UI уже отрисован.

Not Running в iOS: Swift и AppDelegate

В iOS Not Running управляется через делегат UIApplicationDelegate. Ключевые методы: application(_:didFinishLaunchingWithOptions:) вызывается после холодного старта, applicationWillTerminate(_:) вызывается перед завершением приложения пользователем. При этом система может завершить приложение без вызова applicationWillTerminate — например, при аварийном завершении или выгрузке памяти. iOS не гарантирует вызов этого метода, поэтому сохранять данные нужно в applicationDidEnterBackground.

Сценарии перехода в Not Running на iOS

Пользователь может вручную завершить приложение свайпом в App Switcher. Система может выгрузить приложение из памяти в фоне. Приложение может аварийно завершиться (crash). Во всех случаях все объекты, созданные при запуске, уничтожаются. Состояние, которое не было сохранено, теряется безвозвратно. В iOS 13+ для сохранения состояния рекомендуется использовать NSUserActivity или механизм state restoration через UIApplication.stateRestorationIdentifier.

swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // Холодный старт: приложение перешло из Not Running
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Инициализация минимального набора сервисов
        setupAnalytics()
        configureAppearance()
        return true
    }

    // Приложение завершает работу — только ручное закрытие
    func applicationWillTerminate(
        _ application: UIApplication
    ) {
        saveCriticalData()
    }

    // Сохранение данных перед уходом в фон
    func applicationDidEnterBackground(
        _ application: UIApplication
    ) {
        saveApplicationState()
    }

    private func saveCriticalData() {
        UserDefaults.standard.synchronize()
    }

    private func saveApplicationState() {
        let state = ["lastScreen": "main", "timestamp": Date()]
        try? NSKeyedArchiver.archivedData(
            withRootObject: state,
            requiringSecureCoding: true
        )
    }
}

В коде показана корректная обработка Not Running на iOS. applicationWillTerminate вызывается только при ручном завершении пользователем. Сохранение критических данных дублируется в applicationDidEnterBackground, так как этот метод гарантированно вызывается перед уходом в фон. State restoration позволяет сохранить UI-стек для последующего восстановления при холодном старте.

Not Running в Android: Kotlin и процесс

В Android Not Running означает, что процесс приложения не существует. Система Linux, на которой основан Android, управляет процессами через механизм Zygote. При запуске приложения Zygote форкает новый процесс, загружает Dalvik/ART и вызывает Application.onCreate(). В Android нет прямого аналога applicationWillTerminate — система может завершить процесс в любой момент без предупреждения.

Жизненный цикл процесса Android

Когда Activity вызывается впервые, система создаёт процесс, Application и Activity через цепочку onCreate → onStart → onResume. Если пользователь нажимает Back, Activity уничтожается (onDestroy), и процесс может быть завершён системой. Ключевое отличие от iOS: в Android процесс может продолжать существовать даже без активных Activity — например, если работает Foreground Service или есть активный BroadcastReceiver.

kotlin
// Обработка Not Running через SavedStateHandle в ViewModel
class MainViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    companion object {
        private const val KEY_LAST_SCREEN = "last_screen"
        private const val KEY_USER_DATA = "user_data"
    }

    fun saveCurrentState(screen: String, data: String) {
        savedStateHandle[KEY_LAST_SCREEN] = screen
        savedStateHandle[KEY_USER_DATA] = data
    }

    fun restoreState(): AppState? {
        val screen = savedStateHandle.get<String>(KEY_LAST_SCREEN)
        val data = savedStateHandle.get<String>(KEY_USER_DATA)
        return if (screen != null && data != null) {
            AppState(screen, data)
        } else null
    }
}

// Application — первый коллбэк после Not Running
class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        initCrashReporter()
        initDependencyInjection()
    }
}

SavedStateHandle — компонент Android Architecture Components, который автоматически сохраняет состояние при переходе в Not Running и восстанавливает его при холодном старте. ViewModel, созданная через ViewModelProvider, переживает поворот экрана и уничтожение Activity. При завершении процесса данные из SavedStateHandle сериализуются в Bundle и сохраняются в saved instance state.

Причины перехода в Not Running

Not Running наступает по нескольким причинам. Пользователь вручную закрывает приложение. Система выгружает приложение при нехватке памяти. Приложение аварийно завершается с исключением. На Android система может завершить процесс при массовом обновлении приложений или перезагрузке устройства. iOS может завершить приложение при истечении таймаута фоновой задачи (обычно 30 секунд).

ПричинаiOSAndroidВозможность предотвратить
Ручное закрытие пользователемСвайп в App SwitcherСвайп из RecentsНет — пользовательское действие
Нехватка памятиСрабатывание memory warningonTrimMemory / LMKЧастично — оптимизация памяти
Краш приложенияNSException / сигналUncaughtException / ANRДа — обработка ошибок и краш-репортинг
Таймаут фоновой задачи30 сек на Background task10 мин на JobSchedulerДа — правильное планирование задач
Перезагрузка ОСВызов applicationWillTerminateBroadcast ACTION_SHUTDOWNНет — системное событие
Обновление приложенияНе происходит (iOS Sandbox)Процесс завершается при APK-обновленииНет — системное обновление

Как диагностировать переход в Not Running

Для iOS используйте консольное логирование в applicationWillTerminate и applicationDidFinishLaunching. Добавьте флаг в UserDefaults при каждом запуске — если при следующем старте флага нет, приложение было завершено некорректно. На Android используйте ActivityManager.isBackgroundRestricted(), чтобы проверить, может ли приложение запускать фоновые задачи. Также отслеживайте onTrimMemory(TRIM_MEMORY_COMPLETE) — это сигнал, что процесс будет завершён.

Лучшие практики работы с Not Running

Первое правило — никогда не рассчитывайте, что applicationWillTerminate или onDestroy будут вызваны. Сохраняйте критически важные данные при каждом переходе из Active в Background. Используйте key-value хранилища для простых настроек и SQLite/Room для структурированных данных.

Второе правило — измеряйте время холодного старта и оптимизируйте его. Ленивая инициализация, минимизация работы в главном потоке, предварительная загрузка ресурсов, использование SplashScreen API — всё это улучшает восприятие времени запуска. Google рекомендует холодный старт менее 200 мс для отличного UX.

Третье правило — реализуйте State Restoration. На iOS используйте UIApplication.stateRestorationIdentifier и NSUserActivity. На Android используйте SavedStateHandle в ViewModel в сочетании с onSaveInstanceState. Это позволит пользователю продолжить работу с того же места после перезапуска приложения.

Четвёртое правило — обрабатывайте launchOptions и Intent, с которыми приложение было запущено после Not Running. Deep links, push-уведомления, универсальные ссылки — все они передаются через параметры запуска. Разработчик должен корректно извлечь эти данные и направить пользователя на соответствующий экран.

swift
// Обработка deep link после холодного старта
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    // Проверка, пришло ли уведомление
    if let notification = launchOptions?[.remoteNotification] as? [String: Any] {
        handleNotification(notification)
    }
    // Проверка deep link
    if let url = launchOptions?[.url] as? URL {
        handleDeepLink(url)
    }
    return true
}

private func handleDeepLink(_ url: URL) {
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
          let screenId = components.queryItems?.first(where: { $0.name == "screen" })?.value
    else { return }
    openScreen(screenId)
}

В коде показана обработка параметров запуска при холодном старте iOS. launchOptions содержит данные, с которыми система запустила приложение. Уведомления, deep links и универсальные ссылки передаются через этот словарь. Разработчик должен корректно обработать все возможные сценарии запуска, чтобы обеспечить бесшовный пользовательский опыт.

Часто задаваемые вопросы

Что происходит с данными при переходе в Not Running?

Данные, которые были сохранены в постоянное хранилище (UserDefaults, Core Data, SharedPreferences, Room), сохраняются. Данные в оперативной памяти — переменные, кеш, состояние ViewModel без SavedStateHandle — теряются безвозвратно. Поэтому критически важно сохранять состояние приложения при каждом переходе в Background.

Как отличить холодный старт от горячего на iOS?

При холодном старте вызывается application(_:didFinishLaunchingWithOptions:). При горячем старте (возврат из Suspended) этот метод не вызывается — срабатывают только applicationWillEnterForeground и applicationDidBecomeActive. Если вам нужно выполнить действие только при холодном старте, установите флаг в didFinishLaunchingWithOptions.

Может ли Android приложение быть в Not Running с активным Service?

Да. Foreground Service с постоянным уведомлением предотвращает завершение процесса системой, даже если все Activity уничтожены. Background Service (startService без foreground) может быть остановлен системой в любое время. Работающий Service означает, что процесс существует, и это уже не Not Running.

Как эмулировать Not Running на симуляторе?

На iOS симуляторе завершите приложение через App Switcher (Cmd+Shift+H дважды, свайп вверх). На Android эмуляторе используйте adb shell am force-stop com.example.app или кнопку Stop в Logcat. После этого запустите приложение заново — это будет чистый холодный старт из Not Running.

Что такое kill-switch в контексте Not Running?

Kill-switch — серверная команда экстренного завершения приложения. Используется в банковских и корпоративных приложениях для удалённой блокировки доступа. Если приложение получило kill-команду, при следующем холодном старте оно блокирует UI и запрашивает повторную авторизацию. На iOS kill-switch реализуется через remote notifications с флагом блокировки.

Итоги

  • Not Running — начальное и конечное состояние жизненного цикла, приложение не загружено в память и не выполняет код
  • Холодный старт — полная перезагрузка приложения из Not Running, требует инициализации всех компонентов с нуля
  • Горячий старт — возврат из Suspended, не вызывает didFinishLaunchingWithOptions или Application.onCreate
  • Сохранение данных — критически важно выполнять при переходе в Background, так как Not Running может наступить в любой момент
  • iOS — applicationWillTerminate не гарантирован, состояние сохраняется через UserDefaults или state restoration
  • Android — процесс может быть завершён в любой момент, SavedStateHandle в ViewModel сохраняет состояние автоматически
  • Оптимизация старта — ленивая инициализация, минимальная работа в main thread, SplashScreen API для быстрого первого кадра

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

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также