Not Running — det initiala tillståndet i livscykeln för en mobilapp, där appen ännu inte har startats eller redan har avslutat sin verksamhet. Lär dig hur iOS och Android-systemet hanterar detta tillstånd, vilka händelser som leder till övergången från Not Running och hur man korrekt hanterar start och avslutning av appen i Swift och Kotlin.
Huvudpunkter
Not Running — är grundtillståndet i livscykeln för en mobilapp, där appen inte är laddad i enhetens RAM-minne och inte förbrukar systemresurser. I iOS och Android innebär detta tillstånd fullständig frånvaro av processer och trådar som är associerade med appen. Användaren ser appikonen på skrivbordet, men själva appen är inte aktiv och finns inte i listan över nyligen använda.
När användaren trycker på ikonen skapar systemet en ny process, laddar den körbara koden i minnet och initierar alla nödvändiga datastrukturer. Denna process kallas kall start (cold start) och är den mest resurskrävande när det gäller laddningstid.
Systemet kan flytta appen till Not Running från vilket annat tillstånd som helst. Om appen är i bakgrunden (Background) eller pausad (Suspended) har operativsystemet rätt att avlasta den vid RAM-brist för mer prioriterade uppgifter — till exempel för en aktiv app i förgrunden.
Utvecklaren måste vara medveten om att appen kan avslutas av systemet när som helst när den är i bakgrunden. Detta innebär att all osparad data kan gå förlorad. Därför är det kritiskt viktigt att spara tillståndet i nyckel-värde-lager (UserDefaults, SharedPreferences) eller i en lokal databas vid övergångar från Active till Background.
iOS använder prioriteter baserat på appens aktuella tillstånd: Active har högst prioritet, därefter Inactive, Background, Suspended och slutligen Not Running — lägst prioritet. Android använder en liknande processhierarki: Foreground-processen har prioritet OOM_ADJ = 0, Visible-process = 100, Service-process = 200, Background-process = 300, Empty-process = 400. Ju högre värde, desto större är sannolikheten att processen avslutas vid minnesbrist.
| Plattform | Tillstånd | Avlastningsprioritet | Beskrivning |
|---|---|---|---|
| iOS | Not Running | Högst | Appen inte laddad — systemresurs förbrukas inte |
| iOS | Suspended | Hög | App i minnet, men kod körs inte — första målet för avlastning |
| iOS | Background | Medel | App utför bakgrundsuppgift — avlastas efter timeout |
| iOS | Active | Låg | Aktiv app — avlastas endast vid kritisk minnesbrist |
| Android | Empty Process | Högst | Process utan aktiva komponenter — tas bort först |
| Android | Background Process | Hög | Bakgrundsprocess utan synlig Activity |
| Android | Foreground Service | Låg | Tjänst med notis — sällan avslutad |
| Android | Foreground Process | Minimal | Aktiv Activity — avslutas sist |
Kall start (cold start) inträffar när appen övergår från Not Running direkt till Active. Systemet skapar en ny process, laddar klasser, initierar statiska fält, skapar huvudtråden och startar UI-ramverket. I iOS innebär detta anrop av application(_:didFinishLaunchingWithOptions:), i Android — anrop av Application.onCreate() och Activity.onCreate(). Tiden för kall start kan variera från 200 ms till flera sekunder beroende på appens komplexitet.
Varm start (warm start eller hot start) — appen var i tillståndet Suspended och återgår till drift utan fullständig omladdning. Systemet återställer den senaste UI-stacken från minnet och användaren fortsätter arbetet från samma plats. Varm start är betydligt snabbare än kall start, eftersom större delen av koden redan är laddad i minnet. I iOS anropar varm start inte application(_:didFinishLaunchingWithOptions:), endast applicationWillEnterForeground och applicationDidBecomeActive.
Skillnaden mellan kall och varm start är kritisk för användarupplevelsen. Vid kall start måste utvecklaren se till att starten sker så snabbt som möjligt — lat initiering av moduler, fördröjd laddning av tunga resurser, minimering av arbete i huvudtråden vid start. Google rekommenderar kall start högst 500 ms, Apple — högst 400 ms för iOS.
// Mätning av kall start-tid i Android
class App : Application() {
private var startTime: Long = 0L
override fun onCreate() {
super.onCreate()
startTime = System.currentTimeMillis()
}
fun getStartupTime(): Long {
return System.currentTimeMillis() - startTime
}
}
// Starta Activity med lat initiering
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)
// Endast nödvändigt minimum för första bildrutan
setupNavigation()
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
// Tung initiering efter rendering
initializeHeavyModules()
}
}Exemplet visar mätning av kall start-tid i Android. Application.onCreate() anropas vid övergången från Not Running till Active. Tidsstämpeln registreras vid processens start. Activity anväver lat initiering via lazy-delegaten för att inte blockera den första bildrutan. onPostCreate är den optimala platsen för initiering av tunga moduler, eftersom UI redan är renderat.
I iOS hanteras Not Running via delegaten UIApplicationDelegate. Viktiga metoder: application(_:didFinishLaunchingWithOptions:) anropas efter kall start, applicationWillTerminate(_:) anropas före avslutning av appen av användaren. Systemet kan avsluta appen utan att anropa applicationWillTerminate — till exempel vid nödavslutning eller minnesavlastning. iOS garanterar inte att denna metod anropas, därför bör data sparas i applicationDidEnterBackground.
Användaren kan manuellt avsluta appen med en svepgest i App Switcher. Systemet kan avlasta appen från minnet i bakgrunden. Appen kan nödavslutas (krascha). I alla fall förstörs alla objekt som skapats under starten. Tillstånd som inte sparats går oåterkalleligen förlorat. I iOS 13+ för att spara tillstånd rekommenderas att använda NSUserActivity eller mekanismen för state restoration via UIApplication.stateRestorationIdentifier.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Kall start: appen övergick från Not Running
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Initiering av minimal tjänsteuppsättning
setupAnalytics()
configureAppearance()
return true
}
// Appen avslutar — endast manuell stängning
func applicationWillTerminate(
_ application: UIApplication
) {
saveCriticalData()
}
// Spara data före övergång till bakgrunden
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
)
}
}Koden visar korrekt hantering av Not Running i iOS. applicationWillTerminate anropas endast vid manuell avslutning av användaren. Spara kritisk data dupliceras i applicationDidEnterBackground, eftersom denna metod garanterat anropas före övergång till bakgrunden. State restoration gör det möjligt att spara UI-stacken för senare återställning vid kall start.
I Android innebär Not Running att appens process inte existerar. Linux-systemet som Android är baserat på hanterar processer via Zygote-mekanismen. När appen startar forkear Zygote en ny process, laddar Dalvik/ART och anropar Application.onCreate(). I Android finns ingen direkt motsvarighet till applicationWillTerminate — systemet kan avsluta processen när som helst utan varning.
När Activity anropas för första gången skapar systemet processen, Application och Activity via kedjan onCreate → onStart → onResume. Om användaren trycker på Back förstörs Activity (onDestroy) och processen kan avslutas av systemet. Viktig skillnad jämfört med iOS: i Android kan processen fortsätta att existera även utan aktiva Activity — till exempel om en Foreground Service körs eller en aktiv BroadcastReceiver finns.
// Hantering av Not Running via SavedStateHandle i 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 — första återanrop efter Not Running
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
initCrashReporter()
initDependencyInjection()
}
}SavedStateHandle — en komponent i Android Architecture Components som automatiskt sparar tillståndet vid övergång till Not Running och återställer det vid kall start. ViewModel som skapats via ViewModelProvider överlever skärmrotation och förstöring av Activity. Vid processavslutning serialiseras data från SavedStateHandle till Bundle och sparas i saved instance state.
Not Running inträffar av flera anledningar. Användaren stänger appen manuellt. Systemet avlastar appen vid minnesbrist. Appen nödavslutas med ett undantag. I Android kan systemet avsluta processen vid massuppdatering av appar eller omstart av enheten. iOS kan avsluta appen vid timeout för bakgrundsuppgift (vanligtvis 30 sekunder).
| Orsak | iOS | Android | Möjlighet att förebygga |
|---|---|---|---|
| Manuell stängning av användare | Svep i App Switcher | Svep från Recents | Nej — användaråtgärd |
| Minnesbrist | Utlösning av memory warning | onTrimMemory / LMK | Delvis — minnesoptimering |
| Krascher | NSException / signal | UncaughtException / ANR | Ja — felhantering och crash-reporting |
| Timeout för bakgrundsuppgift | 30 sek för Background task | 10 min för JobScheduler | Ja — korrekt uppgiftsplanering |
| Omstart av OS | Anrop av applicationWillTerminate | Broadcast ACTION_SHUTDOWN | Nej — systemhändelse |
| Uppdatering av app | Inträffar inte (iOS Sandbox) | Process avslutas vid APK-uppdatering | Nej — systemuppdatering |
För iOS, använd konsolloggning i applicationWillTerminate och applicationDidFinishLaunching. Lägg till en flagga i UserDefaults vid varje start — om flaggan saknas vid nästa start har appen avslutats felaktigt. I Android använd ActivityManager.isBackgroundRestricted() för att kontrollera om appen kan köra bakgrundsuppgifter. Övervaka också onTrimMemory(TRIM_MEMORY_COMPLETE) — detta är en signal att processen kommer att avslutas.
Första regeln — utgå aldrig från att applicationWillTerminate eller onDestroy kommer att anropas. Spara kritiskt viktiga data vid varje övergång från Active till Background. Använd nyckel-värde-lager för enkla inställningar och SQLite/Room för strukturerad data.
Andra regeln — mät tiden för kall start och optimera den. Lat initiering, minimering av arbete i huvudtråden, förladdning av resurser, användning av SplashScreen API — allt detta förbättrar uppfattningen av starttiden. Google rekommenderar kall start under 200 ms för utmärkt UX.
Tredje regeln — implementera State Restoration. I iOS använd UIApplication.stateRestorationIdentifier och NSUserActivity. I Android använd SavedStateHandle i ViewModel i kombination med onSaveInstanceState. Detta gör det möjligt för användaren att fortsätta arbeta från samma plats efter omstart av appen.
Fjärde regeln — hantera launchOptions och Intent som appen startades med efter Not Running. Deep links, push-notiser, universella länkar — alla skickas via startparametrar. Utvecklaren måste korrekt extrahera dessa data och dirigera användaren till lämplig skärm.
// Hantering av deep link efter kall start
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Kontrollera om notis har kommit
if let notification = launchOptions?[.remoteNotification] as? [String: Any] {
handleNotification(notification)
}
// Kontrollera 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)
}Koden visar hantering av startparametrar vid kall start i iOS. launchOptions innehåller data som systemet startade appen med. Notiser, deep links och universella länkar skickas via denna ordbok. Utvecklaren måste korrekt hantera alla möjliga startscenarier för att säkerställa en sömlös användarupplevelse.
Vanliga frågor
Data som sparats i permanent lagring (UserDefaults, Core Data, SharedPreferences, Room) bevaras. Data i RAM — variabler, cache, ViewModel-tillstånd utan SavedStateHandle — går oåterkalleligen förlorat. Därför är det kritiskt viktigt att spara appens tillstånd vid varje övergång till bakgrunden.
Vid kall start anropas application(_:didFinishLaunchingWithOptions:). Vid varm start (återgång från Suspended) anropas inte denna metod — endast applicationWillEnterForeground och applicationDidBecomeActive aktiveras. Om du behöver utföra en åtgärd endast vid kall start, sätt en flagga i didFinishLaunchingWithOptions.
Ja. En Foreground Service med en permanent notis förhindrar att processen avslutas av systemet, även om alla Activity förstörts. En Background Service (startService utan foreground) kan stoppas av systemet när som helst. En körande Service innebär att processen finns och detta är inte längre Not Running.
I iOS-simulatorn avslutar du appen via App Switcher (Cmd+Shift+H två gånger, svep uppåt). I Android-emulatorn använder du adb shell am force-stop com.example.app eller Stop-knappen i Logcat. Starta sedan appen igen — detta blir en ren kall start från Not Running.
Kill-switch — ett serverkommando för nödavslutning av appen. Används i bank- och företagsappar för fjärrblockering av åtkomst. Om appen har fått ett kill-kommando blockerar den vid nästa kall start UI:t och begär omauktorisering. I iOS implementeras kill-switch via remote notifications med en blockeringsflagga.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också