Not Running — egy mobilalkalmazás életciklusának kezdeti állapota, amelyben az alkalmazás még nem indult el vagy már befejezte működését. Ismerje meg, hogyan kezeli az iOS és Android rendszer ezt az állapotot, mely események vezetnek a Not Running-ból való átmenethez, és hogyan kell helyesen kezelni az alkalmazás indítását és befejezését Swift és Kotlin nyelven.
Főbb pontok
Not Running — egy mobilalkalmazás életciklusának alapállapota, amelyben az alkalmazás nincs betöltve a készülék RAM memóriájába, és nem fogyaszt rendszererőforrásokat. iOS és Android rendszeren ez az állapot az alkalmazáshoz kapcsolódó folyamatok és szálak teljes hiányát jelenti. A felhasználó látja az alkalmazás ikonját az asztalon, de maga az alkalmazás nem aktív, és nem szerepel a legutóbbiak listáján.
Amikor a felhasználó megérinti az ikont, a rendszer új folyamatot hoz létre, betölti a végrehajtható kódot a memóriába, és inicializálja az összes szükséges adatstruktúrát. Ezt a folyamatot hideg indításnak (cold start) nevezzük, és ez a leginkább erőforrás-igényes a betöltési idő szempontjából.
A rendszer bármely más állapotból áthelyezheti az alkalmazást Not Running állapotba. Ha az alkalmazás a háttérben (Background) vagy felfüggesztve (Suspended) van, az operációs rendszer jogosult eltávolítani RAM hiányában a magasabb prioritású feladatok számára — például egy előtérben lévő aktív alkalmazás számára.
A fejlesztőnek figyelembe kell vennie, hogy az alkalmazást a rendszer bármikor befejezheti, amikor az a háttérben van. Ez azt jelenti, hogy minden nem mentett adat elveszhet. Ezért kritikus fontosságú az állapot mentése kulcs-érték tárolókba (UserDefaults, SharedPreferences) vagy helyi adatbázisba az Active-ből Background-ba való átmenetek során.
Az iOS prioritásokat használ az alkalmazás aktuális állapota alapján: az Active rendelkezik a legmagasabb prioritással, ezt követi az Inactive, Background, Suspended, és végül a Not Running — minimális prioritás. Az Android hasonló folyamathierarchiát használ: a Foreground folyamat prioritása OOM_ADJ = 0, a Visible folyamaté = 100, a Service folyamaté = 200, a Background folyamaté = 300, az Empty folyamaté = 400. Minél magasabb az érték, annál nagyobb a valószínűsége, hogy a folyamat befejeződik memóriahiány esetén.
| Platform | Állapot | Eltávolítási prioritás | Leírás |
|---|---|---|---|
| iOS | Not Running | Legmagasabb | Az alkalmazás nincs betöltve — rendszererőforrás nem fogy |
| iOS | Suspended | Magas | Alkalmazás a memóriában, de kód nem fut — első cél az eltávolításhoz |
| iOS | Background | Közepes | Alkalmazás háttérfeladatot végez — időtúllépés után eltávolítva |
| iOS | Active | Alacsony | Aktív alkalmazás — csak kritikus memóriahiány esetén távolítható el |
| Android | Empty Process | Legmagasabb | Aktív komponensek nélküli folyamat — elsőként törlődik |
| Android | Background Process | Magas | Háttérfolyamat látható Activity nélkül |
| Android | Foreground Service | Alacsony | Szolgáltatás értesítéssel — ritkán fejeződik be |
| Android | Foreground Process | Minimális | Aktív Activity — utolsóként fejeződik be |
Hideg indítás (cold start) akkor történik, amikor az alkalmazás Not Running-ból közvetlenül Active állapotba lép. A rendszer új folyamatot hoz létre, betölti az osztályokat, inicializálja a statikus mezőket, létrehozza a fő szálat és elindítja a UI keretrendszert. iOS rendszeren ez az application(_:didFinishLaunchingWithOptions:) meghívását jelenti, Android rendszeren — az Application.onCreate() és Activity.onCreate() meghívását. A hideg indítás ideje 200 ms-tól több másodpercig terjedhet az alkalmazás összetettségétől függően.
Meleg indítás (warm start vagy hot start) — az alkalmazás Suspended állapotban volt, és teljes újratöltés nélkül tér vissza a működéshez. A rendszer visszaállítja az utolsó UI vermet a memóriából, és a felhasználó onnan folytatja a munkát, ahol abbahagyta. A meleg indítás lényegesen gyorsabb, mint a hideg indítás, mivel a kód nagy része már betöltődött a memóriába. iOS rendszeren a meleg indítás nem hívja meg az application(_:didFinishLaunchingWithOptions:)-t, csak az applicationWillEnterForeground és applicationDidBecomeActive metódusokat.
A hideg és meleg indítás közötti különbség kritikus a felhasználói élmény szempontjából. Hideg indítás esetén a fejlesztőnek biztosítania kell, hogy az indítás a lehető leggyorsabban megtörténjen — lusta inicializálás, nehéz erőforrások késleltetett betöltése, a fő szálban végzett munka minimalizálása indításkor. A Google azt javasolja, hogy a hideg indítás ne haladja meg az 500 ms-ot, az Apple — a 400 ms-ot iOS esetében.
// Hideg indítási idő mérése Android rendszeren
class App : Application() {
private var startTime: Long = 0L
override fun onCreate() {
super.onCreate()
startTime = System.currentTimeMillis()
}
fun getStartupTime(): Long {
return System.currentTimeMillis() - startTime
}
}
// Activity indítása lusta inicializálással
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)
// Csak a szükséges minimum az első képkockához
setupNavigation()
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
// Nehéz inicializálás renderelés után
initializeHeavyModules()
}
}A példa a hideg indítási idő mérését mutatja Android rendszeren. Application.onCreate() a Not Running-ból Active-ba való átmenetkor hívódik meg. Az időbélyeg a folyamat indításakor kerül rögzítésre. Az Activity lusta inicializálást használ a lazy-delegáton keresztül, hogy ne blokkolja az első képkockát. Az onPostCreate az optimális hely a nehéz modulok inicializálására, mivel a UI már renderelve van.
iOS rendszeren a Not Running az UIApplicationDelegate delegált segítségével kezelhető. Kulcsfontosságú metódusok: az application(_:didFinishLaunchingWithOptions:) a hideg indítás után hívódik meg, az applicationWillTerminate(_:) az alkalmazás felhasználó általi befejezése előtt hívódik meg. A rendszer azonban befejezheti az alkalmazást az applicationWillTerminate meghívása nélkül — például vészhelyzeti befejezés vagy memória felszabadítása esetén. Az iOS nem garantálja ezen metódus meghívását, ezért az adatokat az applicationDidEnterBackground-ben kell menteni.
A felhasználó manuálisan befejezheti az alkalmazást elcsúsztatással az App Switcherben. A rendszer eltávolíthatja az alkalmazást a memóriából a háttérben. Az alkalmazás vészhelyzetben (crash) befejeződhet. Minden esetben az indításkor létrehozott összes objektum megsemmisül. A nem mentett állapot visszavonhatatlanul elveszik. iOS 13+-ban az állapot mentéséhez az NSUserActivity vagy a state restoration mechanizmus használata javasolt a UIApplication.stateRestorationIdentifier segítségével.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Hideg indítás: alkalmazás átlépett Not Running-ból
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Minimális szolgáltatáskészlet inicializálása
setupAnalytics()
configureAppearance()
return true
}
// Alkalmazás befejezi működését — csak manuális bezárás
func applicationWillTerminate(
_ application: UIApplication
) {
saveCriticalData()
}
// Adatok mentése a háttérbe lépés előtt
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
)
}
}A kód a Not Running helyes kezelését mutatja iOS rendszeren. applicationWillTerminate csak a felhasználó általi manuális befejezéskor hívódik meg. A kritikus adatok mentése duplikálva van az applicationDidEnterBackground-ben, mivel ez a metódus garantáltan meghívódik a háttérbe lépés előtt. A state restoration lehetővé teszi a UI verem mentését a későbbi helyreállításhoz hideg indításkor.
Android rendszeren a Not Running azt jelenti, hogy az alkalmazás folyamata nem létezik. A Linux rendszer, amelyen az Android alapul, a Zygote mechanizmuson keresztül kezeli a folyamatokat. Az alkalmazás indításakor a Zygote új folyamatot fork-ol, betölti a Dalvik/ART-ot és meghívja az Application.onCreate()-t. Android rendszeren nincs közvetlen analógja az applicationWillTerminate-nek — a rendszer bármikor, figyelmeztetés nélkül befejezheti a folyamatot.
Amikor az Activity első alkalommal meghívódik, a rendszer létrehozza a folyamatot, az Application-t és az Activity-t az onCreate → onStart → onResume láncon keresztül. Ha a felhasználó megnyomja a Back gombot, az Activity megsemmisül (onDestroy), és a folyamatot a rendszer befejezheti. Fő különbség az iOS-hez képest: Android rendszeren a folyamat aktív Activity nélkül is tovább létezhet — például ha egy Foreground Service fut, vagy van egy aktív BroadcastReceiver.
// Not Running kezelése SavedStateHandle segítségével ViewModel-ben
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 — első visszahívás Not Running után
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
initCrashReporter()
initDependencyInjection()
}
}SavedStateHandle — az Android Architecture Components egy komponense, amely automatikusan menti az állapotot a Not Running-ba való átmenetkor, és visszaállítja azt hideg indításkor. A ViewModelProvider-en keresztül létrehozott ViewModel túléli a képernyő elforgatását és az Activity megsemmisítését. A folyamat befejezésekor a SavedStateHandle adatai Bundle-be szerializálódnak és a saved instance state-ben tárolódnak.
Not Running több okból következik be. A felhasználó manuálisan bezárja az alkalmazást. A rendszer eltávolítja az alkalmazást memóriahiány esetén. Az alkalmazás vészhelyzetben kivétellel fejeződik be. Android rendszeren a rendszer befejezheti a folyamatot az alkalmazások tömeges frissítésekor vagy a készülék újraindításakor. Az iOS befejezheti az alkalmazást a háttérfeladat időtúllépésekor (általában 30 másodperc).
| Ok | iOS | Android | Megelőzés lehetősége |
|---|---|---|---|
| Felhasználó általi manuális bezárás | Csúsztatás az App Switcherben | Csúsztatás a Recents-ből | Nem — felhasználói művelet |
| Memóriahiány | Memory warning aktiválása | onTrimMemory / LMK | Részben — memória optimalizálása |
| Alkalmazás crash | NSException / jel | UncaughtException / ANR | Igen — hibakezelés és crash-reporting |
| Háttérfeladat időtúllépése | 30 mp Background task esetén | 10 perc JobScheduler esetén | Igen — megfelelő feladatütemezés |
| OS újraindítása | applicationWillTerminate meghívása | Broadcast ACTION_SHUTDOWN | Nem — rendszeresemény |
| Alkalmazás frissítése | Nem történik (iOS Sandbox) | Folyamat befejeződik APK-frissítéskor | Nem — rendszerfrissítés |
iOS rendszeren használjon konzolnaplózást az applicationWillTerminate és applicationDidFinishLaunching metódusokban. Adjon hozzá egy jelzőt a UserDefaults-hoz minden indításkor — ha a következő indításkor a jelző hiányzik, az alkalmazás helytelenül fejeződött be. Android rendszeren használja az ActivityManager.isBackgroundRestricted() metódust annak ellenőrzésére, hogy az alkalmazás indíthat-e háttérfeladatokat. Figyelje továbbá az onTrimMemory(TRIM_MEMORY_COMPLETE) eseményt — ez azt jelzi, hogy a folyamat be fog fejeződni.
Első szabály — soha ne feltételezze, hogy az applicationWillTerminate vagy az onDestroy meghívódik. Mentse a kritikus fontosságú adatokat minden Active-ből Background-ba való átmenetkor. Használjon kulcs-érték tárolókat egyszerű beállításokhoz és SQLite/Room-ot strukturált adatokhoz.
Második szabály — mérje meg a hideg indítás idejét és optimalizálja azt. Lusta inicializálás, a fő szálban végzett munka minimalizálása, erőforrások előzetes betöltése, SplashScreen API használata — mindez javítja az indítási idő érzékelését. A Google azt javasolja, hogy a hideg indítás 200 ms alatt legyen a kiváló UX érdekében.
Harmadik szabály — valósítsa meg az állapot-helyreállítást (State Restoration). iOS rendszeren használja a UIApplication.stateRestorationIdentifier és NSUserActivity elemeket. Android rendszeren használja a SavedStateHandle-t a ViewModel-ben az onSaveInstanceState-val kombinálva. Ez lehetővé teszi a felhasználó számára, hogy az alkalmazás újraindítása után onnan folytassa a munkát, ahol abbahagyta.
Negyedik szabály — kezelje a launchOptions és Intent elemeket, amelyekkel az alkalmazás a Not Running után elindult. Deep link-ek, push értesítések, univerzális linkek — mindegyik az indítási paramétereken keresztül kerül továbbításra. A fejlesztőnek helyesen kell kinyernie ezeket az adatokat, és a felhasználót a megfelelő képernyőre kell irányítania.
// Deep link kezelése hideg indítás után
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Annak ellenőrzése, hogy érkezett-e értesítés
if let notification = launchOptions?[.remoteNotification] as? [String: Any] {
handleNotification(notification)
}
// Deep link ellenőrzése
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)
}A kód az indítási paraméterek kezelését mutatja hideg indításkor iOS rendszeren. launchOptions tartalmazza azokat az adatokat, amelyekkel a rendszer elindította az alkalmazást. Az értesítések, deep link-ek és univerzális linkek ezen a szótáron keresztül kerülnek továbbításra. A fejlesztőnek minden lehetséges indítási forgatókönyvet helyesen kell kezelnie a zökkenőmentes felhasználói élmény biztosítása érdekében.
Gyakran Ismételt Kérdések
A tartós tárhelyen mentett adatok (UserDefaults, Core Data, SharedPreferences, Room) megmaradnak. A RAM-ban lévő adatok — változók, gyorsítótár, ViewModel állapot SavedStateHandle nélkül — visszavonhatatlanul elvesznek. Ezért kritikus fontosságú az alkalmazás állapotának mentése minden háttérbe lépéskor.
Hideg indításkor az application(_:didFinishLaunchingWithOptions:) metódus hívódik meg. Meleg indításkor (visszatérés Suspended-ből) ez a metódus nem hívódik meg — csak az applicationWillEnterForeground és applicationDidBecomeActive aktiválódik. Ha csak hideg indításkor szeretne végrehajtani egy műveletet, állítson be egy jelzőt a didFinishLaunchingWithOptions-ban.
Igen. A Foreground Service állandó értesítéssel megakadályozza a folyamat rendszer általi befejezését, még akkor is, ha az összes Activity megsemmisült. A Background Service (startService foreground nélkül) a rendszer által bármikor leállítható. Egy futó Service azt jelenti, hogy a folyamat létezik, és ez már nem Not Running.
Az iOS szimulátoron fejezze be az alkalmazást az App Switcher segítségével (Cmd+Shift+H kétszer, csúsztasson felfelé). Az Android emulátoron használja az adb shell am force-stop com.example.app parancsot vagy a Stop gombot a Logcat-ben. Ezután indítsa el újra az alkalmazást — ez egy tiszta hideg indítás lesz Not Running-ból.
Kill-switch — egy szerverparancs az alkalmazás vészhelyzeti befejezésére. Banki és vállalati alkalmazásokban használják a távoli hozzáférés blokkolására. Ha az alkalmazás kill parancsot kapott, a következő hideg indításkor blokkolja a UI-t és újraautorizációt kér. iOS rendszeren a kill-switch távoli értesítéseken (remote notifications) keresztül valósul meg blokkoló jelzővel.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is