نکات اصلی
App Lifecycle — یک ماشین حالت محدود است که تمام حالتهای ممکن یک برنامه موبایل و انتقال بین آنها را توصیف میکند. هر حالت مشخص میکند که آیا برنامه میتواند کد اجرا کند، UI نمایش دهد و منابع مصرف کند. iOS و Android مدل مشابه اما نه یکسانی دارند — تفاوتها ناشی از معماری سیستمعامل است: iOS از کنترل سخت حافظه (حالت suspended) استفاده میکند، Android — مدیریت فرآیند انعطافپذیر از طریق onSaveInstanceState.
در iOS lifecycle به foreground/background وابسته است: برنامه یا فعال است یا متوقف شده. در Android lifecycle دانهبندی بیشتری دارد — Activity/Window از 6+ حالت عبور میکند و خود فرآیند یک lifecycle اضافی از طریق ProcessLifecycleOwner دارد. برنامههای مدرن (از 2024) به طور فزایندهای از الگوهای معماری مبتنی بر lifecycle استفاده میکنند: SwiftUI Lifecycle (iOS 16+) از طریق .scenePhase environment، Compose Lifecycle از طریق LifecycleEventObserver. این الگوها به طور خودکار تغییر زمینه را مدیریت کرده و از نشت حافظه جلوگیری میکنند. طبق Google، پردازش صحیح lifecycle در Android مصرف حافظه را در هنگام کار پسزمینه 30–40٪ کاهش میدهد.
در iOS lifecycle برنامه از طریق کلاس UIApplicationDelegate (AppDelegate) مدیریت میشود. روشهای اصلی: application(_:didFinishLaunchingWithOptions:) — مقداردهی اولیه در اولین راهاندازی؛ applicationDidBecomeActive — برنامه قابل مشاهده و آماده تعامل است؛ applicationWillResignActive — انتقال به حالت غیرفعال (تماس ورودی، بستن پرده)؛ applicationDidEnterBackground — برنامه پنهان است، ~5 ثانیه برای ذخیره دادهها وجود دارد؛ applicationWillEnterForeground — بازگشت از پسزمینه؛ applicationWillTerminate — پایان (فقط برای برنامههای قدیمی بدون suspended فراخوانی میشود).
از iOS 13، Apple SceneDelegate (UISceneDelegate) را برای پشتیبانی از برنامههای چندپنجرهای در iPad و macOS Catalyst معرفی کرد. SceneDelegate lifecycle هر صحنه (پنجره) جداگانه را مدیریت میکند: scene(_:willConnectTo:options:) — ایجاد صحنه؛ sceneDidBecomeActive — صحنه فعال است؛ sceneWillResignActive — صحنه فوکوس را از دست میدهد؛ sceneDidEnterBackground — صحنه پنهان است. AppDelegate مسئول رویدادهای جهانی (بارگذاری داده، اعلانهای پوش) است و SceneDelegate — برای وضعیت UI هر پنجره. در SwiftUI lifecycle از طریق مقدار محیطی @Environment(\.scenePhase) مدیریت میشود: .active، .inactive، .background — این یک API یکپارچه برای برنامههای SwiftUI و UIKit فراهم میکند.
در Android lifecycle با کلاس Application شروع میشود — سینگلتونی که قبل از هر Activity ایجاد میشود. متد Application.onCreate() — اولین نقطه ورود، برای مقداردهی اولیه جهانی استفاده میشود (Analytics، DI، Crash Reporting). پس از آن Activity با دنباله زیر راهاندازی میشود: onCreate() → onStart() → onResume(). هنگام کوچکسازی: onPause() → onStop() → onSaveInstanceState(). هنگام نابودی: onDestroy(). هنگام بازگشت: onRestart() → onStart() → onResume().
ProcessLifecycleOwner (از AndroidX Lifecycle 2.2+) lifecycle کل فرآیند را ردیابی میکند، نه یک Activity جداگانه. دو حالت ارائه میدهد: ON_RESUME (برنامه در foreground) و ON_STOP (برنامه پنهان). ProcessLifecycleOwner مشکل «چه زمانی برنامه به پسزمینه رفت» را در سطح فرآیند حل میکند — این برای SDKها، کتابخانهها و برنامههای ماژولار حیاتی است. در Jetpack Compose lifecycle از طریق LifecycleEventObserver و collectAsStateWithLifecycle مدیریت میشود که به طور خودکار جمعآوری داده را در حالت پسزمینه متوقف میکند. Android 14 (API 34) اعلان foreground service lifecycle را از طریق Service.onTimeout اضافه کرد — سرویس باید در 6 ساعت تمام شود، در غیر این صورت سیستم آن را اجباری متوقف میکند.
| iOS | Android | توضیح |
|---|---|---|
| Not Running | — | برنامه راهاندازی نشده |
| didFinishLaunching | Application.onCreate | مقداردهی اولیه در راهاندازی |
| Active | onResume | برنامه قابل مشاهده و دریافت ورودی |
| Inactive | onPause | از دست دادن موقت فوکوس (تماس، پرده) |
| Background | onStop | برنامه پنهان، کد میتواند اجرا شود |
| Suspended | — | کد اجرا نمیشود، حافظه رزرو شده |
| Will Terminate | onDestroy | برنامه در حال پایان است |
تفاوت اصلی: iOS برنامه را 5-10 ثانیه پس از رفتن به پسزمینه به زور به Suspended منتقل میکند (کد اجرا نمیشود). Android کار پسزمینه (سرویسها، WorkManager) را برای مدت طولانیتری مجاز میداند، اما با محدودیتهای Doze Mode (Android 6+) و محدودیتهای پسزمینه (Android 12+). ProcessLifecycleOwner در Android — معادل UIApplicationDidEnterBackgroundNotification در iOS با این تفاوت که در هر انتقال به پسزمینه فعال میشود، نه فقط پس از از دست دادن فوکوس.
پیادهسازی پایه AppDelegate با مدیریت تمام حالتهای چرخه حیات. ذخیره دادهها هنگام انتقال به پسزمینه و بهروزرسانی UI هنگام بازگشت.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Analytics.shared.initialize()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
NotificationCenter.default.post(name: .appDidBecomeActive, object: nil)
}
func applicationWillResignActive(_ application: UIApplication) {
NotificationCenter.default.post(name: .appWillResignActive, object: nil)
}
func applicationDidEnterBackground(_ application: UIApplication) {
CoreDataManager.shared.saveContext()
UserDefaults.standard.synchronize()
}
func applicationWillEnterForeground(_ application: UIApplication) {
NetworkManager.shared.refreshSession()
}
}
AppDelegate — نقطه مرکزی lifecycle. applicationDidEnterBackground — متد حیاتی: iOS ~5 ثانیه برای ذخیره دادهها فرصت میدهد. applicationDidBecomeActive — UI را بهروز کنید، انیمیشنها را دوباره راهاندازی کنید. برای SceneDelegate (iOS 13+) منطق lifecycle بین صحنهها تقسیم میشود: sceneDidBecomeActive / sceneDidEnterBackground پنجرههای جداگانه را مدیریت میکنند.
SceneDelegate برای برنامههای چندپنجرهای iPad. هر صحنه lifecycle مستقل خود را دارد.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
func sceneDidBecomeActive(_ scene: UIScene) {
PlayerManager.shared.resume()
}
func sceneDidEnterBackground(_ scene: UIScene) {
PlayerManager.shared.pause()
CoreDataManager.shared.saveContext()
}
func sceneDidDisconnect(_ scene: UIScene) {
PlayerManager.shared.cleanup()
}
}
SceneDelegate lifecycle یک صحنه جداگانه را مدیریت میکند. sceneDidBecomeActive / sceneDidEnterBackground — معادل متدهای AppDelegate برای یک پنجره خاص. sceneDidDisconnect هنگام بستن صحنه فراخوانی میشود (کاربر پنجره را در iPad بست). برای حفظ سازگاری با iOS 12 و پایینتر، AppDelegate باید منطق SceneDelegate را تکرار کند. در iOS 17+ میتوانید از @Observable برای توقف/ازسرگیری خودکار وظایف بر اساس scenePhase استفاده کنید.
ProcessLifecycleOwner زمانی که برنامه در foreground/background است را در سطح فرآیند ردیابی میکند. این روش بهینه برای مدیریت سراسری lifecycle است.
import android.app.Application
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
}
}
class AppLifecycleObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onEnterForeground() {
Analytics.shared.onForeground()
NetworkMonitor.shared.start()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onEnterBackground() {
Analytics.shared.onBackground()
NetworkMonitor.shared.stop()
}
}
ProcessLifecycleOwner — تنها روش صحیح برای ردیابی انتقال به پسزمینه در سطح برنامه. ON_START زمانی فعال میشود که برنامه قابل مشاهده میشود (foreground)، ON_STOP — زمانی که کاملاً پنهان است (background). برخلاف Activity lifecycle، ProcessLifecycleOwner به صفحه خاصی وابسته نیست. برای Jetpack Compose به جای مشاهده دستی از LifecycleResumeEffect یا collectAsStateWithLifecycle استفاده کنید.
ViewModel + Lifecycle — معماری صحیح Android برای کار با lifecycle. ViewModel به طور خودکار در onDestroy پاک میشود و از نشت جلوگیری میکند.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
class TimerViewModel : ViewModel() {
private val _time = MutableLiveData<Long>()
val time: LiveData<Long> = _time
private var startTime = System.currentTimeMillis()
init {
updateTime()
}
private fun updateTime() {
_time.value = System.currentTimeMillis() - startTime
}
override fun onCleared() {
super.onCleared()
Logger.d("ViewModel cleared — آزادسازی منابع")
}
}
// در Activity
class TimerActivity : AppCompatActivity() {
private val viewModel: TimerViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Logger.d("Activity created")
}
override fun onResume() {
super.onResume()
viewModel.time.observe(this) { Logger.d("Time: $it") }
}
override fun onPause() {
super.onPause()
Logger.d("Activity paused — توقف انیمیشنها")
}
override fun onDestroy() {
super.onDestroy()
Logger.d("Activity destroyed — پاکسازی")
}
}
ViewModel از چرخش صفحه جان سالم به در میبرد و فقط در finish() Activity نابود میشود. onCleared() — مکان آزادسازی منابع، لغو اشتراک از جریانها. LiveData به طور خودکار مشاهده را در onPause متوقف و در onResume ازسر میگیرد — این محافظت در برابر نشت و کرش در حین کار پسزمینه را فراهم میکند. در Compose از collectAsStateWithLifecycle() برای همین هدف استفاده کنید.
سوالات متداول
هنگام کوچکسازی، برنامه از active به inactive (کوتاه مدت)، سپس به background میرود. پس از چند ثانیه سیستم ممکن است آن را به suspended منتقل کند — کد اجرا نمیشود، حافظه رزرو شده است. در صورت کمبود حافظه، برنامه suspended خاتمه مییابد (willTerminate فراخوانی نمیشود). دادهها را در applicationDidEnterBackground ذخیره کنید — این آخرین نقطه تضمین شده برای ذخیره است.
حداقل اجباری: applicationDidEnterBackground — ذخیره دادههای کاربر؛ applicationWillEnterForeground — بهروزرسانی UI؛ در Android onPause — توقف انیمیشنها/حسگرها. ProcessLifecycleOwner پردازش را ساده میکند: onResume — onPause برای foreground، onStart — onStop برای دید. سایر حالتها را در صورت نیاز پردازش کنید — همه حالتها برای هر برنامهای حیاتی نیستند.
AppDelegate — نماینده جهانی کل برنامه (راهاندازی، انتقال به پسزمینه). SceneDelegate (iOS 13+) lifecycle یک پنجره جداگانه (صحنه) را مدیریت میکند — در برنامههای چندپنجرهای iPad هر صحنه lifecycle خود را دارد. برای iOS 12 و پایینتر، کل lifecycle از طریق AppDelegate پردازش میشود. از iPadOS 16+ SceneDelegate برای Stage Manager اجباری است.
ProcessLifecycleOwner — کامپوننتی از AndroidX Lifecycle که lifecycle کل برنامه (فرآیند) را ردیابی میکند، نه یک Activity جداگانه. دو رویداد اصلی ارائه میدهد: ON_RESUME (برنامه در foreground) و ON_STOP (برنامه در background). برای مقداردهی اولیه/پاکسازی SDKها، تحلیلها، مانیتورهای شبکه استفاده میشود — هر چیزی که باید به انتقال برنامه به پسزمینه واکنش نشان دهد، صرفنظر از صفحه فعلی.
در Jetpack Compose از LifecycleEventObserver از طریق LocalLifecycleOwner.current.lifecycle یا تابع collectAsStateWithLifecycle() استفاده کنید. برای صفحات Compose از LifecycleResumeEffect استفاده کنید — معادل DisposableEffect که در onResume اجرا و در onPause پاک میشود. lifecycleScope.launchWhenResumed — کوروتینی که به طور خودکار در پسزمینه متوقف میشود.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.