Suspended — suspendidong estado ng lifecycle ng iOS app, kung saan ito ay naka-freeze sa memorya ngunit hindi nag-execute ng code. Ipinapakita namin kung paano gumagana ang Suspended, anong mga panganib ang dulot ng pag-freeze ng app sa background, paano pinamamahalaan ng iOS ang pagbabawas ng mga Suspended app, at paano i-implement ang state restoration para sa seamless na pag-recover pagkatapos bumalik mula sa Suspended.
Mga Pangunahing Punto
Suspended — estado ng lifecycle ng iOS app kung saan ito ay nasa operational memorya ng device ngunit hindi nag-e-execute ng anumang code. Ito ang huling estado bago ang kumpletong pagtatapos: ang app ay lumilipat sa Suspended mula sa Background pagkatapos makumpleto ang lahat ng background task o pagkatapos ng timeout. Sa Suspended, ang app ay ganap na naka-freeze — lahat ng thread ay suspendido, hindi gumagana ang mga timer, walang aktibidad sa network.
Suspended — natatanging feature ng iOS na wala sa standard lifecycle ng Android. Ang dahilan ay ang magkaibang arkitektura ng pamamahala ng proseso. Pinapanatili ng iOS ang imahe ng app sa memorya (analog ng hibernation sa desktop) upang kapag bumalik ang user, agad na ma-recover ang interface nang walang cold start. Ang Android ay walang Suspended — ang proseso ay maaaring umiiral at mag-execute ng code (Background), o natapos na (Not Running), bagama't maaaring ihinto ng Android ang pag-execute ng mga thread sa pamamagitan ng LMK.
Para sa user, ang Suspended ay mukhang instant na pag-recover: lumilipat siya sa pagitan ng mga app sa pamamagitan ng App Switcher, at bawat app ay bubukas sa parehong lugar kung saan niya ito iniwan. Lumilikha ito ng ilusyon na lahat ng app ay tumatakbo nang sabay-sabay. Sa katotohanan, karamihan sa kanila ay naka-freeze sa Suspended. Hot start mula sa Suspended ay mas mabilis kaysa cold start mula sa Not Running, dahil ang code ay nasa memorya na.
Sinusubaybayan ng iOS ang estado ng lahat ng app at gumagawa ng desisyon tungkol sa pagbabawas ng mga Suspended app batay sa available na memorya. Kapag kulang ang memorya, sinisimulan ng system na ibaba ang mga Suspended app, simula sa mga pinakamatagal na nasa estadong ito. Kung hindi pa rin sapat ang memorya, inililipat ng system ang mga app mula sa Background at Inactive patungo sa Suspended, pagkatapos ay ibinababa ang mga ito. Ang prosesong ito ay ganap na transparent para sa user — nakikita lamang niya ang icon ng app sa App Switcher, na kapag na-click ay magsisimula ng cold start.
| Katangian | Suspended (iOS) | Background (iOS) | Background (Android) |
|---|---|---|---|
| Nag-e-execute ng code | Hindi | Oo (limitado) | Oo (limitado) |
| Sa memorya | Oo | Oo | Oo |
| Pagkonsumo ng CPU | 0% | Mababa | Mababa |
| Hot start | Oo — instant na pag-recover | Oo — sa pamamagitan ng Inactive | Hindi — maaaring napatay ang proseso |
| Timeout | Hindi — maaaring nasa memorya nang ilang oras | ~30 segundo (pagkatapos ng beginBackgroundTask) | Depende sa bersyon ng API |
| Pagbabawas ng system | Kapag kulang ang memorya | Kapag kritikal na kulang ang memorya | LMK (Low Memory Killer) |
| Pagbabalik sa trabaho | Mula sa App Switcher — agad | Mula sa App Switcher — sa pamamagitan ng Inactive | Cold start |
| State Restoration | Inirerekomenda | Hindi kinakailangan | SavedStateHandle |
Sa iOS, Suspended ay awtomatikong naaabot pagkatapos makumpleto ang lahat ng background task. Tinatawag ng system ang applicationDidEnterBackground, nagbibigay ng oras para i-execute ang beginBackgroundTask (mga 30 segundo), pagkatapos ay puwersahang i-suspend ang lahat ng thread at ilipat ang app sa Suspended na estado. Ang mga object sa memorya ay napanatili, ngunit walang code na na-e-execute — ang app ay naka-freeze sa kasalukuyang estado.
Kritikal na mahalagang sandali: applicationDidEnterBackground — huling paraan na garantisadong tatawagin bago ang Suspended. Pagkatapos nito, hindi nakakatanggap ang app ng anumang notification tungkol sa pagbabawas mula sa memorya. Kung papatayin ng user o system ang app na nasa Suspended, hindi tatawagin ang applicationWillTerminate o applicationDidEnterBackground muli. Kaya naman ang lahat ng pag-save ng data ay dapat mangyari sa applicationDidEnterBackground, hindi sa applicationWillTerminate.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Huling garantisadong tawag bago ang Suspended
func applicationDidEnterBackground(_ application: UIApplication) {
// Sine-save ang lahat ng dapat makaligtas sa pagbabawas mula sa memorya
savePersistentState()
saveNavigationStack()
// Humihiling ng karagdagang oras kung kinakailangan
let task = application.beginBackgroundTask {
application.endBackgroundTask(task)
}
}
// Pagbabalik mula sa Suspended — hot start
func applicationWillEnterForeground(_ application: UIApplication) {
// App ay nasa Suspended, bumabalik sa trabaho
print("Pagbabalik mula sa Suspended o Background")
}
// Buong pag-recover pagkatapos ng pagbabawas mula sa memorya
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Kung ito ay cold start pagkatapos ng pagbabawas mula sa Suspended —
// ini-recover ang state restoration
return true
}
private func savePersistentState() {
UserDefaults.standard.set(Date(), forKey: "lastActiveDate")
}
private func saveNavigationStack() {
guard let rootVC = window?.rootViewController else { return }
// Sine-save ang kasalukuyang navigation stack
if let navController = rootVC as? UINavigationController {
let vcClasses = navController.viewControllers.map { type(of: $0) }
UserDefaults.standard.set(vcClasses.map { NSStringFromClass($0) }, forKey: "navStack")
}
}
}Ipinapakita ng code ang kritikal na paghawak ng Suspended sa iOS. applicationDidEnterBackground — huling garantisadong tawag. Lahat ng pag-save ng data ay dapat mangyari dito: estado ng user, navigation stack, draft, timer. Tinatawag ang applicationWillEnterForeground kapag bumalik mula sa Suspended o Background. didFinishLaunchingWithOptions — lamang sa cold start, kapag ang app ay ibinaba mula sa memorya pagkatapos ng Suspended.
Sa Android walang direktang analog ng iOS Suspended. Hindi nina-freeze ng Android ang mga app sa memorya na may pagpapanatili ng konteksto ng pag-execute. Sa halip, pinapanatili ng Android ang proseso sa background (Background) o tinatapos ito (Not Running). Gayunpaman, sa Android 11+ (API 30) lumitaw ang mekanismong App Freezer, na nagsu-suspend ng pag-execute ng mga background process gamit ang SIGSTOP signal. Ito ay isang functional analog ng Suspended, ngunit may mahahalagang pagkakaiba.
App Freezer — bahagi ng sistema ng pamamahala ng memorya ng Android. Kapag ang app ay matagal na nasa background at walang aktibong notification, nagpapadala ang system ng SIGSTOP dito, na nagsu-suspend sa lahat ng thread. Kapag bumalik ang app sa foreground, ipinapadala ang SIGCONT at magpapatuloy ang pag-execute. Pangunahing pagkakaiba sa iOS: Hindi ginagarantiya ng App Freezer ang pagpapanatili ng estado — maaaring mawala ang data sa memorya kung ang proseso ay napatay habang naka-freeze.
Sa Android inirerekomenda ang paggamit ng SavedStateHandle sa ViewModel para sa awtomatikong pag-save ng estado sa anumang pagtatapos ng proseso. Nagsa-save ang SavedStateHandle ng data sa Bundle sa pamamagitan ng onSaveInstanceState, na nakakaligtas sa parehong App Freezer at Process Death. Hindi tulad ng iOS, kung saan ang pagbabawas mula sa Suspended ay isang pambihirang sitwasyon, sa Android ang Process Death ay normal na pag-uugali na dapat palaging asahan.
// SavedStateHandle — kaligtasan mula sa Process Death sa Android
class CheckoutViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// Estado na makakaligtas sa proseso kahit pagkatapos ng App Freezer
var currentStep: MutableLiveData<Int> =
savedStateHandle.getLiveData("checkout_step", 1)
var cartItems: MutableLiveData<List<CartItem>> =
savedStateHandle.getLiveData("cart_items", emptyList())
fun proceedToNextStep() {
currentStep.value = (currentStep.value ?: 0) + 1
}
fun addToCart(item: CartItem) {
val updatedList = (cartItems.value ?: emptyList()) + item
cartItems.value = updatedList
savedStateHandle["cart_items"] = updatedList
}
}
// Pag-save sa onStop kung sakaling magkaroon ng App Freezer
class MainActivity : AppCompatActivity() {
override fun onStop() {
super.onStop()
// Sine-save ang data na dapat makaligtas sa pag-freeze
saveDraftData()
// Nagpapalabas ng mga resources na hindi kailangan sa naka-freeze na estado
releaseHeavyResources()
// Nagbabala na ang app ay i-freeze
// (Pag-log para sa debugging)
Log.d("Lifecycle", "Activity ay tumigil — posibleng App Freeze")
}
}Ipinapakita ng code ang diskarte sa paghawak ng analog ng Suspended sa Android. SavedStateHandle sa ViewModel ay awtomatikong nagse-save at nagre-recover ng data sa Process Death. onStop — huling garantisadong kaganapan bago ang posibleng App Freezer o pagtatapos ng proseso. Estado ng order form, listahan ng mga produkto sa cart — lahat ng data na ito ay nakakaligtas sa pag-freeze salamat sa SavedStateHandle. Para sa mabibigat na resources (bitmap, database cursor) ang onStop ay lugar para maglabas ng memorya.
State Restoration — ang built-in na mekanismo ng iOS para sa pag-save at pag-recover ng UI state pagkatapos ibaba ang app mula sa memorya. Kung ang app ay nasa Suspended at ibinaba ito ng system, sa susunod na cold start, ire-recover ng state restoration ang navigation stack, scroll position, estado ng forms, at iba pang UI elements. Babalik ang user sa parehong screen kung saan siya tumigil.
Gumagana ang State Restoration sa pamamagitan ng mga protokol na UIViewControllerRestoration at UIStateRestoring. Nagtatalaga ang developer ng restorationIdentifier sa bawat ViewController at View na gusto niyang i-recover. Kapag pumunta sa Background, ine-encode ng iOS ang estado ng mga object na ito. Pagkatapos bumalik mula sa pagbabawas, lumilikha ang iOS ng mga bagong object at didecode ang naka-save na estado. Kung walang state restoration, makakakita ang user ng blangkong screen pagkatapos ng cold start sa halip na lugar kung saan siya tumigil.
import UIKit
class DetailViewController: UIViewController {
var itemID: String = ""
var scrollPosition: CGPoint = .zero
override func viewDidLoad() {
super.viewDidLoad()
restorationIdentifier = "DetailViewController"
restorationClass = type(of: self)
}
override func encodeRestorableState(with coder: NSCoder) {
super.encodeRestorableState(with: coder)
coder.encode(itemID, forKey: "itemID")
coder.encode(scrollPosition, forKey: "scrollPosition")
}
override func decodeRestorableState(with coder: NSCoder) {
super.decodeRestorableState(with: coder)
if let savedID = coder.decodeObject(forKey: "itemID") as? String {
itemID = savedID
loadItem()
}
if let savedPosition = coder.decodeCGPoint(forKey: "scrollPosition") {
scrollPosition = savedPosition
// Ire-recover ang posisyon pagkatapos mag-load ng data
}
}
}
// AppDelegate — pag-activate ng State Restoration
func application(
_ application: UIApplication,
shouldSaveSecureApplicationState coder: NSCoder
) -> Bool {
return true
}
func application(
_ application: UIApplication,
shouldRestoreSecureApplicationState coder: NSCoder
) -> Bool {
return true
}Ipinapakita ng code ang implementasyon ng State Restoration sa iOS. restorationIdentifier at restorationClass ay kinakailangan para sa bawat ViewController na ire-recover. encodeRestorableState/decodeRestorableState ay nagse-save at naglo-load ng data sa pamamagitan ng NSCoder. Sa AppDelegate, binubuksan ng shouldSaveSecureApplicationState at shouldRestoreSecureApplicationState ang naka-encrypt na pag-save ng estado. Mula noong iOS 12+, inirerekomenda ang paggamit ng secure encoding (NSSecureCoding) para sa proteksyon ng data.
Unang tuntunin — huwag kailanman ipalagay na babalik ang app mula sa Suspended. Maaaring ibaba ng system ang app anumang oras. Lahat ng kritikal na mahalagang data ay dapat i-save sa permanenteng storage bago lumipat sa Suspended — iyon ay sa applicationDidEnterBackground o onStop. UserDefaults, Core Data, File Manager — angkop na storage. Ang memorya (variables, properties) — hindi mapagkakatiwalaang storage para sa data na dapat makaligtas sa Suspended.
Ikalawang tuntunin — maglabas ng resources bago ang Suspended. Isara ang file descriptors, maglabas ng GPU memory (Metal, Core Graphics), isara ang network connections. Kahit na hindi gumagamit ng CPU ang app sa Suspended, ang mga nakabaong resources ay naka-block para sa ibang apps. Sa iOS sa Suspended, hindi dapat panatilihin ang mga bukas na socket — kapag bumalik mula sa Suspended, maaaring hindi gumana ang mga ito, na magdudulot ng mga error.
Ikatlong tuntunin — huwag maglagay ng lohika na nakadepende sa oras sa paghihintay ng pagbabalik mula sa Suspended. Ang mga timer, callback at network activity ay humihinto sa Suspended. Kung ang app ay nasa Suspended nang ilang oras, sa pagbabalik ang timer ay maaaring gumana nang hindi tama. Suriin ang pagiging bago ng data sa pagbabalik — maaaring lipas na ang cache at nag-expire na ang token ng awtorisasyon.
Ikaapat na tuntunin — gamitin ang State Restoration para sa lahat ng screen, lalo na para sa input forms, scrollable lists at detail screens. Kung walang state restoration, pagkatapos bumalik mula sa ibinabang Suspended, makikita ng user ang paunang screen ng app sa halip na lugar kung saan siya tumigil. Pinapalala nito ang karanasan ng user at pinipilit ang user na ulitin ang mga aksyon.
import UIKit
// Pagsusuri: ang app ba ay ibinaba mula sa memorya?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Sinusuri kung may naka-save na estado
if UserDefaults.standard.object(forKey: "navStack") != nil {
// Ang app ay ibinaba mula sa Suspended
// Kailangang i-recover ang estado
restoreNavigationStack()
} else {
// Malinis na cold start mula sa Not Running
showOnboardingIfNeeded()
}
return true
}
private func restoreNavigationStack() {
guard let savedStack = UserDefaults.standard.array(forKey: "navStack") as? [String],
let navController = window?.rootViewController as? UINavigationController
else { return }
for vcClassName in savedStack {
if let vcClass = NSClassFromString(vcClassName) as? UIViewController.Type {
let vc = vcClass.init()
navController.pushViewController(vc, animated: false)
}
}
}Ipinapakita ng code ang kasanayan sa pagtukoy kung ang app ay ibinaba mula sa Suspended. Pagsusuri ng UserDefaults para sa pagkakaroon ng naka-save na navigation stack ay nagbibigay-daan upang makilala ang cold start pagkatapos ng pagbabawas mula sa malinis na cold start. Sa unang kaso, ang navigation stack ay nire-recover, sa pangalawa — ang onboarding o pangunahing screen ay ipinapakita. Ang pamamaraang ito ay umaakma sa built-in na State Restoration para sa mga kaso kung saan hindi sapat ang NSCoder.
Mga Madalas Itanong
Walang limitasyon — mula ilang segundo hanggang ilang araw. Walang timeout ang iOS para sa Suspended. Mananatili ang app sa memorya hanggang magpasya ang system na ibaba ito dahil sa kakulangan ng resources. Sa praktika nananatili ang mga app sa Suspended mula 15 minuto hanggang ilang oras, depende sa dami ng RAM ng device at bilang ng mga aktibong app.
Hindi. Ang applicationWillTerminate ay hindi tinatawag kapag ang app ay ibinaba mula sa Suspended. Ang system ay naglalabas lamang ng memorya nang hindi inaabisuhan ang app. Ito ay isa pang dahilan kung bakit ang lahat ng pag-save ng data ay dapat mangyari sa applicationDidEnterBackground. Ang applicationWillTerminate ay tinatawag lamang kapag ang user ay manu-manong tinatapos ang app sa pamamagitan ng pag-swipe mula sa App Switcher.
Walang direktang analog. Sa Android 11+ lumitaw ang App Freezer, na nagsu-suspend ng mga background process sa pamamagitan ng SIGSTOP — ito ay functionally na katulad ng Suspended. Gayunpaman, ang Android apps ay dapat idisenyo na isinasaalang-alang ang Process Death anumang oras. Gamitin ang SavedStateHandle sa ViewModel at onSaveInstanceState para sa pag-save ng estado na makakaligtas sa parehong App Freezer at Process Death.
Sa iOS, walang direktang API para sa pagsusuri. Hindi direktang pamamaraan: suriin ang UserDefaults para sa pagkakaroon ng naka-save na estado sa didFinishLaunchingWithOptions. Kung may estado — ang app ay ibinaba mula sa Suspended at magsisimula ng cold start. Kung walang estado — malinis na cold start. Sa SwiftUI, maaari kang mag-save ng flag sa scenePhase.background at suriin ito sa susunod na pagsisimula.
Kapag lumilipat sa Suspended, kumukuha ang iOS ng snapshot — screenshot ng kasalukuyang UI ng app. Ang screenshot na ito ay ipinapakita sa App Switcher at kapag bumalik sa app (bilang animation ng pagtunaw). Kung ang app ay naglalaman ng kumpidensyal na data, maaaring ilantad ito ng snapshot. Para sa proteksyon, gamitin ang UIApplication.shouldSnapshotSecureApp (iOS 16+) o maglagay ng blur-overlay sa applicationDidEnterBackground.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din