Not Running — چیست، حالت اولیه چرخه حیات

نویسنده: IT Sectr منتشر شده: 2026-03-03 زمان مطالعه: 11 دقیقه

Not Running — حالت اولیه چرخه حیات یک برنامه موبایل است که در آن برنامه هنوز راه‌اندازی نشده یا کار خود را به پایان رسانده است. بیاموزید که چگونه سیستم iOS و Android این حالت را مدیریت می‌کنند، چه رویدادهایی منجر به انتقال از Not Running می‌شوند و چگونه راه‌اندازی و پایان برنامه را در Swift و Kotlin به درستی مدیریت کنید.

نکات اصلی

  • Not Running — برنامه در حافظه بارگذاری نشده و کد اجرا نمی‌کند، این نقطه ورود و خروج در چرخه حیات است
  • راه‌اندازی — انتقال از Not Running با ضربه روی آیکون، از طریق deep link یا اعلان push اتفاق می‌افتد
  • پایان — کاربر برنامه را با swipe می‌بندد، سیستم در کمبود حافظه آن را تخلیه می‌کند یا crash رخ می‌دهد
  • راه‌اندازی سرد — برنامه از صفر شروع می‌شود، همه اشیاء از نو ساخته می‌شوند، وضعیت از کش بازیابی نمی‌شود
  • راه‌اندازی گرم — برنامه در Suspended بوده و بدون مقداردهی کامل به Active بازمی‌گردد

Not Running — این چه حالتی است

Not Running — حالت پایه چرخه حیات یک برنامه موبایل است که در آن برنامه در حافظه RAM دستگاه بارگذاری نشده و منابع سیستم را مصرف نمی‌کند. در iOS و Android این حالت به معنای عدم کامل وجود فرآیندها و رشته‌های مرتبط با برنامه است. کاربر آیکون برنامه را روی دسکتاپ می‌بیند، اما خود برنامه فعال نیست و در لیست اخیرها قرار ندارد.

وقتی کاربر روی آیکون ضربه می‌زند، سیستم یک فرآیند جدید ایجاد می‌کند، کد قابل اجرا را در حافظه بارگذاری می‌کند و تمام ساختارهای داده لازم را مقداردهی می‌کند. این فرآیند راه‌اندازی سرد (cold start) نامیده می‌شود و از نظر زمان بارگذاری پرمصرف‌ترین است.

سیستم می‌تواند برنامه را از هر حالت دیگری به Not Running منتقل کند. اگر برنامه در پس‌زمینه (Background) یا معلق (Suspended) باشد، سیستم عامل حق دارد در کمبود حافظه RAM برای وظایف اولویت‌دارتر آن را تخلیه کند — مثلاً برای یک برنامه فعال در پیش‌زمینه.

توسعه‌دهنده باید در نظر داشته باشد که برنامه می‌تواند در هر لحظه توسط سیستم پایان یابد، زمانی که در پس‌زمینه است. این بدان معناست که تمام داده‌های ذخیره‌نشده ممکن است از دست بروند. بنابراین ذخیره وضعیت در فروشگاه‌های کلید-مقدار (UserDefaults, SharedPreferences) یا در پایگاه داده محلی در انتقال‌های Active به Background بسیار حیاتی است.

سیستم چگونه تعیین می‌کند کدام برنامه را تخلیه کند

iOS از اولویت‌ها بر اساس وضعیت فعلی برنامه استفاده می‌کند: Active بالاترین اولویت را دارد، سپس Inactive، Background، Suspended و در نهایت Not Running — حداقل اولویت. Android از سلسله‌مراتب فرآیند مشابهی استفاده می‌کند: فرآیند Foreground اولویت OOM_ADJ = 0، فرآیند Visible = 100، فرآیند Service = 200، فرآیند Background = 300، فرآیند Empty = 400. هرچه مقدار بالاتر باشد، احتمال پایان یافتن فرآیند در کمبود حافظه بیشتر است.

پلتفرموضعیتاولویت تخلیهتوضیحات
iOSNot Runningبالاترینبرنامه بارگذاری نشده — منبع سیستم مصرف نمی‌شود
iOSSuspendedبالابرنامه در حافظه است اما کد اجرا نمی‌شود — هدف اول برای تخلیه
iOSBackgroundمتوسطبرنامه وظیفه پس‌زمینه را انجام می‌دهد — پس از زمان‌بندی تخلیه می‌شود
iOSActiveپایینبرنامه فعال — فقط در کمبود بحرانی حافظه تخلیه می‌شود
AndroidEmpty Processبالاترینفرآیند بدون مؤلفه فعال — اول حذف می‌شود
AndroidBackground Processبالافرآیند پس‌زمینه بدون Activity قابل مشاهده
AndroidForeground Serviceپایینسرویس با اعلان — به ندرت پایان می‌یابد
AndroidForeground ProcessحداقلActivity فعال — آخر از همه پایان می‌یابد

راه‌اندازی سرد و گرم برنامه

راه‌اندازی سرد (cold start) زمانی رخ می‌دهد که برنامه از Not Running مستقیماً به Active منتقل می‌شود. سیستم یک فرآیند جدید ایجاد می‌کند، کلاس‌ها را بارگذاری می‌کند، فیلدهای ایستا را مقداردهی می‌کند، رشته اصلی را ایجاد می‌کند و چارچوب UI را راه‌اندازی می‌کند. در iOS این به معنای فراخوانی application(_:didFinishLaunchingWithOptions:)، در Android به معنای فراخوانی Application.onCreate() و Activity.onCreate() است. زمان راه‌اندازی سرد بسته به پیچیدگی برنامه می‌تواند از 200 میلی‌ثانیه تا چند ثانیه باشد.

راه‌اندازی گرم (warm start یا hot start) — برنامه در حالت Suspended بوده و بدون بارگذاری مجدد کامل به کار بازمی‌گردد. سیستم آخرین پشته UI را از حافظه بازیابی می‌کند و کاربر کار را از همان مکان ادامه می‌دهد. راه‌اندازی گرم به طور قابل توجهی سریع‌تر از سرد است، زیرا بیشتر کدها قبلاً در حافظه بارگذاری شده‌اند. در iOS راه‌اندازی گرم application(_:didFinishLaunchingWithOptions:) را فراخوانی نمی‌کند، فقط applicationWillEnterForeground و applicationDidBecomeActive را فراخوانی می‌کند.

تفاوت بین راه‌اندازی سرد و گرم برای تجربه کاربری حیاتی است. در راه‌اندازی سرد، توسعه‌دهنده باید اطمینان حاصل کند که راه‌اندازی تا حد امکان سریع انجام می‌شود — مقداردهی تنبل ماژول‌ها، بارگذاری تأخیری منابع سنگین، به حداقل رساندن کار در رشته اصلی در شروع. Google توصیه می‌کند راه‌اندازی سرد بیشتر از 500 میلی‌ثانیه نباشد، Apple — بیشتر از 400 میلی‌ثانیه برای iOS.

kotlin
// اندازه‌گیری زمان راه‌اندازی سرد در Android
class App : Application() {
    private var startTime: Long = 0L

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

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

// راه‌اندازی Activity با مقداردهی تنبل
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)
        // فقط حداقل لازم برای اولین فریم
        setupNavigation()
    }

    override fun onPostCreate(savedInstanceState: Bundle?) {
        super.onPostCreate(savedInstanceState)
        // مقداردهی سنگین پس از رندر
        initializeHeavyModules()
    }
}

در مثال اندازه‌گیری زمان راه‌اندازی سرد در Android نشان داده شده است. Application.onCreate() در انتقال از Not Running به Active فراخوانی می‌شود. برچسب زمانی در شروع فرآیند ثبت می‌شود. Activity از مقداردهی تنبل از طریق lazy-delegate استفاده می‌کند تا اولین فریم را مسدود نکند. onPostCreate مکان بهینه برای مقداردهی ماژول‌های سنگین است، زیرا UI قبلاً رندر شده است.

Not Running در iOS: Swift و AppDelegate

در iOS Not Running از طریق delegate UIApplicationDelegate مدیریت می‌شود. روش‌های کلیدی: application(_:didFinishLaunchingWithOptions:) پس از راه‌اندازی سرد فراخوانی می‌شود، applicationWillTerminate(_:) قبل از پایان برنامه توسط کاربر فراخوانی می‌شود. با این حال سیستم می‌تواند برنامه را بدون فراخوانی applicationWillTerminate پایان دهد — مثلاً در پایان اضطراری یا تخلیه حافظه. iOS تضمین نمی‌کند که این روش فراخوانی شود، بنابراین داده‌ها باید در applicationDidEnterBackground ذخیره شوند.

سناریوهای انتقال به Not Running در iOS

کاربر می‌تواند دستی برنامه را با swipe در App Switcher پایان دهد. سیستم می‌تواند برنامه را از حافظه در پس‌زمینه تخلیه کند. برنامه می‌تواند به طور اضطراری (crash) پایان یابد. در همه موارد، تمام اشیاء ایجاد شده در طول راه‌اندازی نابود می‌شوند. وضعیتی که ذخیره نشده است، به طور جبران‌ناپذیری از دست می‌رود. در iOS 13+ برای ذخیره وضعیت توصیه می‌شود از NSUserActivity یا مکانیزم state restoration از طریق UIApplication.stateRestorationIdentifier استفاده کنید.

swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // راه‌اندازی سرد: برنامه از Not Running منتقل شد
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // مقداردهی حداقل مجموعه سرویس‌ها
        setupAnalytics()
        configureAppearance()
        return true
    }

    // برنامه کار را پایان می‌دهد — فقط بستن دستی
    func applicationWillTerminate(
        _ application: UIApplication
    ) {
        saveCriticalData()
    }

    // ذخیره داده‌ها قبل از رفتن به پس‌زمینه
    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
        )
    }
}

کد مدیریت صحیح Not Running در iOS را نشان می‌دهد. applicationWillTerminate فقط در پایان دستی توسط کاربر فراخوانی می‌شود. ذخیره داده‌های حیاتی در applicationDidEnterBackground تکرار می‌شود، زیرا این روش تضمین شده قبل از رفتن به پس‌زمینه فراخوانی می‌شود. State restoration اجازه می‌دهد پشته UI برای بازیابی بعدی در راه‌اندازی سرد ذخیره شود.

Not Running در Android: Kotlin و فرآیند

در Android Not Running به این معنی است که فرآیند برنامه وجود ندارد. سیستم Linux که Android بر پایه آن است، فرآیندها را از طریق مکانیزم Zygote مدیریت می‌کند. هنگام راه‌اندازی برنامه، Zygote یک فرآیند جدید fork می‌کند، Dalvik/ART را بارگذاری می‌کند و Application.onCreate() را فراخوانی می‌کند. در Android معادل مستقیمی برای applicationWillTerminate وجود ندارد — سیستم می‌تواند در هر لحظه بدون هشدار فرآیند را پایان دهد.

چرخه حیات فرآیند Android

وقتی Activity برای اولین بار فراخوانی می‌شود، سیستم فرآیند، Application و Activity را از طریق زنجیره onCreate → onStart → onResume ایجاد می‌کند. اگر کاربر دکمه Back را فشار دهد، Activity نابود می‌شود (onDestroy) و فرآیند ممکن است توسط سیستم پایان یابد. تفاوت کلیدی با iOS: در Android فرآیند می‌تواند حتی بدون Activity های فعال ادامه وجود داشته باشد — مثلاً اگر Foreground Service در حال اجرا باشد یا BroadcastReceiver فعالی وجود داشته باشد.

kotlin
// مدیریت Not Running از طریق SavedStateHandle در 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 — اولین فراخوانی پس از Not Running
class MyApplication : Application() {

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

SavedStateHandle — مؤلفه Android Architecture Components که به طور خودکار وضعیت را در انتقال به Not Running ذخیره می‌کند و آن را در راه‌اندازی سرد بازیابی می‌کند. ViewModel ایجاد شده از طریق ViewModelProvider از چرخش صفحه و نابودی Activity جان سالم به در می‌برد. در پایان فرآیند، داده‌های SavedStateHandle به Bundle سریالیزه شده و در saved instance state ذخیره می‌شوند.

دلایل انتقال به Not Running

Not Running به چند دلیل رخ می‌دهد. کاربر دستی برنامه را می‌بندد. سیستم برنامه را در کمبود حافظه تخلیه می‌کند. برنامه با خطا به طور اضطراری پایان می‌یابد. در Android سیستم می‌تواند فرآیند را در به‌روزرسانی انبوه برنامه‌ها یا راه‌اندازی مجدد دستگاه پایان دهد. iOS می‌تواند برنامه را در زمان‌بندی وظیفه پس‌زمینه (معمولاً 30 ثانیه) پایان دهد.

دلیلiOSAndroidامکان جلوگیری
بستن دستی توسط کاربرSwipe در App SwitcherSwipe از Recentsخیر — اقدام کاربر
کمبود حافظهفعال شدن memory warningonTrimMemory / LMKتا حدی — بهینه‌سازی حافظه
Crash برنامهNSException / سیگنالUncaughtException / ANRبله — مدیریت خطا و crash-reporting
زمان‌بندی وظیفه پس‌زمینه30 ثانیه برای Background task10 دقیقه برای JobSchedulerبله — برنامه‌ریزی صحیح وظایف
راه‌اندازی مجدد سیستم‌عاملفراخوانی applicationWillTerminateBroadcast ACTION_SHUTDOWNخیر — رویداد سیستمی
به‌روزرسانی برنامهرخ نمی‌دهد (iOS Sandbox)فرآیند در به‌روزرسانی APK پایان می‌یابدخیر — به‌روزرسانی سیستمی

تشخیص انتقال به Not Running

برای iOS از لاگ کنسول در applicationWillTerminate و applicationDidFinishLaunching استفاده کنید. در هر راه‌اندازی یک پرچم به UserDefaults اضافه کنید — اگر در شروع بعدی پرچم وجود نداشت، برنامه به درستی پایان نیافته است. در Android از ActivityManager.isBackgroundRestricted() استفاده کنید تا بررسی کنید آیا برنامه می‌تواند وظایف پس‌زمینه را اجرا کند. همچنین onTrimMemory(TRIM_MEMORY_COMPLETE) را ردیابی کنید — این سیگنالی است که فرآیند پایان خواهد یافت.

بهترین روش‌های کار با Not Running

قانون اول — هرگز فرض نکنید که applicationWillTerminate یا onDestroy فراخوانی خواهند شد. داده‌های حیاتی را در هر انتقال از Active به Background ذخیره کنید. از فروشگاه‌های کلید-مقدار برای تنظیمات ساده و SQLite/Room برای داده‌های ساختاریافته استفاده کنید.

قانون دوم — زمان راه‌اندازی سرد را اندازه‌گیری و بهینه‌سازی کنید. مقداردهی تنبل، به حداقل رساندن کار در رشته اصلی، بارگذاری پیش‌فرض منابع، استفاده از SplashScreen API — همه اینها درک زمان راه‌اندازی را بهبود می‌بخشد. Google توصیه می‌کند راه‌اندازی سرد کمتر از 200 میلی‌ثانیه برای UX عالی.

قانون سوم — State Restoration را پیاده‌سازی کنید. در iOS از UIApplication.stateRestorationIdentifier و NSUserActivity استفاده کنید. در Android از SavedStateHandle در ViewModel به همراه onSaveInstanceState استفاده کنید. این به کاربر اجازه می‌دهد پس از راه‌اندازی مجدد برنامه از همان مکان به کار ادامه دهد.

قانون چهارم — launchOptions و Intent را که برنامه با آنها پس از Not Running راه‌اندازی شده است، مدیریت کنید. Deep link‌ها، اعلان‌های push، پیوندهای جهانی — همه آنها از طریق پارامترهای راه‌اندازی منتقل می‌شوند. توسعه‌دهنده باید این داده‌ها را به درستی استخراج کرده و کاربر را به صفحه مربوطه هدایت کند.

swift
// مدیریت deep link پس از راه‌اندازی سرد
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    // بررسی رسیدن اعلان
    if let notification = launchOptions?[.remoteNotification] as? [String: Any] {
        handleNotification(notification)
    }
    // بررسی 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)
}

کد مدیریت پارامترهای راه‌اندازی در راه‌اندازی سرد iOS را نشان می‌دهد. launchOptions حاوی داده‌هایی است که سیستم برنامه را با آنها راه‌اندازی کرده است. اعلان‌ها، deep link‌ها و پیوندهای جهانی از طریق این دیکشنری منتقل می‌شوند. توسعه‌دهنده باید تمام سناریوهای ممکن راه‌اندازی را به درستی مدیریت کند تا تجربه کاربری بی‌نقصی ارائه دهد.

سوالات متداول

در انتقال به Not Running چه اتفاقی برای داده‌ها می‌افتد؟

داده‌هایی که در حافظه دائمی ذخیره شده‌اند (UserDefaults, Core Data, SharedPreferences, Room) حفظ می‌شوند. داده‌های موجود در RAM — متغیرها، کش، وضعیت ViewModel بدون SavedStateHandle — به طور جبران‌ناپذیری از دست می‌روند. بنابراین ذخیره وضعیت برنامه در هر انتقال به پس‌زمینه بسیار حیاتی است.

چگونه راه‌اندازی سرد را از گرم در iOS تشخیص دهیم؟

در راه‌اندازی سرد application(_:didFinishLaunchingWithOptions:) فراخوانی می‌شود. در راه‌اندازی گرم (بازگشت از Suspended) این روش فراخوانی نمی‌شود — فقط applicationWillEnterForeground و applicationDidBecomeActive فعال می‌شوند. اگر نیاز به انجام عملی فقط در راه‌اندازی سرد دارید، یک پرچم در didFinishLaunchingWithOptions تنظیم کنید.

آیا برنامه Android می‌تواند با Service فعال در Not Running باشد؟

بله. Foreground Service با اعلان دائمی از پایان فرآیند توسط سیستم جلوگیری می‌کند، حتی اگر همه Activity ها نابود شده باشند. Background Service (startService بدون foreground) ممکن است در هر زمان توسط سیستم متوقف شود. Service در حال اجرا به این معنی است که فرآیند وجود دارد و این دیگر Not Running نیست.

چگونه Not Running را در شبیه‌ساز شبیه‌سازی کنیم؟

در شبیه‌ساز iOS برنامه را از طریق App Switcher پایان دهید (Cmd+Shift+H دو بار، swipe به بالا). در شبیه‌ساز Android از adb shell am force-stop com.example.app یا دکمه Stop در Logcat استفاده کنید. سپس برنامه را دوباره راه‌اندازی کنید — این یک راه‌اندازی سرد تمیز از Not Running خواهد بود.

kill-switch در زمینه Not Running چیست؟

Kill-switch — دستور سرور برای پایان اضطراری برنامه. در برنامه‌های بانکی و شرکتی برای مسدود کردن دسترسی از راه دور استفاده می‌شود. اگر برنامه دستور kill را دریافت کرده باشد، در راه‌اندازی سرد بعدی UI را مسدود کرده و درخواست مجوز مجدد می‌کند. در iOS kill-switch از طریق remote notifications با پرچم مسدودسازی پیاده‌سازی می‌شود.

خلاصه

  • Not Running — حالت اولیه و نهایی چرخه حیات، برنامه در حافظه بارگذاری نشده و کد اجرا نمی‌کند
  • راه‌اندازی سرد — بارگذاری مجدد کامل برنامه از Not Running، نیازمند مقداردهی همه مؤلفه‌ها از صفر
  • راه‌اندازی گرم — بازگشت از Suspended، didFinishLaunchingWithOptions یا Application.onCreate را فراخوانی نمی‌کند
  • ذخیره داده‌ها — در انتقال به Background بسیار حیاتی است، زیرا Not Running ممکن است در هر لحظه رخ دهد
  • iOS — applicationWillTerminate تضمین نشده، وضعیت از طریق UserDefaults یا state restoration ذخیره می‌شود
  • Android — فرآیند می‌تواند در هر لحظه پایان یابد، SavedStateHandle در ViewModel وضعیت را خودکار ذخیره می‌کند
  • بهینه‌سازی راه‌اندازی — مقداردهی تنبل، حداقل کار در main thread، SplashScreen API برای اولین فریم سریع

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید