يتوقّع المستخدمون أن يتم تحميل التطبيقات بسرعة وأن تكون متجاوبة. إذا كان وقت بدء تشغيل التطبيق طويلاً، لن يلبي هذا التوقّع وقد يؤدي إلى إحباط المستخدمين. ويمكن أن تؤدي هذه التجربة السيئة إلى تقييم المستخدم لتطبيقك بشكل سلبي على "متجر Play" أو حتى التوقف عن استخدامه نهائيًا.
تقدّم هذه الصفحة معلومات للمساعدة في تحسين وقت تشغيل تطبيقك، بما في ذلك نظرة عامة على العمليات الداخلية لعملية الإطلاق، وكيفية تحديد أداء بدء التشغيل، وبعض المشاكل الشائعة المتعلقة بوقت بدء التشغيل مع نصائح حول كيفية حلّها.
فهم حالات بدء تشغيل التطبيق المختلفة
يمكن أن يتم تشغيل التطبيق في إحدى الحالات الثلاث التالية: التشغيل على البارد أو إعادة تشغيل بطيء أو إعادة تشغيل سريع. تؤثر كل حالة في المدة التي يستغرقها ظهور تطبيقك للمستخدم. في التشغيل على البارد، يبدأ تطبيقك من البداية. في الحالات الأخرى، يحتاج النظام إلى نقل التطبيق الذي يتم تشغيله من الخلفية إلى المقدّمة.
ننصحك بالتحسين دائمًا استنادًا إلى افتراض تشغيل على البارد. ويمكن أن يؤدي ذلك إلى تحسين أداء عمليات التشغيل البارد والساخن أيضًا.
لتحسين تطبيقك من أجل بدء التشغيل السريع، من المفيد فهم ما يحدث على مستوى النظام والتطبيق وكيفية تفاعلهما في كل حالة من هذه الحالات.
من المقاييس المهمة لتحديد وقت بدء تشغيل التطبيق الوقت المستغرَق للعرض الأولي (TTID) والوقت المستغرَق للعرض الكامل (TTFD). يشير مقياس TTID إلى الوقت المستغرَق لعرض الإطار الأول، بينما يشير مقياس TTFD إلى الوقت المستغرَق ليصبح التطبيق تفاعليًا بالكامل. وكلاهما مهمان بنفس القدر، لأنّ TTID يتيح للمستخدم معرفة أنّ التطبيق بصدد التحميل، بينما يشير TTFD إلى الوقت الذي يصبح فيه التطبيق قابلاً للاستخدام فعليًا. إذا كان أيّ من هذين الوقتين طويلاً جدًا، قد يخرج المستخدم من تطبيقك قبل أن يتم تحميله بالكامل.
التشغيل على البارد
يشير التشغيل على البارد إلى بدء تشغيل تطبيق من البداية. وهذا يعني أنّه إلى أن يتم بدء هذا الإجراء، تنشئ عملية النظام عملية التطبيق. تحدث عمليات بدء التشغيل البارد في حالات مثل تشغيل تطبيقك للمرة الأولى منذ بدء تشغيل الجهاز أو منذ أن أوقف النظام التطبيق.
يمثّل هذا النوع من عمليات البدء أكبر تحدٍ لتقليل وقت بدء التشغيل، لأنّ النظام والتطبيق لديهما مهام أكثر من حالات التشغيل الأخرى.
في بداية التشغيل على البارد، ينفّذ النظام المهام الثلاث التالية:
- حمِّل التطبيق وافتحه.
- عرض نافذة بدء فارغة للتطبيق فور تشغيله
- أنشئ عملية التطبيق.
بعد أن ينشئ النظام عملية التطبيق، تصبح هذه العملية مسؤولة عن المراحل التالية:
- أنشئ عنصر التطبيق.
- إطلاق سلسلة التعليمات الرئيسية
- إنشاء النشاط الرئيسي
- تضخيم عدد المشاهدات
- تحديد تصميم الشاشة
- تنفيذ عملية الرسم الأولية
عندما تنتهي عملية التطبيق من الرسم الأول، تستبدل عملية النظام نافذة الخلفية المعروضة بالنشاط الرئيسي. في هذه المرحلة، يمكن للمستخدم بدء استخدام التطبيق.
يوضِّح الشكل 1 كيفية تبادل العمل بين عمليات النظام والتطبيق.
يمكن أن تنشأ مشاكل في الأداء أثناء إنشاء التطبيق وإنشاء النشاط.
إنشاء التطبيق
عند تشغيل تطبيقك، تظل نافذة البداية الفارغة معروضة على الشاشة إلى أن ينتهي النظام من رسم التطبيق للمرة الأولى. في هذه المرحلة، يبدّل نظام التشغيل نافذة بدء التشغيل بتطبيقك، ما يتيح للمستخدم التفاعل مع التطبيق.
إذا أعدت تعريف Application.onCreate() في تطبيقك، سيستدعي النظام الطريقة onCreate() في عنصر تطبيقك. بعد ذلك، ينشئ التطبيق سلسلة واجهة المستخدم، المعروفة أيضًا باسم سلسلة واجهة المستخدم، ويكلّفها بإنشاء نشاطك الرئيسي.
من هذه النقطة، تستمر العمليات على مستوى النظام والتطبيق وفقًا لمراحل دورة حياة التطبيق.
إنشاء نشاط
بعد أن تنشئ عملية التطبيق نشاطك، ينفّذ النشاط العمليات التالية:
- تهيئة القيم
- يتم استدعاء دوال الإنشاء.
- يستدعي طريقة رد الاتصال، مثل
Activity.onCreate()، المناسبة لحالة النشاط الحالية.
عادةً، يكون لطريقة onCreate() أكبر تأثير في وقت التحميل، لأنّها تنفّذ العمل بأعلى تكلفة إضافية، أي تحميل طرق العرض وتوسيعها وتهيئة العناصر اللازمة لتشغيل النشاط.
إعادة التشغيل البطيء
تشمل إعادة التشغيل البطيء مجموعة فرعية من العمليات التي تحدث أثناء التشغيل على البارد. في الوقت نفسه، يمثّل هذا النوع من عمليات إعادة التشغيل تكلفة إضافية أكبر من عملية إعادة التشغيل السريع. هناك العديد من الحالات المحتملة التي يمكن اعتبارها عمليات بدء باردة، مثل ما يلي:
يخرج المستخدم من تطبيقك ثم يعيد تشغيله. قد تستمر العملية في التنفيذ، ولكن يجب أن يعيد التطبيق إنشاء النشاط من البداية باستخدام طلب إلى
onCreate().يُخرج النظام تطبيقك من الذاكرة ثم يعيد المستخدم تشغيله. يجب إعادة تشغيل العملية والنشاط، ولكن يمكن أن تستفيد المهمة إلى حد ما من حزمة حالة المثيل المحفوظة التي تم تمريرها إلى
onCreate().
إعادة تشغيل سريع
تكون النفقات العامة لإعادة التشغيل السريع لتطبيقك أقل من النفقات العامة للتشغيل على البارد. في إعادة التشغيل السريع، يضع النظام نشاطك في المقدّمة. إذا كانت جميع أنشطة تطبيقك لا تزال مقيمة في الذاكرة، يمكن للتطبيق تجنُّب تكرار تهيئة العناصر وتضخيم التنسيق والعرض.
ومع ذلك، إذا تم الإزالة نهائيًّا لبعض الذاكرة استجابةً لأحداث تقليل استخدام الذاكرة، مثل
onTrimMemory()، يجب إعادة إنشاء هذه العناصر استجابةً
لحدث إعادة التشغيل السريع.
تعرض إعادة التشغيل السريع السلوك نفسه على الشاشة كما في سيناريو التشغيل على البارد. تعرض عملية النظام شاشة فارغة إلى أن ينتهي التطبيق من عرض النشاط.
كيفية تحديد وقت بدء تشغيل التطبيق في Perfetto
لتحديد وحلّ المشاكل المتعلّقة ببدء تشغيل التطبيق، من المفيد تحديد ما يتم تضمينه بالضبط في مرحلة بدء تشغيل التطبيق. لتحديد مرحلة بدء تشغيل التطبيق بأكملها في Perfetto، اتّبِع الخطوات التالية:
في Perfetto، ابحث عن الصف الذي يتضمّن مقياس "عمليات بدء تشغيل تطبيقات Android" المشتق. إذا لم يظهر لك، حاوِل تسجيل تتبُّع باستخدام تطبيق تتبُّع نشاط النظام على الجهاز فقط.
الشكل 3: شريحة المقياس المشتق "عمليات بدء تشغيل تطبيقات Android" في Perfetto انقر على الشريحة المرتبطة واضغط على m لاختيار الشريحة. تظهر أقواس حول الشريحة وتشير إلى المدة التي استغرقتها. تظهر المدة أيضًا في علامة التبويب الاختيار الحالي.
ثبِّت صف "تطبيقات Android الناشئة" من خلال النقر على رمز التثبيت الذي يظهر عند تمرير المؤشر فوق الصف.
انتقِل إلى الصف الذي يتضمّن التطبيق المعنيّ وانقر على الخلية الأولى لتوسيع الصف.
يمكنك تكبير حجم المحادثة الرئيسية، التي تظهر عادةً في أعلى الصفحة، من خلال الضغط على w (اضغط على s وa وd لتصغير الحجم والانتقال إلى اليمين واليسار على التوالي).
الشكل 4:شريحة المقياس المشتق "عمليات بدء تشغيل تطبيقات Android" بجانب الخيط الرئيسي للتطبيق تسهّل شريحة المقاييس المشتقة معرفة المحتوى المضمّن في بدء تشغيل التطبيق، ما يتيح لك مواصلة تصحيح الأخطاء بتفصيل أكبر.
استخدام المقاييس لفحص التطبيقات الناشئة وتحسينها
لتشخيص أداء وقت بدء التشغيل بشكل سليم، يمكنك تتبُّع المقاييس التي توضّح المدة التي يستغرقها تطبيقك لبدء التشغيل. يوفّر نظام التشغيل Android عدة طرق لتوضيح المشاكل التي يواجهها تطبيقك، كما يساعدك في تشخيصها. يمكن أن تنبّهك "مؤشرات Android الحيوية" إلى حدوث مشكلة، كما يمكن أن تساعدك أدوات التشخيص في تحديد المشكلة.
مزايا استخدام مقاييس الشركات الناشئة
يستخدم نظام التشغيل Android مقياسَي الوقت المُستغرَق للعرض الأولي (TTID) والوقت المُستغرَق للعرض الكامل (TTFD) لتحسين عمليات بدء تشغيل التطبيقات الباردة والدافئة. يستخدم وقت تشغيل Android (ART) البيانات من هذه المقاييس لإجراء عملية تجميع مسبق فعّالة للرمز البرمجي بهدف تحسين عمليات بدء التشغيل المستقبلية.
تؤدي عمليات بدء التشغيل الأسرع إلى تفاعل أكثر استدامة من المستخدمين مع تطبيقك، ما يقلّل من حالات الخروج المبكر أو إعادة تشغيل المثيل أو الانتقال إلى تطبيق آخر.
مؤشرات Android الحيوية
يمكن أن تساعد "مؤشرات Android الحيوية" في تحسين أداء تطبيقك من خلال تنبيهك على Play Console عندما تكون أوقات بدء تشغيل تطبيقك مفرطة.
تعتبر "مؤشرات Android الحيوية" أوقات بدء التشغيل التالية لتطبيقك مفرطة:
- يستغرق بدء التشغيل على البارد 5 ثوانٍ أو أكثر.
- يستغرق بدء التشغيل الدافئ ثانيتَين أو أكثر.
- يستغرق بدء التشغيل من الخلفية بعد فترة قصيرة مدة 1.5 ثانية أو أكثر.
تستخدِم "مؤشرات Android الحيوية" مقياس الوقت المُستغرَق للعرض الأولي (TTID). للحصول على معلومات حول طريقة جمع Google Play لبيانات "مؤشرات Android الحيوية"، يمكنك الاطّلاع على مستندات Play Console.
الوقت المستغرَق للعرض الأولي
يشير مصطلح "الوقت المستغرَق للعرض الأولي" (TTID) إلى الوقت الذي يستغرقه عرض الإطار الأول من واجهة مستخدم التطبيق. يقيس هذا المقياس الوقت الذي يستغرقه التطبيق لإنتاج إطاره الأول، بما في ذلك تهيئة العملية أثناء التشغيل على البارد، وإنشاء النشاط أثناء التشغيل على البارد أو إعادة التشغيل بطيء، وعرض الإطار الأول. يساعد الحفاظ على انخفاض وقت عرض التطبيق الأوّلي في تحسين تجربة المستخدم من خلال السماح له بمشاهدة تطبيقك يتم تشغيله بسرعة. يتم إعداد تقارير عن TTID تلقائيًا لكل تطبيق من خلال إطار عمل Android. عند تحسين وقت بدء تشغيل التطبيق، ننصحك بتنفيذ reportFullyDrawn للحصول على معلومات تصل إلى TTFD.
يتم قياس TTID كقيمة وقتية تمثّل إجمالي الوقت المنقضي الذي يتضمّن تسلسل الأحداث التالي:
- بدء العملية
- جارٍ تهيئة العناصر.
- إنشاء النشاط وتهيئته
- تضخيم التنسيق
- رسم التطبيق للمرة الأولى
استرداد TTID
للعثور على TTID، ابحث في أداة سطر الأوامر Logcat عن سطر ناتج يحتوي على قيمة تُسمى Displayed. هذه القيمة هي TTID وتبدو مشابهة للمثال التالي، حيث تكون قيمة TTID هي 3s534ms:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
للعثور على TTID في "استوديو Android"، عليك إيقاف الفلاتر في عرض Logcat من القائمة المنسدلة الخاصة بالفلاتر، ثم البحث عن Displayed الوقت، كما هو موضّح في الشكل 5.
يجب إيقاف الفلاتر لأنّ خادم النظام، وليس التطبيق نفسه، هو الذي يعرض هذا السجلّ.
Displayed
في Logcatلا يسجّل المقياس Displayed في ناتج Logcat بالضرورة مقدار الوقت اللازم إلى أن يتم تحميل جميع الموارد وعرضها. ويستثني الموارد التي لا تتم الإشارة إليها في ملف التصميم أو التي ينشئها التطبيق كجزء من عملية تهيئة الكائن. ويستبعد هذا التقرير هذه الموارد لأنّ تحميلها
هو عملية مضمّنة ولا تحظر العرض الأولي للتطبيق.
في بعض الأحيان، يحتوي السطر Displayed في ناتج Logcat على حقل إضافي
لإجمالي الوقت. على سبيل المثال:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
في هذه الحالة، يكون قياس الوقت المستغرَق في العرض الأول مخصّصًا للنشاط الذي يتم رسمه أولاً فقط. يبدأ قياس وقت total عند بدء عملية التطبيق، ويمكن أن يشمل نشاطًا آخر يتم بدء تشغيله أولاً ولكن لا يعرض أي شيء على الشاشة. لا يتم عرض قياس الوقت total إلا عند وجود فرق بين مدة بدء التشغيل لنشاط واحد وإجمالي مدة بدء التشغيل.
ننصحك باستخدام Logcat في "استوديو Android"، ولكن إذا كنت لا تستخدم "استوديو Android"، يمكنك أيضًا قياس TTID من خلال تشغيل تطبيقك باستخدام أمر adb shell الخاص بمدير الأنشطة. وفي ما يلي مثال لذلك:
adb [-d|-e|-s <serialNumber>] shell am start -S -W
com.example.app/.MainActivity
-c android.intent.category.LAUNCHER
-a android.intent.action.MAIN
يظهر المقياس Displayed في ناتج Logcat كما كان من قبل. تعرض نافذة الجهاز ما يلي:
Starting: Intent
Activity: com.example.app/.MainActivity
ThisTime: 2044
TotalTime: 2044
WaitTime: 2054
Complete
الوسيطتان -c و-a اختياريتان وتتيحان لك تحديد <category>
و<action>.
الوقت اللازم للعرض بملء الشاشة
يشير مصطلح "الوقت اللازم للعرض الكامل" (TTFD) إلى الوقت الذي يستغرقه التطبيق ليصبح تفاعليًا مع المستخدم. ويتم تسجيله على أنّه الوقت المستغرَق لعرض الإطار الأول لواجهة مستخدم التطبيق، بالإضافة إلى المحتوى الذي يتم تحميله بشكل غير متزامن بعد عرض الإطار الأولي. ويشير ذلك عادةً إلى المحتوى الأساسي الذي يتم تحميله من الشبكة أو القرص، كما يوضّح التطبيق. بعبارة أخرى، يشمل مقياس TTFD مقياس TTID بالإضافة إلى الوقت الذي يستغرقه التطبيق ليصبح قابلاً للاستخدام. يساعد الحفاظ على انخفاض وقت التفاعل الأول في تطبيقك على تحسين تجربة المستخدم من خلال السماح له بالتفاعل مع تطبيقك بسرعة.
يحدّد النظام معرّف TTID عندما تستدعي Choreographer طريقة onDraw() الخاصة بالنشاط، وعندما يعرف أنّه يستدعيها للمرة الأولى.
ومع ذلك، لا يعرف النظام متى يجب تحديد مقياس TTFD لأنّ كل تطبيق يتصرف بشكل مختلف. لتحديد وقت عرض أول إطار، يحتاج التطبيق إلى إرسال إشارة إلى النظام
عندما يصل إلى حالة العرض الكامل.
استرداد TTFD
للعثور على مقياس TTFD، أشِر إلى حالة الرسم الكامل من خلال استدعاء الطريقة
reportFullyDrawn() الخاصة بالعنصر ComponentActivity. تعرض الطريقة
reportFullyDrawn الوقت الذي يتم فيه رسم التطبيق بالكامل ويكون في حالة
قابلة للاستخدام. يشير TTFD إلى الوقت المنقضي منذ أن يتلقّى النظام نية تشغيل التطبيق إلى أن يتم استدعاء reportFullyDrawn(). إذا لم تستدعِ الدالة
reportFullyDrawn()، لن يتم تسجيل أي قيمة لسمة TTFD.
لقياس TTFD، استدعِ الدالة reportFullyDrawn() بعد رسم واجهة المستخدم والبيانات بالكامل. لا تستدعِ الدالة reportFullyDrawn() قبل أن يتم رسم نافذة النشاط الأول وعرضها لأول مرة كما يقيسها النظام، لأنّ النظام سيُبلغ عن الوقت الذي قاسه. بعبارة أخرى، إذا طلبت
reportFullyDrawn() قبل أن يرصد النظام معرّف TTID، سيُبلغ النظام عن كلّ من معرّف TTID ومعرّف TTFD بالقيمة نفسها، وهذه القيمة هي قيمة معرّف TTID.
عند استخدام reportFullyDrawn()، تعرض أداة Logcat نتيجة مشابهة للمثال التالي، حيث يبلغ وقت التفاعل الأول 1 ثانية و54 ملي ثانية:
system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms
يتضمّن ناتج Logcat أحيانًا total وقتًا، كما هو موضّح في الوقت المستغرَق في العرض الأوّلي.
إذا كانت أوقات العرض أبطأ من المطلوب، يمكنك محاولة تحديد المؤثِّرات السلبية في عملية بدء التشغيل.
يمكنك استخدام reportFullyDrawn() للإشارة إلى حالة الرسم الكامل في الحالات الأساسية التي تكون فيها على دراية بأنّه تم تحقيق حالة الرسم الكامل. ومع ذلك، في الحالات التي يجب فيها أن تكمل سلاسل الخلفية عملها قبل الوصول إلى حالة الرسم الكامل، عليك تأخير reportFullyDrawn() للحصول على قياس أكثر دقة لمقياس TTFD. لمعرفة كيفية تأخير reportFullyDrawn()، يُرجى الاطّلاع على القسم التالي.
تحسين دقة توقيت بدء التشغيل
إذا كان تطبيقك ينفّذ التحميل الكسول ولم يتضمّن العرض الأوّلي جميع الموارد، مثل عندما يجلب تطبيقك الصور من الشبكة، قد تحتاج إلى تأخير استدعاء reportFullyDrawn إلى ما بعد أن يصبح تطبيقك قابلاً للاستخدام حتى تتمكّن من تضمين تعبئة القائمة كجزء من توقيت قياس الأداء.
على سبيل المثال، إذا كانت واجهة المستخدم تحتوي على قائمة ديناميكية، مثل RecyclerView
أو قائمة كسولة، قد تتم تعبئة هذه القائمة من خلال مهمة تعمل في الخلفية وتكتمل بعد
رسم القائمة لأول مرة، وبالتالي بعد وضع علامة على واجهة المستخدم بأنّها مرسومة بالكامل.
في هذه الحالات، لا يتم تضمين بيانات مستخدمي القائمة في قياس الأداء.
لتضمين تعبئة القائمة كجزء من توقيت مقياس الأداء، احصل على
FullyDrawnReporter باستخدام getFullyDrawnReporter()، وأضِف أداة إعداد تقارير إليها في رمز تطبيقك. حرِّر أداة إعداد التقارير بعد أن تنتهي مهمة الخلفية من ملء القائمة.
لا تستدعي FullyDrawnReporter الطريقة reportFullyDrawn() إلا بعد إيقاف جميع أدوات تسجيل التقارير التي تمت إضافتها. من خلال إضافة أداة إعداد تقارير إلى أن تكتمل العملية التي تعمل في الخلفية، تتضمّن التوقيتات أيضًا مقدار الوقت الذي يستغرقه ملء القائمة في بيانات توقيت بدء التشغيل. لا يؤدي ذلك إلى تغيير سلوك التطبيق بالنسبة إلى المستخدم، ولكنّه يتيح لبيانات بدء التشغيل المتعلقة بالتوقيت أن تتضمّن الوقت المستغرَق لتعبئة القائمة. لا يتم استدعاء reportFullyDrawn() إلا بعد اكتمال جميع المهام، بغض النظر عن الترتيب.
يوضّح المثال التالي كيف يمكنك تنفيذ مهام متعدّدة في الخلفية بشكل متزامن، مع تسجيل كل مهمة لمسؤول إعداد تقارير خاص بها:
Kotlin
class MainActivity : ComponentActivity() {
sealed interface ActivityState {
data object LOADING : ActivityState
data object LOADED : ActivityState
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var activityState by remember {
mutableStateOf(ActivityState.LOADING as ActivityState)
}
fullyDrawnReporter.addOnReportDrawnListener {
activityState = ActivityState.LOADED
}
ReportFullyDrawnTheme {
when(activityState) {
is ActivityState.LOADING -> {
// Display the loading UI.
}
is ActivityState.LOADED -> {
// Display the full UI.
}
}
}
SideEffect {
fullyDrawnReporter.addReporter()
lifecycleScope.launch(Dispatchers.IO) {
// Perform the background operation.
fullyDrawnReporter.removeReporter()
}
fullyDrawnReporter.addReporter()
lifecycleScope.launch(Dispatchers.IO) {
// Perform the background operation.
fullyDrawnReporter.removeReporter()
}
}
}
}
}
Java
public class MainActivity extends ComponentActivity {
private FullyDrawnReporter fullyDrawnReporter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fullyDrawnReporter = getFullyDrawnReporter();
fullyDrawnReporter.addOnReportDrawnListener(() -> {
// Trigger the UI update.
return Unit.INSTANCE;
});
new Thread(new Runnable() {
@Override
public void run() {
fullyDrawnReporter.addReporter();
// Do the background work.
fullyDrawnReporter.removeReporter();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
fullyDrawnReporter.addReporter();
// Do the background work.
fullyDrawnReporter.removeReporter();
}
}).start();
}
}
إذا كان تطبيقك يستخدم Jetpack Compose، يمكنك استخدام واجهات برمجة التطبيقات التالية للإشارة إلى حالة الرسم الكامل:
-
ReportDrawn: يشير إلى أنّ العنصر القابل للإنشاء جاهز على الفور للتفاعل. -
ReportDrawnWhen: تأخذ قيمة منطقية، مثلlist.count > 0، لتحديد الوقت الذي يصبح فيه العنصر القابل للإنشاء جاهزًا للتفاعل. ReportDrawnAfter: تأخذ طريقة تعليق تشير، بعد اكتمالها، إلى أنّ الدالة المركّبة جاهزة للتفاعل.
تحديد المشاكل التي تؤدي إلى بطء الأداء
للبحث عن مواضع الاختناق، يمكنك استخدام "محلّل وحدة المعالجة المركزية" في "استوديو Android". لمزيد من المعلومات، يُرجى الاطّلاع على فحص نشاط وحدة المعالجة المركزية باستخدام أداة CPU Profiler.
يمكنك أيضًا الحصول على إحصاءات حول المشاكل المحتملة من خلال التتبُّع المضمّن
داخل طرق onCreate() الخاصة بتطبيقاتك وأنشطتك. لمعرفة المزيد عن التتبُّع المضمّن، راجِع مستندات وظائف Trace ونظرة عامة على تتبُّع النظام.
حلّ المشاكل الشائعة
يتناول هذا القسم العديد من المشاكل التي تؤثر غالبًا في أداء بدء تشغيل التطبيق. تتعلّق هذه المشاكل بشكل أساسي بتهيئة عناصر التطبيق والنشاط، بالإضافة إلى تحميل الشاشات.
عملية تهيئة التطبيق الثقيل
قد يتأثر أداء التشغيل سلبًا عندما يتجاوز الرمز البرمجي العنصر Application
وينفّذ عمليات مكثّفة أو منطقًا معقّدًا عند تهيئة هذا العنصر. قد يضيع تطبيقك الوقت أثناء بدء التشغيل إذا كانت الفئات الفرعية Application تنفّذ عمليات تهيئة لا يلزم إجراؤها بعد.
قد تكون بعض عمليات التهيئة غير ضرورية تمامًا، مثل تهيئة معلومات الحالة للنشاط الرئيسي عندما يتم تشغيل التطبيق استجابةً لغرض. باستخدام Intent، لا يستخدم التطبيق سوى مجموعة فرعية من بيانات الحالة التي تم تهيئتها سابقًا.
تشمل التحديات الأخرى أثناء تهيئة التطبيق أحداث جمع البيانات غير المرغوب فيها التي تكون مؤثرة أو عديدة، أو عمليات الإدخال والإخراج على القرص التي تحدث بشكل متزامن مع التهيئة، ما يؤدي إلى حظر عملية التهيئة بشكل أكبر. وتُعد عملية جمع البيانات غير الضرورية من الاعتبارات المهمة بشكل خاص في وقت تشغيل Dalvik، بينما ينفّذ وقت تشغيل Android (ART) عملية جمع البيانات غير الضرورية بشكل متزامن، ما يقلّل من تأثير هذه العملية.
تشخيص المشكلة
يمكنك استخدام تتبُّع الأسلوب أو التتبُّع المضمّن لمحاولة تشخيص المشكلة.
تتبُّع الإجراءات
يؤدي تشغيل أداة "محلّل أداء وحدة المعالجة المركزية" إلى الكشف عن أنّ الطريقة callApplicationOnCreate() تستدعي في النهاية الطريقة com.example.customApplication.onCreate. إذا أظهرت الأداة أنّ تنفيذ هذه الطرق يستغرق وقتًا طويلاً، يمكنك استكشاف المزيد لمعرفة العمل الذي يتم تنفيذه.
التتبُّع المضمّن
استخدِم التتبُّع المضمّن للتحقيق في الأسباب المحتملة، بما في ذلك ما يلي:
- وظيفة
onCreate()الأولية لتطبيقك - أي عناصر سينغلتون عامة يبدأ تطبيقك في تهيئتها
- أي عمليات إدخال/إخراج للقرص أو إلغاء تسلسل أو حلقات ضيقة قد تحدث أثناء الاختناق
حلول للمشكلة
سواء كانت المشكلة تكمن في عمليات الإعداد غير الضرورية أو في عمليات الإدخال/الإخراج من القرص، فإنّ الحلّ هو الإعداد عند الحاجة. بعبارة أخرى، لا تبدأ في إنشاء الكائنات إلا عند الحاجة إليها. بدلاً من إنشاء عناصر ثابتة عامة، انتقِل إلى نمط كائن فردي حيث يبدأ التطبيق في تهيئة العناصر فقط في المرة الأولى التي يحتاج فيها إليها.
ننصحك أيضًا باستخدام إطار عمل لإدخال التبعيات، مثل Hilt، الذي ينشئ العناصر والتبعيات عند إدخالها لأول مرة.
إذا كان تطبيقك يستخدم موفّري المحتوى لتهيئة مكوّنات التطبيق عند بدء التشغيل، ننصحك باستخدام مكتبة "بدء تشغيل التطبيق" بدلاً من ذلك.
إعداد النشاط الثقيل
يتطلّب إنشاء الأنشطة في كثير من الأحيان الكثير من العمل الذي يتضمّن تكاليف عامة مرتفعة. في كثير من الأحيان، تتوفّر فرص لتحسين هذا العمل من أجل تحقيق تحسينات في الأداء. تشمل المشاكل الشائعة ما يلي:
- تضخيم التنسيقات الكبيرة أو المعقّدة
- حظر رسم الشاشة على القرص أو إدخال/إخراج البيانات من الشبكة
- تحميل صور نقطية وفك ترميزها
- تحويل عناصر
VectorDrawableإلى صور نقطية - تهيئة الأنظمة الفرعية الأخرى للنشاط
تشخيص المشكلة
في هذه الحالة أيضًا، يمكن أن يكون تتبُّع الطريقة وتتبُّع التعليمات البرمجية المضمّنة مفيدًا.
تتبُّع الإجراءات
إذا أظهرت الأداة أنّ تنفيذ هذه الطرق يستغرق وقتًا طويلاً، يمكنك استكشاف المزيد لمعرفة العمل الذي يتم تنفيذه.
التتبُّع المضمّن
استخدِم التتبُّع المضمّن للتحقيق في الأسباب المحتملة، بما في ذلك ما يلي:
onCreate()الوظيفة الأولية لتطبيقك- أي عناصر فردية عامة تتم تهيئتها
- أي عمليات إدخال/إخراج للقرص أو إلغاء تسلسل أو حلقات ضيقة قد تحدث أثناء الاختناق
حلول للمشكلة
هناك العديد من المشاكل المحتملة التي تؤدي إلى بطء الأداء، ولكن إليك مشكلتين شائعتين مع الحلول المقترَحة:
- كلما كانت هيكلية طرق العرض أكبر، استغرق التطبيق وقتًا أطول لتضخيمها. في ما يلي خطوتان يمكنك اتّخاذهما لحلّ هذه المشكلة:
- يمكنك تسوية هيكلية طرق العرض من خلال تقليل التصميمات المكرّرة أو المتداخلة.
- لا تضِف أجزاءً من واجهة المستخدم لا تحتاج إلى أن تكون مرئية أثناء التشغيل.
بدلاً من ذلك، استخدِم عنصر
ViewStubكعنصر نائب للتسلسلات الهرمية الفرعية التي يمكن للتطبيق توسيعها في وقت أكثر ملاءمة.
- يمكن أن يؤدي تنفيذ جميع عمليات تهيئة الموارد في سلسلة التعليمات الرئيسية إلى إبطاء عملية بدء التشغيل أيضًا. يمكنك معالجة هذه المشكلة باتّباع الخطوات التالية:
- انقل جميع عمليات تهيئة الموارد حتى يتمكّن التطبيق من تنفيذها بشكل غير متزامن في سلسلة محادثات مختلفة.
- اسمح للتطبيق بتحميل وعرض طرق العرض، ثم عدِّل لاحقًا الخصائص المرئية التي تعتمد على الصور النقطية والموارد الأخرى.
شاشات البداية المخصّصة
قد تلاحظ إضافة وقت إضافي أثناء بدء التشغيل إذا سبق لك استخدام إحدى الطرق التالية لتنفيذ شاشة بداية مخصّصة في Android 11 (المستوى 30 لواجهة برمجة التطبيقات) أو إصدار أقدم:
- استخدام سمة المظهر
windowDisablePreviewلإيقاف الشاشة البيضاء الأولية التي يرسمها النظام أثناء التشغيل - استخدام
Activityمخصّص
اعتبارًا من Android 12، يجب الانتقال إلى واجهة برمجة التطبيقات SplashScreen.
تتيح واجهة برمجة التطبيقات هذه بدء التشغيل بشكل أسرع وتتيح لك تعديل شاشة البداية بالطرق التالية:
- ضبط مظهر لتغيير مظهر شاشة البداية
- التحكّم في مدة عرض شاشة البداية باستخدام
windowSplashScreenAnimationDuration - خصِّص الصورة المتحركة لشاشة البداية، وتعامل مع الصورة المتحركة لإغلاق شاشة البداية بشكل سليم.
بالإضافة إلى ذلك، تنقل مكتبة التوافق وظائف SplashScreen API إلى الإصدارات القديمة من نظام التشغيل لتوفير التوافق مع الإصدارات القديمة وإنشاء مظهر موحّد لشاشة البداية على جميع إصدارات Android.
راجِع دليل نقل بيانات شاشة البداية للاطّلاع على التفاصيل.
اقتراحات مخصصة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة.
- العرض البطيء
- مقاييس Capture Macrobenchmark
- إنشاء ملفات تعريف أساسية{:#creating-profile-rules}