Warm Start: الجوهر، الإطلاق الدافئ والتحسين في Android

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

Warm Start هو سيناريو إطلاق تطبيق Android حيث تكون عملية التطبيق موجودة بالفعل في الذاكرة (على سبيل المثال، بعد التصغير)، ولكن تم تدمير Activity بواسطة النظام لتوفير الموارد. تم تنفيذ Application.onCreate بالفعل، وتم تحميل الفئات، ولكن يتم إنشاء UI من جديد. وفقاً لـ Google، 2024، يستغرق Warm Start من 200 إلى 800 مللي ثانية ويمثل حوالي 40% من جميع عمليات الإطلاق على الأجهزة ذات 4 جيجابايت RAM.

الخلاصة

  • Warm Start — إطلاق التطبيق بعملية موجودة، ولكن دون Activity في الذاكرة
  • الفرق عن Cold Start: لا يتم تنفيذ Application.onCreate، الفئات محملة بالفعل
  • الوقت يستغرق Warm Start 200–800 مللي ثانية مقابل 1–5 ثوانٍ لـ Cold Start
  • السيناريوهات: العودة إلى التطبيق بعد عدة ساعات، إزالة Activity بواسطة OOM-killer
  • التحسين يركز على الحفاظ على حالة Activity والتخزين المؤقت للبيانات

ما هو Warm Start

Warm Start هو حالة بين Cold Start وHot Start: عملية التطبيق موجودة في الذاكرة (أحياناً في ذاكرة التخزين المؤقت الخلفية لنظام Linux)، ولكن Activity غير نشطة وسيتم إنشاؤها من جديد. عندما تنفد RAM من Android، قد يزيل Activity من المكدس، تاركاً العملية حية. عندما يعود المستخدم إلى التطبيق، يحدث Warm Start: يتم إنشاء مثيل جديد لـ Activity، يتم تنفيذ طرق دورة الحياة onCreate ← onStart ← onResume، ولكن يتم تخطي Application.onCreate وتحميل الفئات.

أسباب Warm Start

يقرر Android إزالة Activity بناءً على أولوية العملية (مرتبة الأهمية). Activity في الخلفية (المستوى PROCESS_STATE_IMPORTANT_FOREGROUND أو PROCESS_STATE_TOP_SLEEPING) قد يتم تدميرها بعد 5–30 دقيقة من تصغير التطبيق، حسب RAM المتاحة. على الأجهزة ذات 3 جيجابايت RAM، قد يتم إزالة Activity خلال 10 دقائق؛ على الأجهزة ذات 8 جيجابايت RAM، بعد عدة ساعات. من المهم: أثناء Warm Start، يتم استدعاء onSaveInstanceState قبل تدمير Activity، ويمكن للمطور حفظ حالة UI.

إدراك المستخدم

لا يرى المستخدم الفرق بين Warm وCold Start — هو ببساطة يضغط على أيقونة التطبيق وينتظر. ومع ذلك، أثناء Warm Start، قد تظهر شاشة بيضاء إذا لم يقم التطبيق بتعيين سمة نافذة بدء مخصصة. Google توصي بتعيين سمة مخصصة في البيان (Theme.AppCompat.Light أو Theme.Material3.DayNight) لنشاط البدء لتجنب وميض الشاشة البيضاء/السوداء أثناء Warm Start. على Android 12+، تخفي API SplashScreen هذا التأثير أيضاً.

Warm Start مقابل Cold Start مقابل Hot Start

فهم الفرق بين أنواع الإطلاق الثلاثة ضروري لاختيار استراتيجية التنميط والتحسين الصحيحة. لكل نوع مدته الخاصة، واختناقاته، وأدوات القياس الخاصة به.

المعيارCold StartWarm StartHot Start
العمليةتنشأ من الصفرموجودة في الذاكرةموجودة في الذاكرة
Application.onCreateيتم تنفيذهلا يتم تنفيذهلا يتم تنفيذه
Activityتنشأ من الصفرتنشأ من الصفرتستعاد من المكدس
الوقت1–5 ثوانٍ200–800 مللي ثانية< 200 مللي ثانية
onCreate Activityكاملكامل (مع استعادة)يتم تخطيه

عملياً، يمثل Warm Start من 30% إلى 60% من جميع عمليات إطلاق التطبيقات، حسب عادات المستخدم وRAM الجهاز. المستخدمون الذين يبقون العديد من التطبيقات مفتوحة (متعددو المهام) يواجهون Warm Start أكثر. للشبكات الاجتماعية والمراسلات، Warm Start هو السيناريو الأكثر شيوعاً لأن التطبيق دائماً في الخلفية. للتطبيقات المصرفية، على العكس، يسود Cold Start (تنظيف إجباري للعملية لأسباب أمنية).

مراحل الإطلاق الدافئ

يتكون Warm Start من ثلاث مراحل، كل منها يمكن قياسها وتحسينها. على عكس Cold Start، لا توجد مرحلة fork ولا تحميل فئات، ولكن هناك مرحلة استعادة الحالة التي قد تكون مكلفة.

المرحلة 1: نافذة البدء (خلفية النافذة)

يتحقق النظام مما إذا كان للتطبيق سمة لنافذة البدء. إذا لم يتم تعيين السمة، تظهر شاشة بيضاء (أو سوداء، حسب النظام). إذا تم تعيين السمة، يتم عرض خلفية السمة. تستغرق هذه المرحلة 10–30 مللي ثانية، لكنها ملحوظة بصرياً إذا كانت السمة لا تتطابق مع UI الفعلي للتطبيق. استخدم Theme.Material3.DayNight مع windowBackground مخصص يتطابق لونه مع خلفية الشاشة الأولى — وهذا يخلق تأثير تحميل فوري.

المرحلة 2: إنشاء Activity (الاستعادة)

يستدعي النظام onCreate مرراً Bundle savedInstanceState الذي تم حفظه في onSaveInstanceState قبل تدمير Activity. إذا حفظ التطبيق الحالة بشكل صحيح (نص الحقول، موضع التمرير، بيانات ViewModel)، تتم الاستعادة بسرعة. إذا لم يكن كذلك، تبدأ Activity من الصفر ويرى المستخدم مؤشر تحميل بينما يتم تحميل البيانات. النقطة الرئيسية: كائنات ViewModel تنجو من Warm Start فقط إذا لم يتم تدمير العملية — أثناء Warm Start، يبقى ViewModel في الذاكرة.

المرحلة 3: الإطار الأول (TTFD)

بعد onCreate، يتم تنفيذ onStart ← onResume، ويقوم النظام بتشغيل الرسم الأول. TTFD (الوقت حتى الرسم الأول) لـ Warm Start يجب أن يكون أقل من 300 مللي ثانية على جهاز متوسط. إذا كانت الشاشة الأولى تحتوي على RecyclerView معقد مع Views ثقيلة أو تحميل صور من الشبكة، قد يتجاوز TTFD العتبة. استخدم Placeholder وShimmer لتحميل سلس للمحتوى بعد الإطار الأول.

كيفية قياس Warm Start

قياس Warm Start أكثر تعقيداً من Cold Start لأنك تحتاج لمحاكاة الحالة حيث العملية حية ولكن Activity مدمرة. أمر ADB القياسي مع العلم -S لا يعمل — فهو يقتل العملية. استخدم طرقاً مختلفة لـ Warm Start.

ADB shell am start بدون -S

أولاً، قم بتشغيل التطبيق عبر adb shell monkey أو اضغط على الأيقونة، ثم صغره (adb shell input keyevent 3 keyevent HOME). انتظر 5–10 ثوانٍ ليتمكن النظام من إزالة Activity، ثم قم بتشغيل adb shell am start -W (بدون -S). سيعيد الأمر وقت إطلاق أقصر من Cold Start. للتكرار، استخدم سكريبت: تشغيل ← انتظار ← home ← انتظار ← تشغيل.

bash
# محاكاة Warm Start عبر ADB
$ adb shell am start -W \
    com.example.app/.MainActivity

# الإخراج (Warm Start):
# ThisTime: 412 ms
# TotalTime: 412 ms
# WaitTime: 423 ms

Macrobenchmark لـ Warm Start

مكتبة androidx.benchmark.macro تدعم قياس Warm Start. في الاختبار، قم بتعيين startupMode = StartupMode.WARM — ستقوم المكتبة بتشغيل التطبيق، وتصغيره، والانتظار (تأخير قابل للتكوين)، ثم قياس إعادة التشغيل. يقوم Macrobenchmark بـ 10–20 تكراراً ويحسب النسب المئوية. في CI/CD، يمكنك تعيين عتبة: إذا تجاوز P50 Warm Start 600 مللي ثانية، يفشل الاختبار. هذا يسمح بتتبع الانحدارات مع كل commit.

مراقبة أداء Firebase

يميز Firebase تلقائياً بين Cold وWarm Start بناءً على الوقت منذ آخر إغلاق للتطبيق. إذا تم فتح التطبيق خلال آخر 30 دقيقة، يصنف Firebase الإطلاق كـ Warm. في وحدة تحكم Firebase، سترى رسوماً بيانية منفصلة لكل نوع إطلاق، مما يسمح لك بتقييم فعالية التحسينات. على سبيل المثال، بعد تنفيذ الحفاظ على الحالة في ViewModel، قد ترى انخفاضاً بنسبة 30% في وقت Warm Start.

كيفية تحسين Warm Start

يركز تحسين Warm Start على مجالين: تسريع Activity.onCreate والاستعادة الصحيحة للحالة. نظراً لأن Application.onCreate وتحميل الفئات قد اكتملا بالفعل، فإن الاختناق الرئيسي هو كود UI للشاشة الأولى.

الاستعادة غير المتزامنة للحالة

إذا كانت الحالة المحفوظة (savedInstanceState) تحتوي على بيانات تحتاج إلى إلغاء التسلسل (Bitmap, String, JSON)، قم بذلك في سلسلة خلفية. بدلاً من القراءة مباشرة من Bundle في onCreate، قم بتشغيل coroutine وأظهر شاشة shimmer. عملياً، إلغاء تسلسل Bundle على جهاز متوسط يستغرق 20–100 مللي ثانية — يبدو قليلاً، ولكن لـ Warm Start، هذا 10–50% من الوقت الإجمالي. استخدم Saved State Module من Jetpack، الذي يحفظ ويستعيد تلقائياً حالة ViewModel في Bundle أو قاعدة البيانات.

تحسين setContentView

تضخيم تخطيط XML هو أحد أغلى مراحل Warm Start. إذا كانت الشاشة الأولى تستخدم CoordinatorLayout معقداً مع AppBar وCollapsingToolbar وNestedScrollView وثلاث RecyclerViews، يمكن أن يصل وقت التضخيم إلى 300 مللي ثانية. الحلول: استخدم ConstraintLayout لتسلسل هرمي مسطح، طبق ViewStub للأقسام غير المرئية عند البدء (bottom sheet, dialog)، فعّل التضخيم غير المتزامن للـ fragments الثقيلة عبر AsyncLayoutInflater. في Jetpack Compose، لا حاجة للتضخيم، لكن تجميع شجرة Compose أثناء Warm Start قد يستغرق وقتاً مماثلاً.

التخزين المؤقت للبيانات

أثناء Warm Start، البيانات التي حملها التطبيق في الجلسة السابقة قد تكون بالفعل في الذاكرة المؤقتة: قاعدة بيانات Room، SharedPreferences، ذاكرة مؤقتة في ViewModel. إذا كانت شاشتك الأولى تعرض قائمة من الخادم، تحقق من الذاكرة المؤقتة عند البدء وحدّث البيانات في الخلفية. استخدم استراتيجية cache-then-network: اعرض أولاً البيانات المخزنة مؤقتاً (فورياً)، ثم حدّث من الخادم (بشكل غير متزامن). هذا يقلل وقت Warm Start المدرك إلى 100–200 مللي ثانية.

kotlin
// ViewModel مع التخزين المؤقت لـ Warm Start
class FeedViewModel : ViewModel() {
    private val cache = MutableStateFlow<List<Item>>(emptyList())

    init {
        // ذاكرة مؤقتة أولاً، ثم الشبكة
        viewModelScope.launch {
            cache.emit(db.getItems()) // Warm Start: البيانات موجودة بالفعل في BD
            cache.emit(api.fetchItems()) // تحديث في الخلفية
        }
    }
}

الحفاظ على الحالة أثناء Warm Start

الحفاظ الصحيح على الحالة هو العامل الرئيسي الذي يميز Warm Start الجيد عن السيئ. يتوقع المستخدم العودة إلى التطبيق ورؤية ما تركه تماماً — بما في ذلك موضع التمرير، النص في الحقول، وعلامات التبويب المحددة.

onSaveInstanceState

يستدعي النظام onSaveInstanceState عندما يتم تدمير Activity، ولكن قبل أن يتم قتل العملية. يتم حفظ أنواع البيانات البسيطة فقط (String, Int, Parcelable, Serializable) في Bundle. للبيانات المعقدة، استخدم SavedStateHandle في ViewModel — فهو يحفظ ويستعيد الحقول تلقائياً أثناء Warm Start. على عكس onSaveInstanceState، يعمل SavedStateHandle حتى إذا نجت العملية من Warm Start (ViewModel لا يُدمر). مثال: للنص في EditText، استخدم SavedStateHandle.getLiveData(“text”) — سيتم حفظ النص واستعادته تلقائياً.

ViewModel وWarm Start

إذا لم تُقتل العملية أثناء Warm Start، يبقى ViewModel في الذاكرة ولا يتم استدعاء onCleared. هذا يعني أن جميع البيانات المحملة في الجلسة السابقة متاحة فورياً. ومع ذلك، إذا قُتلت العملية (الجهاز في سكون عميق لأكثر من 30 دقيقة)، يتم تدمير ViewModel وإنشاؤه من جديد مع SavedStateHandle. لسلوك ViewModel الصحيح أثناء Warm Start، استخدم SavedStateHandle مع الحقول التي تحتاج إلى الاستعادة في أي سيناريو. الفرق: ViewModel مع @HiltViewModel يدعم SavedStateHandle تلقائياً.

الآليةالعملية حيةالعملية مقتولة
ViewModelالبيانات في الذاكرةمدمر، يُنشأ من جديد
SavedStateHandleالبيانات في الذاكرةيُستعاد من Bundle
onSaveInstanceStateيُستدعى عند إزالة Activityلا يُستدعى
Room DBالذاكرة المؤقتة متاحةالذاكرة المؤقتة متاحة (قرص)

حفظ موضع تمرير RecyclerView

أحد أكثر مشاكل Warm Start شيوعاً — فقدان موضع التمرير. قام المستخدم بالتمرير إلى العنصر 50، صغر التطبيق، عاد — ويرى بداية القائمة. الحل: احفظ layoutManager.onSaveInstanceState (يحفظ الموضع والإزاحة لأول عنصر مرئي) واستعدده في onRestoreInstanceState. يمكنك أيضاً حفظ آخر موضع مرئي في SharedPreferences بمفتاح تاريخ/وقت لاستعادة الموضع بسرعة أثناء Warm Start.

kotlin
// حفظ موضع تمرير RecyclerView
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putParcelable(
        "rv_state", binding.recyclerView
            .layoutManager?.onSaveInstanceState()
    )
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    savedInstanceState?.getParcelable<Parcelable>("rv_state")
        ?.let { binding.recyclerView.layoutManager?.onRestoreInstanceState(it) }
}

أمثلة كود لـ Warm Start

مثالان عمليان لتحسين Warm Start: استخدام SavedStateHandle في ViewModel والاستعادة غير المتزامنة للبيانات المعقدة بعد الإطلاق.

ViewModel مع SavedStateHandle

SavedStateHandle يحفظ الحقول تلقائياً في Bundle ويستعيدها أثناء Warm Start. سيتم استعادة حقل ملف تعريف المستخدم (String, JSON) دون طلبات غير ضرورية للخادم. إذا قُتلت العملية، يقوم SavedStateHandle بتحميل آخر حالة محفوظة من Bundle.

kotlin
class ProfileViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    val profile: StateFlow<Profile?>
        get() = savedStateHandle
            .getStateFlow("profile", null)

    fun loadProfile(id: String) {
        viewModelScope.launch {
            savedStateHandle["profile"] =
                api.getProfile(id)
        }
    }
}

// Warm Start: profile ليس null، UI بدون محمل
// بعد التحميل: profile يتم تحديثه في SavedStateHandle

AsyncLayoutInflater للشاشات الثقيلة

إذا كانت الشاشة الأولى تحتوي على تخطيط معقد (خريطة، تدرج، قوائم متعددة)، استخدم AsyncLayoutInflater لتضخيم العناصر الثقيلة في الخلفية. بينما يتم تضخيم التخطيط، اعرض placeholder مع تأثير shimmer. هذا مهم بشكل خاص لـ Warm Start، حيث كل ملي ثانية لها أهميتها. يعمل AsyncLayoutInflater على سلسلة خلفية ويمرر View الجاهز إلى callback في السلسلة الرئيسية.

kotlin
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // تخطيط placeholder للعرض الفوري
        setContentView(R.layout.placeholder_shimmer)

        // تحميل غير متزامن للتخطيط الثقيل
        AsyncLayoutInflater(this).inflate(
            R.layout.activity_main_complex,
            findViewById(R.id.container)
        ) { view, resId, parent ->
            parent?.removeAllViews()
            parent?.addView(view)
        }
    }
}

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

هل يمكن أن يتحول Warm Start إلى Cold Start؟

نعم، إذا قرر النظام في لحظة Warm Start قتل عملية التطبيق (مثلاً لتحرير الذاكرة لتطبيق آخر)، يصبح الإطلاق Cold Start من الصفر. يحدث هذا على الأجهزة ذات 2–3 جيجابايت RAM عند تشغيل تطبيقات متعددة في وقت واحد. في الواقع، Warm Start مضمون فقط لمدة 10–20 دقيقة بعد التصغير على الأجهزة المتوسطة.

هل يتم الحفاظ على ViewModel أثناء Warm Start؟

نعم، إذا لم تُقتل العملية، يبقى ViewModel في الذاكرة ولا يتم استدعاء onCleared. هذه ميزة رئيسية لـ Warm Start: جميع البيانات المحملة عبر طلبات الشبكة، الذاكرة المؤقتة في ViewModel — كلها متاحة فورياً. إذا قُتلت العملية، يتم إنشاء ViewModel من جديد عبر ViewModelProvider.Factory أو @HiltViewModel، ويستعيد SavedStateHandle الحقول المحفوظة.

لماذا قد يكون Warm Start أبطأ من Cold Start؟

نظرياً، Warm Start دائماً أسرع من Cold Start، لكن عملياً هناك سيناريوهات يكون فيها الفرق ضئيلاً: إذا كان Application.onCreate خفيفاً (50 مللي ثانية) وActivity.onCreate ثقيلاً (800 مللي ثانية)، فإن Warm Start (800 مللي ثانية) يكاد يساوي Cold Start (850 مللي ثانية). في هذه الحالة، يجب تحسين ليس Application، بل Activity.onCreate — يصبح هو الاختناق لـ Warm Start.

كيف تؤثر API SplashScreen على Warm Start؟

تظهر API SplashScreen على Android 12+ شاشة بدء النظام (أيقونة على خلفية ملونة) فوراً عند الإطلاق — لكل من Cold وWarm Start. لـ Warm Start، تظهر الشاشة لمدة 100–300 مللي ثانية فقط، وبعدها يتم استبدالها بـ UI التطبيق. SplashScreen لا تسرع الإطلاق نفسه، لكنها تخفي وقت إنشاء Activity، محسنة الإدراك.

هل من الضروري تحسين Warm Start إذا كان Cold Start سريعاً بالفعل؟

نعم، لأن Warm Start يحدث 2–3 مرات أكثر من Cold Start. إذا استغرق Cold Start 1.2 ثانية وWarm Start 600 مللي ثانية، فإن 40% من عمليات الإطلاق (Warm) لا تزال تستغرق 0.6 ثانية، وهو أمر ملحوظ. تحسين Warm Start إلى 200–300 مللي ثانية يعطي المستخدم شعوراً بالعودة الفورية. على الأجهزة ذات 6+ جيجابايت RAM، يمكن أن يشكل Warm Start ما يصل إلى 80% من جميع عمليات الإطلاق، مما يجعل تحسينه أولوية.

الملخص

  • Warm Start — إطلاق تطبيق بعملية موجودة، دون Activity في الذاكرة، الوقت 200–800 مللي ثانية
  • الفرق الرئيسي عن Cold Start: Application.onCreate لا ينفذ، الفئات محملة
  • ثلاث مراحل لـ Warm Start: نافذة البدء ← إنشاء Activity ← الإطار الأول
  • يقاس عبر ADB بدون العلم -S أو Macrobenchmark مع StartupMode.WARM
  • التحسين: SavedStateHandle, AsyncLayoutInflater, cache-then-network, ConstraintLayout
  • ViewModel يُحفظ أثناء Warm Start (العملية حية) — البيانات متاحة فوراً
  • Warm Start يمثل 40–80% من جميع عمليات إطلاق التطبيقات

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

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

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

اقرأ أيضًا