Cold Start هو دورة التشغيل الكاملة لتطبيق Android تبدأ من حالة صفرية، عندما لا توجد عملية التطبيق في الذاكرة ولم يتم إنشاء Activity بعد. يقوم النظام بإنشاء عملية جديدة، وتحميل الفئات، وتهيئة Application، وإنشاء Activity، وتنفيذ الرسم الأول. وفقًا Google، 2024، يمكن أن يستغرق التشغيل البارد على الأجهزة متوسطة المدى من 1 إلى 5 ثوانٍ، وكل 100 مللي ثانية من التأخير تقلل احتمالية الاحتفاظ بالمستخدم بنسبة 3%.
النقاط الرئيسية
Cold Start (التشغيل البارد) هو سيناريو يتم فيه تشغيل تطبيق Android من الحالة الأولية: يقوم نظام التشغيل بإنشاء عملية جديدة (fork من Zygote)، وتخصيص الذاكرة، وتحميل كود DEX في ART، وتهيئة الفئات، وإنشاء مثيل Application، ثم أول Activity. قبل تشغيل التطبيق، لا توجد بيانات عنه في ذاكرة الجهاز، باستثناء صور الفئات المخزنة مؤقتًا إذا تم استخدام Background Dexopt.
يحدث التشغيل البارد في ثلاث حالات: عند التشغيل الأول بعد تثبيت التطبيق، عند التشغيل بعد إعادة تشغيل الجهاز، وعند التشغيل بعد أن قام النظام بإزالة العملية بسبب نقص الذاكرة. على الأجهزة ذات 2–4 غيغابايت من ذاكرة الوصول العشوائي، يقوم النظام بإزالة عمليات الخلفية بقوة، لذلك يمكن أن يحدث Cold Start في كل مرة يعود فيها المستخدم إلى التطبيق بعد عدة ساعات من عدم النشاط. في Android 12+، يمكن للنظام الاحتفاظ بعملية مجمدة (freeze / cached)، ولكن مع توفير الذاكرة النشط (OOM-killer)، سيتم إنهاء العملية.
وفقًا لـ Google (تقرير Find My Device، 2023)، يغلق 65% من المستخدمين التطبيق إذا لم يتم فتحه خلال 3 ثوانٍ. بالنسبة لوسائل التواصل الاجتماعي والمراسلة، حيث يعود المستخدمون عشرات المرات في اليوم، يؤثر Cold Start مباشرة على الاحتفاظ. في Google Play Console، مقياس Cold Start جزء من قسم Android Vitals ويُعرض كأحد مؤشرات ANR والأداء. التطبيق الذي يتجاوز حد Cold Start “السيئ” (أكثر من 5 ثوانٍ على 25% من الأجهزة) يتلقى تحذيرًا في وحدة التحكم وقد يتم تخفيضه في نتائج البحث.
يميز Android بين ثلاثة أنواع من تشغيل التطبيق، لكل منها مدة مختلفة، وتأثير على تجربة المستخدم، وأساليب تحسين. فهم الفرق ضروري لاختيار استراتيجية التنميط الصحيحة.
| نوع التشغيل | حالة العملية | Application.onCreate | الوقت النموذجي |
|---|---|---|---|
| Cold | لا توجد عملية | يتم التنفيذ | 1–5 ثوانٍ |
| Warm | العملية موجودة، لا Activity | لا يتم التنفيذ | 200–600 مللي ثانية |
| Hot | العملية + Activity في الذاكرة | لا يتم التنفيذ | < 200 مللي ثانية |
يحدث Warm Start عندما تكون عملية التطبيق موجودة بالفعل في الخلفية، ولكن تم تدمير Activity (على سبيل المثال، عاد المستخدم بعد توقف طويل وحرر النظام ذاكرة Activity). Hot Start — عندما يقوم المستخدم بتصغير التطبيق وفتحه مرة أخرى على الفور: Activity متوقفة ويستغرق الاسترداد الحد الأدنى من الوقت. بالنسبة للمستخدم، Cold Start هو النوع الأكثر وضوحًا، وتحسينه يعطي أكبر تحسن في تجربة المستخدم.
يمكن أن يصبح Cold Start Warm Start بعد تشغيل التطبيق مرة واحدة على الأقل — يخزن ART صور الفئات المترجمة في ذاكرة التخزين المؤقت (Image in Boot Profile) ويصبح تحميل DEX اللاحق أسرع. لذلك، عادة ما يكون التشغيل الثاني بعد أول Cold Start أسرع بنسبة 20–40%. إذا كان التطبيق يستخدم Baseline Profiles، يتم تحميل الملفات الشخصية في التشغيل الأول ويمكن أن يكون التشغيل الثاني أسرع: Google Play، الذي نشر Baseline Profiles، سرّع Cold Start بنسبة 30% على الأجهزة التي تعمل بنظام Android 12+.
يتكون Cold Start من مراحل محددة بدقة، يمكن قياس وتحسين كل منها بشكل مستقل. تساعد معرفة المراحل في تحديد المرحلة التي يفقد فيها التطبيق الوقت. يحدد Google أربع مراحل رئيسية: إنشاء العملية، تهيئة Application، إنشاء Activity، والإطار الأول.
يقوم نظام Android (ActivityManagerService) بإنشاء عملية جديدة عن طريق fork من عملية Zygote. Zygote هي عملية محملة مسبقًا بفئات Android المشتركة. يستغرق fork 30–80 مللي ثانية — هذا الوقت خارج سيطرة التطبيق. بعد fork، يبدأ ActivityThread — مثيل الحلقة الرئيسية للتطبيق. في هذه المرحلة، يحدث أيضًا تحميل الفئات من خلال ClassLoader، ويبدأ ART في تفسير أول bytecode. إذا كان التطبيق يستخدم العديد من المهيئات الثابتة، فقد تطول هذه المرحلة.
مباشرة بعد بدء ActivityThread، يتم استدعاء Application.onCreate. هنا يرتكب المطورون الخطأ في أغلب الأحيان بتهيئة كل شيء دفعة واحدة: Crashlytics، Firebase، عملاء الشبكة، قواعد البيانات، مكونات Dagger، حاويات DI. كل تهيئة من هذه هي وقت محظور على الخيط الرئيسي. إذا استغرق Application.onCreate 500 مللي ثانية، يرى المستخدم شاشة بيضاء (أو سوداء) لمدة نصف ثانية. المدة المثلى لهذه المرحلة هي أقل من 200 مللي ثانية على جهاز متوسط المدى.
بعد تهيئة Application، يتم إنشاء مثيل Activity (MainActivity أو Launcher Activity). يتم استدعاء Activity.onCreate، حيث يحدث setContentView، وتهيئة الأجزاء (fragments)، وإعداد ViewModel، والاشتراك في LiveData/Flow. إذا قام onCreate بتحميل البيانات (SharedPreferences، SQLite، API) بشكل متزامن على الخيط الرئيسي، تتمدد المرحلة. الهدف هو إبقاء onCreate في حدود 200–400 مللي ثانية على جهاز متوسط المدى.
بعد اكتمال onCreate، يبدأ العرض الأول: القياس، التخطيط، الرسم. تسمى هذه اللحظة TTFD (Time To First Draw). إذا كان التطبيق يستخدم شاشة البداية (عبر SplashScreen API على Android 12+ أو عبر theme)، فقد يحدث العرض بشكل أسرع، لكن المستخدم سيظل ينتظر حتى يختفي splash. TTFD المثالي لـ Cold Start هو أقل من 1.5 ثانية.
يتطلب قياس Cold Start أدوات خاصة، لأن التسجيل العادي (Log.d) يبدأ العمل فقط بعد إنشاء Application، ويظل توقيت fork وتحميل الفئات غير متاح. يوصي Google بثلاث طرق: أوامر ADB، Android Vitals، ووحدات ماكرو مخصصة للأداء.
أبسط وأكثر الطرق قابلية للتكرار هو أمر adb shell am start -S -W. العلم -S يوقف التطبيق قسرًا قبل التشغيل (يضمن Cold Start). يخرج الأمر ثلاثة مقاييس: ThisTime (وقت بدء Activity)، TotalTime (الوقت الإجمالي بما في ذلك تشغيل العملية)، وWaitTime (الوقت بما في ذلك جميع تأخيرات Activity Manager). للحصول على قياسات نظيفة، قم بإجراء 5–7 قراءات واستخدم الوسيط — القراءات الفردية عرضة للضوضاء (اختناق وحدة المعالجة المركزية، الحمل في الخلفية).
# Cold Start إجباري مع القياس
$ adb shell am start -S -W \
com.example.app/.MainActivity
# مخرجات الأمر:
# ThisTime: 1842 ms
# TotalTime: 1842 ms
# WaitTime: 1855 ms
تجمع Google Play Console مقاييس مجهولة من جميع الأجهزة المثبت عليها التطبيق. في قسم Android Vitals ← Launch time، يُعرض التوزيع الوسيط لـ Cold Start حسب طراز الجهاز وإصدار Android. هذه هي الطريقة الوحيدة لرؤية المقاييس الحقيقية على أجهزة المستخدمين، وليس فقط على أجهزة الاختبار. إذا تجاوز Cold Start 5 ثوانٍ على Redmi 9A (2 غيغابايت RAM) و1.2 ثانية على Pixel 8، فالمشكلة في حجم الذاكرة وعدد الفئات. يعرض Google أيضًا التأخير المدرك من قبل المستخدم بناءً على النسبة المئوية 25.
تتيح مكتبة Google Jetpack Macrobenchmark (androidx.benchmark) كتابة اختبارات آلية لتشغيل التطبيق. يقوم الاختبار بتثبيت التطبيق، وتشغيله من حالة باردة، وقياس الوقت حتى الإطار الأول. Macrobenchmark يقوم تلقائيًا بـ 20 تشغيلًا، ويتجاهل القيم المتطرفة، ويعرض نسبًا مئوية مستقرة. بالنسبة لـ CI/CD، يمكن مقارنة baseline والتشغيل الحالي — إذا زاد الوقت، يمكن أن يفشل خط أنابيب CI.
تحسين Cold Start هو عمل منهجي يؤثر على عدة مستويات من التطبيق: الكود، الموارد، تكوين البناء، وهندسة التهيئة. يوصي Google بالبدء بالأكثر تكلفة — Application.onCreate — والانتقال إلى التفاصيل الأصغر.
انقل جميع التهيئات غير المطلوبة عند بدء التشغيل من Application.onCreate إلى أول نقطة استخدام. Firebase، Crashlytics، SDK التحليلات، إشعارات الدفع، مكونات DI — يمكن تهيئة كل شيء بعد عرض الشاشة الأولى. استخدم Lazy (by lazy) في Kotlin أو تهيئة ContentProvider مع استدعاء صريح initialize(context). وفقًا لـ Google (Android Performance، 2023)، تقلل التهيئة البطيئة Cold Start بنسبة 40–60% للتطبيقات التي تستخدم 5+ SDK.
Baseline Profiles هي ترجمة AOT للفئات والطرق الحرجة المستخدمة عند بدء تشغيل التطبيق. بدون Baseline Profiles، يفسر ART كود DEX أو يجمعه عبر JIT، مما يستغرق وقتًا. مع الملفات الشخصية، يقوم ART بتجميع الطرق المحددة إلى كود أصلي (AOT) أثناء تثبيت التطبيق. تؤكد Google أن Baseline Profiles تسرع Cold Start بنسبة 15–40% على Android 9+ وما يصل إلى 60% مع تحسينات ART في Android 12+. لإنشاء الملفات الشخصية، استخدم المكون الإضافي androidx.benchmark:benchmark-baseline-profile-gradle-plugin.
تتيح مكتبة androidx.startup ترتيب تهيئة المكونات وتنفيذها في ContentProvider واحد. بدلاً من ContentProviders متعددة من مكتبات مختلفة (كل منها يضيف 1–2 مللي ثانية إلى التشغيل البارد)، يقوم App Startup بدمجها في رسم بياني للتبعيات ويهيئ حسب الحاجة فقط. عند بدء التشغيل، يتم تنفيذ المكونات المميزة بـ @Initializer المطلوبة للشاشة الأولى فقط. بالنسبة للباقي، يتم تعيين العلم needEarlyInit = false — تبدأ بعد العرض الأول.
// App Startup Initializer — التهيئة بعد بدء التشغيل
class AnalyticsInitializer : Initializer<Unit> {
override fun create(context: Context) {
Analytics.init(context)
}
override fun dependencies() = listOf<Class<out Initializer<*>>>()
}
// في AndroidManifest.xml ضع علامة اختياري
// <meta-data android:name="AnalyticsInitializer"
// android:value="false" />
يؤثر حجم ملف DEX مباشرة على وقت تحميل ART. استخدم R8/ProGuard للتعمية وإزالة الكود الميت (MinifyEnabled = true). قم بتمكين android:extractNativeLibs="false" في البيان (manifest) حتى لا يقوم APK بفك ضغط ملفات .so عند التثبيت. للمشاريع التي تحتوي على أكثر من 10 تتبع مرجعي، أضف startup-priority فقط للشاشة الأولى. كل طريقة إضافية في DEX تضيف 0.5–2 مللي ثانية للتحميل، وللتطبيقات التي تحتوي على أكثر من 50k طريقة (multidex مع primary dex) — حتى 300 مللي ثانية.
Android Vitals في Google Play Console (قسم Launch time) يجمع البيانات من جميع الأجهزة المثبت عليها التطبيق، بشرط موافقة المستخدم على التشخيص المجهول. تنقسم المقاييس إلى ثلاث فئات: “جيد”، “معتدل”، “سيئ”، حسب وقت Cold Start.
يحدد Google Cold Start “سيئ” على أنه وقت يتجاوز 5 ثوانٍ على أي جهاز. لكن عمليًا، للأجهزة الرائدة (Snapdragon 8 Gen)، الوقت الجيد أقل من 1.5 ثانية، للمتوسطة — أقل من 2.5 ثانية، للميزانية — أقل من 4 ثوانٍ. يعرض Android Vitals الوسيط لكل طراز جهاز، مما يسمح بفهم الأجهزة التي يعمل عليها التطبيق ببطء. إذا كان Cold Start سيئًا على أجهزة Samsung A-series أو Xiaomi Redmi، فالسبب غالبًا هو ذاكرة الفلاش البطيئة وقلة ذاكرة الوصول العشوائي (التسريع عبر Baseline Profiles يعطي أكبر تأثير على هذه الأجهزة تحديدًا).
بالإضافة إلى العرض في وحدة التحكم، يؤثر مقياس Cold Start على تقييم جودة التطبيق في بحث Google Play. التطبيقات ذات النسبة العالية من عمليات التشغيل “السيئة” تحصل على علامة “تحذير الأداء” على صفحة التثبيت، مما يقلل التحويل. وفقًا لـ Google (Android Performance Playbook، 2024)، التطبيقات التي حلت مشاكل Cold Start زادت من تحويل التثبيت بمتوسط 5% وحسّنت الاحتفاظ (D1) بنسبة 3–7%.
لمراقبة أكثر تفصيلاً، استخدم Firebase Performance Monitoring. يتتبع Cold Start على مستوى الجلسة، مقسمًا حسب إصدار التطبيق وإصدار Android. على عكس Android Vitals، يظهر Firebase مخطط تتبع للوقت المستغرق حسب المرحلة. على سبيل المثال، يمكنك رؤية أنه في الإصدار 3.2.0، استغرق Application.onCreate 800 مللي ثانية (بسبب مكتبة إشعارات دفع جديدة)، بينما في الإصدار 3.2.1 — 200 مللي ثانية (بعد الإصلاح).
فيما يلي مثالان عمليان يسرعان Cold Start مباشرة: نقل تهيئة SDK بعد بدء التشغيل واستخدام SplashScreen API.
الخطأ النموذجي هو تهيئة جميع SDK في Application.onCreate. يوضح أدناه كيفية نقل التهيئة غير الحرجة إلى كوروتين يتم تشغيله بعد رسم الإطار الأول. مهم: Firebase وCrashlytics وSDK الإبلاغ عن الأعطال يجب تهيئتها عند بدء التشغيل — لا يمكن تأجيلها لأنها تلتقط الأعطال أثناء تهيئة المكونات الأخرى. للباقي، استخدم lifecycleScope في أول Activity.
// ❌ سيئ — كل التهيئة في Application.onCreate
class App : Application() {
override fun onCreate() {
super.onCreate()
Firebase.init(this) // حرج
Analytics.init(this) // يمكن لاحقًا
Database.init(this) // يمكن لاحقًا
ImageLoader.init(this) // يمكن لاحقًا
}
}
// ✅ جيد — Firebase عند البداية، الباقي بعد التضخيم
class App : Application() {
override fun onCreate() {
super.onCreate()
Firebase.init(this)
}
}
// في MainActivity بعد الإطار الأول:
lifecycleScope.launchWhenResumed {
initializeNonCriticalSdks()
}
على Android 12+، استخدم SplashScreen API الرسمي الذي يعرض splash النظام (أيقونة التطبيق على خلفية داكنة/فاتحة) فور بدء العملية. هذا يخفي وقت التهيئة عن المستخدم — يرى splash بدلاً من شاشة بيضاء. للأجهزة القديمة، استخدم theme-based splash (Theme.SplashScreen في الأنماط). مهم: يجب ألا يستمر splash أكثر من 300 مللي ثانية — إذا لم يكن التطبيق جاهزًا بحلول ذلك الوقت، ارسم هيكلًا عظميًا “ثابتًا” (shimmer) واعرض تقدم التحميل.
// SplashScreen API — Android 12+
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition {
isReady.value == false
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
// Splash قائم على السمة (Android 5-11)
// في themes.xml:
// <style name="Theme.App.Starting" parent="Theme.SplashScreen">
// <item name="windowSplashScreenBackground">@color/white</item>
// <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
// </style>
الأسئلة الشائعة
يستخدم المحاكي جهاز كمبيوتر مضيفًا قويًا ويحاكي المعالج بتسريع الأجهزة (HAXM / WHPX). الأجهزة الفعلية، خاصة ذات الميزانية المحدودة (ذاكرة eMMC بدلاً من UFS)، لديها إدخال/إخراج أبطأ بكثير. يُنصح بقياس Cold Start على جهاز فعلي متوسط المدى للحصول على بيانات واقعية.
وفقًا لتوصيات Google، يجب أن يكون متوسط Cold Start أقل من ثانيتين على الأجهزة متوسطة المدى. للأجهزة الرائدة — أقل من 1.5 ثانية. للأجهزة ذات الميزانية المحدودة (2 غيغابايت RAM) يُسمح حتى 4 ثوانٍ، لكن يُوصى بالتحسين إلى 3 ثوانٍ. القيم التي تزيد عن 5 ثوانٍ تعتبر حرجة.
بشكل غير مباشر — نعم. إذا كان البيان (manifest) يحتوي على أيقونة متجهة (AdaptiveIcon)، فيجب ترجمتها إلى drawable عند بدء التشغيل. إذا كانت الأيقونة تحتوي على مسارات معقدة (pathData بعشرات المنحنيات)، يستغرق التجميع 10–30 مللي ثانية. استخدم VectorDrawable مع pathData محسّن (عبر SVGOMG أو Android Studio Vector Asset).
نعم، إذا تم تحميل Feature Module (Android App Bundle) عند الطلب، يُقاس Cold Start من لحظة النقر على الميزة حتى الإطار الأول. يتم تحميل الوحدات عند الطلب عبر Play Core Library، ويضيف تثبيتها 500–3000 مللي ثانية إلى وقت بدء التشغيل. قم بتحسين كود الميزة بنفس طريقة الوحدة الرئيسية.
التطبيقات التي تحتوي على أكثر من 64k طريقة تتطلب Multidex. هذا يعني أن ART يجب أن يقوم بتحميل ملفات DEX متعددة، مما يزيد وقت Cold Start بمقدار 200–800 مللي ثانية اعتمادًا على عدد ملفات classes.dex. استخدم minSdk 21+ (ART مع دعم multidex الأصلي) وقم بتكوين primary dex عبر --main-dex-list للحفاظ على الفئات الحرجة في ملف DEX الأول.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا