Not Running — What It Is, the Initial Lifecycle State

Author: IT Sectr Published: 2026-03-03 Reading time: 11 min

Not Running — the initial lifecycle state of a mobile application when it has not been launched yet or has already terminated. Learn how iOS and Android manage this state, what events lead to a transition from Not Running, and how to properly handle application launch and termination in Swift and Kotlin.

Key Takeaways

  • Not Running — the application is not loaded into memory and is not executing code; it is the entry and exit point of the lifecycle
  • Launch — transition from Not Running occurs when tapping the app icon, via deep link, or push notification
  • Termination — the user closes the app with a swipe, the system unloads it due to low memory, or a crash occurs
  • Cold start — the application starts from scratch, all objects are created anew, state is not restored from cache
  • Hot start — the application was in Suspended and returns to Active without full initialization

Not Running — What Is This State

Not Running is the basic lifecycle state of a mobile application in which it is not loaded into the device’s RAM and does not consume system resources. In iOS and Android, this state means the complete absence of processes and threads associated with the application. The user sees the app icon on the home screen, but the application itself is not active and is not in the recent apps list.

When the user taps the app icon, the system creates a new process, loads the executable code into memory, and initializes all necessary data structures. This process is called a cold start and is the most resource-intensive in terms of load time.

The system can move the application to Not Running from any other state. If the application is in the background or suspended, the operating system has the right to unload it when there is insufficient RAM for higher-priority tasks — for example, for an active foreground application.

The developer must consider that the application can be terminated by the system at any moment when it is in the background. This means that all unsaved data may be lost. Therefore, it is critically important to save state in key-value stores (UserDefaults, SharedPreferences) or a local database during transitions from Active to Background.

How the System Determines Which Application to Unload

iOS uses priorities based on the current application state: Active has the highest priority, followed by Inactive, Background, Suspended, and finally Not Running — the lowest priority. Android uses a similar process hierarchy: Foreground process has priority OOM_ADJ = 0, Visible process = 100, Service process = 200, Background process = 300, Empty process = 400. The higher the value, the more likely the process will be terminated when memory is low.

PlatformStateUnload PriorityDescription
iOSNot RunningHighestApplication not loaded — no system resources consumed
iOSSuspendedHighApplication in memory but code not executing — first target for unloading
iOSBackgroundMediumApplication executing a background task — unloaded after timeout
iOSActiveLowActive application — unloaded only under critical memory pressure
AndroidEmpty ProcessHighestProcess with no active components — removed first
AndroidBackground ProcessHighBackground process without a visible Activity
AndroidForeground ServiceLowService with a notification — rarely terminated
AndroidForeground ProcessMinimumActive Activity — terminated last

Cold vs Warm Start of an Application

Cold start occurs when the application transitions from Not Running directly to Active. The system creates a new process, loads classes, initializes static fields, creates the main thread, and starts the UI framework. On iOS, this means calling application(_:didFinishLaunchingWithOptions:), on Android — calling Application.onCreate() and Activity.onCreate(). Cold start time can range from 200 ms to several seconds depending on the application’s complexity.

Warm start (or hot start) — the application was in the Suspended state and resumes without a full reload. The system restores the last UI stack from memory, and the user continues working from the same point. A warm start is significantly faster than a cold start because most of the code is already loaded into memory. On iOS, a warm start does not call application(_:didFinishLaunchingWithOptions:), only applicationWillEnterForeground and applicationDidBecomeActive.

The difference between cold and warm start is critical for user experience. During a cold start, the developer must ensure that the launch happens as quickly as possible — lazy initialization of modules, deferred loading of heavy resources, minimizing work on the main thread at startup. Google recommends a cold start of no more than 500 ms, Apple — no more than 400 ms for iOS.

kotlin
// Measuring cold start time in Android
class App : Application() {
    private var startTime: Long = 0L

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

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

// Starting Activity with lazy initialization
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)
        // Only the necessary minimum for the first frame
        setupNavigation()
    }

    override fun onPostCreate(savedInstanceState: Bundle?) {
        super.onPostCreate(savedInstanceState)
        // Heavy initialization after rendering
        initializeHeavyModules()
    }
}

The example shows measuring cold start time in Android. Application.onCreate() is called when transitioning from Not Running to Active. The timestamp is recorded at process start. The Activity uses lazy initialization via a lazy delegate to avoid blocking the first frame. onPostCreate is the optimal place to initialize heavy modules since the UI has already been rendered.

Not Running in iOS: Swift and AppDelegate

In iOS, Not Running is managed through the UIApplicationDelegate protocol. Key methods: application(_:didFinishLaunchingWithOptions:) is called after a cold start, applicationWillTerminate(_:) is called before the user terminates the application. However, the system may terminate the application without calling applicationWillTerminate — for example, during an emergency termination or memory pressure. iOS does not guarantee that this method will be called, so data should be saved in applicationDidEnterBackground.

Transition Scenarios to Not Running on iOS

The user can manually terminate the application with a swipe in the App Switcher. The system can unload the application from memory while in the background. The application may crash. In all cases, all objects created during launch are destroyed. State that was not saved is lost forever. In iOS 13+, it is recommended to use NSUserActivity or the state restoration mechanism via UIApplication.stateRestorationIdentifier to preserve state.

swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // Cold start: application transitioned from Not Running
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Initializing the minimum set of services
        setupAnalytics()
        configureAppearance()
        return true
    }

    // Application terminates — only manual close
    func applicationWillTerminate(
        _ application: UIApplication
    ) {
        saveCriticalData()
    }

    // Saving data before going to the background
    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
        )
    }
}

The code demonstrates correct Not Running handling on iOS. applicationWillTerminate is only called when the user manually terminates the app. Saving critical data is duplicated in applicationDidEnterBackground since this method is guaranteed to be called before going to the background. State restoration allows saving the UI stack for later recovery during a cold start.

Not Running in Android: Kotlin and Process

In Android, Not Running means the application process does not exist. The Linux system underlying Android manages processes through the Zygote mechanism. When an application launches, Zygote forks a new process, loads Dalvik/ART, and calls Application.onCreate(). Android does not have a direct equivalent of applicationWillTerminate — the system can terminate the process at any time without warning.

Android Process Lifecycle

When an Activity is first called, the system creates the process, Application, and Activity through the chain onCreate → onStart → onResume. If the user presses Back, the Activity is destroyed (onDestroy), and the process may be terminated by the system. A key difference from iOS: in Android, the process can continue to exist even without active Activities — for example, if a Foreground Service is running or there is an active BroadcastReceiver.

kotlin
// Handling Not Running via SavedStateHandle in 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 — the first callback after Not Running
class MyApplication : Application() {

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

SavedStateHandle is a component of Android Architecture Components that automatically saves state during a transition to Not Running and restores it on a cold start. A ViewModel created via ViewModelProvider survives screen rotation and Activity destruction. When the process terminates, data from SavedStateHandle is serialized into a Bundle and saved in the saved instance state.

Reasons for Transitioning to Not Running

Not Running occurs for several reasons. The user manually closes the application. The system unloads the application due to low memory. The application crashes with an exception. On Android, the system may terminate the process during a mass app update or device reboot. iOS may terminate the application when a background task times out (usually 30 seconds).

ReasoniOSAndroidCan Be Prevented
Manual close by userSwipe in App SwitcherSwipe from RecentsNo — user action
Low memoryMemory warning triggeredonTrimMemory / LMKPartially — memory optimization
Application crashNSException / signalUncaughtException / ANRYes — error handling and crash reporting
Background task timeout30 sec for Background task10 min for JobSchedulerYes — proper task scheduling
OS rebootapplicationWillTerminate calledBroadcast ACTION_SHUTDOWNNo — system event
App updateDoes not occur (iOS Sandbox)Process terminated on APK updateNo — system update

How to Diagnose a Transition to Not Running

For iOS, use console logging in applicationWillTerminate and applicationDidFinishLaunching. Add a flag in UserDefaults on each launch — if the flag is missing on the next start, the application was terminated improperly. On Android, use ActivityManager.isBackgroundRestricted() to check whether the application can run background tasks. Also, monitor onTrimMemory(TRIM_MEMORY_COMPLETE) — this is a signal that the process will be terminated.

Best Practices for Working with Not Running

First rule — never assume that applicationWillTerminate or onDestroy will be called. Save critically important data on every transition from Active to Background. Use key-value stores for simple settings and SQLite/Room for structured data.

Second rule — measure cold start time and optimize it. Lazy initialization, minimizing work on the main thread, preloading resources, using the SplashScreen API — all of these improve perceived launch time. Google recommends a cold start of less than 200 ms for excellent UX.

Third rule — implement State Restoration. On iOS, use UIApplication.stateRestorationIdentifier and NSUserActivity. On Android, use SavedStateHandle in ViewModel combined with onSaveInstanceState. This will allow the user to continue working from the same point after an app restart.

Fourth rule — handle launchOptions and Intent with which the application was started after Not Running. Deep links, push notifications, universal links — all of these are passed through launch parameters. The developer must correctly extract this data and navigate the user to the appropriate screen.

swift
// Handling deep link after cold start
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    // Checking if a notification arrived
    if let notification = launchOptions?[.remoteNotification] as? [String: Any] {
        handleNotification(notification)
    }
    // Checking 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)
}

The code shows handling of launch parameters on iOS cold start. launchOptions contains the data with which the system launched the application. Notifications, deep links, and universal links are passed through this dictionary. The developer must correctly handle all possible launch scenarios to ensure a seamless user experience.

Frequently Asked Questions

What happens to data when transitioning to Not Running?

Data that was saved to persistent storage (UserDefaults, Core Data, SharedPreferences, Room) is preserved. Data in RAM — variables, cache, ViewModel state without SavedStateHandle — is irretrievably lost. Therefore, it is critically important to save application state on every transition to the Background.

How to distinguish a cold start from a hot start on iOS?

During a cold start, application(_:didFinishLaunchingWithOptions:) is called. During a hot start (return from Suspended), this method is not called — only applicationWillEnterForeground and applicationDidBecomeActive are triggered. If you need to perform an action only on a cold start, set a flag in didFinishLaunchingWithOptions.

Can an Android application be in Not Running with an active Service?

Yes. A Foreground Service with a persistent notification prevents the system from terminating the process, even if all Activities are destroyed. A Background Service (startService without foreground) can be stopped by the system at any time. A running Service means the process exists, and this is no longer Not Running.

How to emulate Not Running on a simulator?

On the iOS simulator, terminate the app through the App Switcher (Cmd+Shift+H twice, swipe up). On the Android emulator, use adb shell am force-stop com.example.app or the Stop button in Logcat. After that, launch the application again — this will be a clean cold start from Not Running.

What is a kill-switch in the context of Not Running?

Kill-switch is a server command for emergency application termination. It is used in banking and enterprise applications for remote access blocking. If the application receives a kill command, on the next cold start it blocks the UI and requests reauthentication. On iOS, a kill-switch is implemented via remote notifications with a blocking flag.

Summary

  • Not Running — the initial and final lifecycle state, the application is not loaded into memory and is not executing code
  • Cold start — full restart of the application from Not Running, requires initializing all components from scratch
  • Hot start — return from Suspended, does not call didFinishLaunchingWithOptions or Application.onCreate
  • Data saving — critically important to perform when transitioning to Background, as Not Running can occur at any moment
  • iOS — applicationWillTerminate is not guaranteed, state is saved via UserDefaults or state restoration
  • Android — the process can be terminated at any time, SavedStateHandle in ViewModel saves state automatically
  • Startup optimization — lazy initialization, minimal work on the main thread, SplashScreen API for a fast first frame

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also