Not Running — ما هي، الحالة الأولية لدورة الحياة

المؤلف: IT Sectr نُشر: 2026-03-03 وقت القراءة: 11 دق

Not Running — الحالة الأولية لدورة حياة التطبيق المحمول عندما لم يتم تشغيله بعد أو أنهى عمله بالفعل. تعرف على كيفية إدارة iOS وAndroid لهذه الحالة، وما الأحداث التي تؤدي إلى الانتقال من Not Running وكيفية التعامل بشكل صحيح مع بدء التطبيق وإنهائه في Swift وKotlin.

الرئيسية

  • Not Running — التطبيق غير محمل في الذاكرة ولا ينفذ كوداً، إنها نقطة الدخول والخروج في دورة الحياة
  • التشغيل — يحدث الانتقال من Not Running عند النقر على أيقونة التطبيق، عبر رابط عميق أو إشعار دفع
  • الإنهاء — يغلق المستخدم التطبيق بتمريرة، يقوم النظام بتفريغه عند نقص الذاكرة أو يحدث تعطل
  • التشغيل البارد — يبدأ التطبيق من الصفر، يتم إنشاء جميع الكائنات من جديد، لا تتم استعادة الحالة من الذاكرة المؤقتة
  • التشغيل الساخن — كان التطبيق في حالة Suspended ويعود إلى Active بدون تهيئة كاملة

Not Running — ما هي هذه الحالة

Not Running هي الحالة الأساسية لدورة حياة التطبيق المحمول حيث لا يكون محملاً في ذاكرة الوصول العشوائي للجهاز ولا يستهلك موارد النظام. في iOS وAndroid، تعني هذه الحالة الغياب التام للعمليات والمسارات المرتبطة بالتطبيق. يرى المستخدم أيقونة التطبيق على الشاشة الرئيسية، لكن التطبيق نفسه غير نشط وليس في قائمة التطبيقات الحديثة.

عندما ينقر المستخدم على أيقونة التطبيق، يقوم النظام بإنشاء عملية جديدة، وتحميل الكود القابل للتنفيذ في الذاكرة وتهيئة جميع هياكل البيانات الضرورية. تسمى هذه العملية التشغيل البارد (cold start) وهي الأكثر استهلاكاً للموارد من حيث وقت التحميل.

يمكن للنظام نقل التطبيق إلى Not Running من أي حالة أخرى. إذا كان التطبيق في الخلفية أو معلقاً، يحق لنظام التشغيل تفريغه عند عدم كفاية ذاكرة الوصول العشوائي للمهام ذات الأولوية الأعلى — على سبيل المثال، لتطبيق نشط في المقدمة.

يجب على المطور أن يأخذ في الاعتبار أن التطبيق يمكن إنهاؤه من قبل النظام في أي لحظة عندما يكون في الخلفية. هذا يعني أن جميع البيانات غير المحفوظة قد تُفقد. لذلك، من المهم جداً حفظ الحالة في مخازن مفتاح-قيمة (UserDefaults, SharedPreferences) أو في قاعدة بيانات محلية أثناء الانتقالات من Active إلى Background.

كيف يحدد النظام أي تطبيق سيتم تفريغه

يستخدم iOS أولويات بناءً على حالة التطبيق الحالية: Active لديه أعلى أولوية، يليه Inactive، ثم Background، ثم Suspended، وأخيراً Not Running — أقل أولوية. يستخدم Android هيكلية عمليات مماثلة: عملية المقدمة لها أولوية 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 لتجنب حجب الإطار الأول. onPostCreate هو المكان الأمثل لتهيئة الوحدات الثقيلة حيث أن UI قد تم عرضه بالفعل.

Not Running في iOS: Swift وAppDelegate

في iOS، يتم إدارة Not Running من خلال بروتوكول UIApplicationDelegate. الطرق الرئيسية: application(_:didFinishLaunchingWithOptions:) يُستدعى بعد التشغيل البارد، applicationWillTerminate(_:) يُستدعى قبل إنهاء المستخدم للتطبيق. ومع ذلك، يمكن للنظام إنهاء التطبيق دون استدعاء applicationWillTerminate — على سبيل المثال، أثناء الإنهاء الطارئ أو ضغط الذاكرة. لا يضمن iOS استدعاء هذه الطريقة، لذلك يجب حفظ البيانات في applicationDidEnterBackground.

سيناريوهات الانتقال إلى Not Running في iOS

يمكن للمستخدم إنهاء التطبيق يدوياً بتمريرة في App Switcher. يمكن للنظام تفريغ التطبيق من الذاكرة أثناء وجوده في الخلفية. قد يتعطل التطبيق. في جميع الحالات، يتم تدمير جميع الكائنات التي تم إنشاؤها أثناء بدء التشغيل. الحالة التي لم يتم حفظها تُفقد إلى الأبد. في iOS 13+، يُوصى باستخدام NSUserActivity أو آلية استعادة الحالة عبر 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 لأن هذه الطريقة مضمونة الاستدعاء قبل الذهاب إلى الخلفية. تسمح استعادة الحالة بحفظ كومة UI للاسترداد لاحقاً أثناء التشغيل البارد.

Not Running في Android: Kotlin والعملية

في Android، Not Running يعني أن عملية التطبيق غير موجودة. نظام Linux الذي يقوم عليه Android يدير العمليات من خلال آلية Zygote. عند بدء تشغيل التطبيق، يقوم Zygote بتفرع عملية جديدة، وتحميل Dalvik/ART واستدعاء Application.onCreate(). لا يوجد في Android مقابل مباشر لـ applicationWillTerminate — يمكن للنظام إنهاء العملية في أي وقت دون إنذار.

دورة حياة العملية في Android

عند استدعاء Activity لأول مرة، يقوم النظام بإنشاء العملية وApplication وActivity من خلال السلسلة onCreate → onStart → onResume. إذا ضغط المستخدم على زر الرجوع، يتم تدمير Activity (onDestroy)، وقد يتم إنهاء العملية بواسطة النظام. فرق رئيسي عن iOS: في Android، يمكن للعملية الاستمرار في الوجود حتى بدون Activities نشطة — على سبيل المثال، إذا كان 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 وحفظها في حالة المثيل المحفوظة.

أسباب الانتقال إلى Not Running

Not Running يحدث لعدة أسباب. يغلق المستخدم التطبيق يدوياً. يقوم النظام بتفريغ التطبيق بسبب نقص الذاكرة. يتعطل التطبيق مع استثناء. في Android، قد ينهي النظام العملية أثناء تحديث شامل للتطبيقات أو إعادة تشغيل الجهاز. قد ينهي iOS التطبيق عند انتهاء مهلة مهمة الخلفية (عادة 30 ثانية).

السببiOSAndroidإمكانية المنع
الإغلاق اليدوي من قبل المستخدمتمريرة في App Switcherتمريرة من Recentsلا — إجراء المستخدم
نقص الذاكرةتفعيل تحذير الذاكرةonTrimMemory / LMKجزئياً — تحسين الذاكرة
تعطل التطبيقNSException / إشارةUncaughtException / ANRنعم — معالجة الأخطاء والإبلاغ عن الأعطال
مهلة مهمة الخلفية30 ثانية لمهمة الخلفية10 دقائق لـ JobSchedulerنعم — جدولة المهام الصحيحة
إعادة تشغيل نظام التشغيلاستدعاء applicationWillTerminateBroadcast ACTION_SHUTDOWNلا — حدث نظامي
تحديث التطبيقلا يحدث (iOS Sandbox)تُنهى العملية عند تحديث APKلا — تحديث النظام

كيفية تشخيص الانتقال إلى Not Running

لنظام iOS، استخدم تسجيل console في applicationWillTerminate وapplicationDidFinishLaunching. أضف علامة في UserDefaults عند كل بدء تشغيل — إذا كانت العلامة مفقودة في البداية التالية، فقد تم إنهاء التطبيق بشكل غير صحيح. في Android، استخدم ActivityManager.isBackgroundRestricted() للتحقق مما إذا كان التطبيق يمكنه تشغيل مهام الخلفية. أيضاً، راقب onTrimMemory(TRIM_MEMORY_COMPLETE) — هذه إشارة إلى أنه سيتم إنهاء العملية.

أفضل الممارسات للعمل مع Not Running

القاعدة الأولى — لا تفترض أبداً أنه سيتم استدعاء applicationWillTerminate أو onDestroy. احفظ البيانات المهمة بشكل حرج عند كل انتقال من Active إلى Background. استخدم مخازن مفتاح-قيمة للإعدادات البسيطة وSQLite/Room للبيانات المنظمة.

القاعدة الثانية — قس وقت التشغيل البارد وحسّنه. التهيئة البطيئة، تقليل العمل في المسار الرئيسي، التحميل المسبق للموارد، استخدام واجهة برمجة تطبيقات SplashScreen — كل هذا يحسن وقت بدء التشغيل المدرك. يوصي Google بتشغيل بارد أقل من 200 مللي ثانية لتجربة مستخدم ممتازة.

القاعدة الثالثة — قم بتنفيذ استعادة الحالة. في iOS، استخدم UIApplication.stateRestorationIdentifier وNSUserActivity. في Android، استخدم SavedStateHandle في ViewModel مقترناً بـ onSaveInstanceState. سيسمح هذا للمستخدم بمواصلة العمل من نفس النقطة بعد إعادة تشغيل التطبيق.

القاعدة الرابعة — تعامل مع launchOptions وIntent التي تم تشغيل التطبيق بها بعد Not Running. الروابط العميقة، إشعارات الدفع، الروابط العامة — كلها تُمرر عبر معلمات بدء التشغيل. يجب على المطور استخراج هذه البيانات بشكل صحيح وتوجيه المستخدم إلى الشاشة المناسبة.

swift
// معالجة الرابط العميق بعد التشغيل البارد
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    // التحقق من وصول الإشعار
    if let notification = launchOptions?[.remoteNotification] as? [String: Any] {
        handleNotification(notification)
    }
    // التحقق من الرابط العميق
    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 يحتوي على البيانات التي قام النظام بتشغيل التطبيق بها. يتم تمرير الإشعارات والروابط العميقة والروابط العامة من خلال هذا القاموس. يجب على المطور معالجة جميع سيناريوهات بدء التشغيل الممكنة بشكل صحيح لضمان تجربة مستخدم سلسة.

الأسئلة الشائعة

ماذا يحدث للبيانات عند الانتقال إلى Not Running؟

البيانات التي تم حفظها في التخزين الدائم (UserDefaults, Core Data, SharedPreferences, Room) يتم الاحتفاظ بها. البيانات في ذاكرة الوصول العشوائي — المتغيرات، الذاكرة المؤقتة، حالة ViewModel بدون SavedStateHandle — تُفقد بشكل لا رجعة فيه. لذلك، من المهم جداً حفظ حالة التطبيق عند كل انتقال إلى الخلفية.

كيف أميز بين التشغيل البارد والساخن في iOS؟

أثناء التشغيل البارد، يتم استدعاء application(_:didFinishLaunchingWithOptions:). أثناء التشغيل الساخن (العودة من Suspended)، لا يتم استدعاء هذه الطريقة — يتم تفعيل applicationWillEnterForeground وapplicationDidBecomeActive فقط. إذا كنت بحاجة إلى تنفيذ إجراء فقط عند التشغيل البارد، قم بتعيين علامة في didFinishLaunchingWithOptions.

هل يمكن أن يكون تطبيق Android في Not Running مع Service نشط؟

نعم. Foreground Service مع إشعار دائم يمنع النظام من إنهاء العملية، حتى إذا تم تدمير جميع Activities. يمكن إيقاف Background Service (startService بدون foreground) بواسطة النظام في أي وقت. وجود Service قيد التشغيل يعني أن العملية موجودة، وهذا لم يعد Not Running.

كيفية محاكاة Not Running على المحاكي؟

على محاكي iOS، قم بإنهاء التطبيق من خلال App Switcher (Cmd+Shift+H مرتين، تمريرة لأعلى). على محاكي Android، استخدم adb shell am force-stop com.example.app أو زر الإيقاف في Logcat. بعد ذلك، قم بتشغيل التطبيق مرة أخرى — سيكون هذا تشغيلاً بارداً نظيفاً من Not Running.

ما هو kill-switch في سياق Not Running؟

Kill-switch هو أمر خادم للإنهاء الطارئ للتطبيق. يُستخدم في التطبيقات المصرفية والمؤسسية لحظر الوصول عن بُعد. إذا تلقى التطبيق أمر kill، عند التشغيل البارد التالي يقوم بحظر UI ويطلب إعادة المصادقة. في iOS، يتم تنفيذ kill-switch عبر الإشعارات عن بُعد مع علامة حظر.

الملخص

  • Not Running — الحالة الأولية والنهائية لدورة الحياة، التطبيق غير محمل في الذاكرة ولا ينفذ كوداً
  • التشغيل البارد — إعادة تشغيل كاملة للتطبيق من Not Running، يتطلب تهيئة جميع المكونات من الصفر
  • التشغيل الساخن — العودة من Suspended، لا يستدعي didFinishLaunchingWithOptions أو Application.onCreate
  • حفظ البيانات — من المهم جداً القيام به عند الانتقال إلى الخلفية، حيث أن Not Running يمكن أن يحدث في أي لحظة
  • iOS — applicationWillTerminate غير مضمون، يتم حفظ الحالة عبر UserDefaults أو استعادة الحالة
  • Android — يمكن إنهاء العملية في أي وقت، SavedStateHandle في ViewModel يحفظ الحالة تلقائياً
  • تحسين بدء التشغيل — تهيئة بطيئة، عمل أدنى في المسار الرئيسي، واجهة برمجة تطبيقات SplashScreen لإطار أول سريع

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا