قياس وقت التحميل وعرض الشاشة باستخدام Firebase Performance Monitoring

1. مقدمة

تاريخ آخر تعديل: 2021-03-11

لماذا نحتاج إلى قياس أداء "المشاهدات"؟

تُعدّ طرق العرض جزءًا أساسيًا من تطبيقات Android التي تؤثر بشكل مباشر في تجربة المستخدم. على سبيل المثال، يحتوي النشاط أو الجزء على واجهة المستخدم التي تتضمّن عناصر العرض التي يتفاعل معها المستخدمون. لا يمكن للمستخدمين الاطّلاع على المحتوى الكامل لواجهة المستخدم إلى أن يتم رسمه بالكامل على الشاشة. ستؤدي الشاشات البطيئة والمتوقفة إلى إعاقة تفاعل المستخدم مع تطبيقك بشكل مباشر وتقديم تجربة مستخدم سيئة.

ألا توفّر خدمة "مراقبة أداء Firebase" مقاييس الأداء هذه بشكلٍ جاهز؟

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

ما ستتعلمه

  • كيفية إضافة خدمة "مراقبة أداء Firebase" إلى تطبيق Android
  • فهم عملية تحميل نشاط أو جزء
  • كيفية إعداد تتبُّع لعمليات تنفيذ الرموز المخصّصة من أجل قياس وقت تحميل نشاط أو جزء
  • فهم عرض الشاشة وما هو الإطار البطيء/المجمّد
  • كيفية تسجيل تتبُّع الرموز المخصّصة باستخدام المقاييس لتسجيل الشاشات البطيئة أو المتوقّفة
  • كيفية عرض المقاييس التي تم جمعها في وحدة تحكّم Firebase

المتطلبات

  • الإصدار 4.0 من "استوديو Android" أو إصدار أحدث
  • جهاز Android أو محاكي Android
  • الإصدار 8 من Java أو إصدار أحدث

2. بدء الإعداد

الحصول على الرمز

نفِّذ الأوامر التالية لاستنساخ الرمز النموذجي لهذا الدرس العملي. سيؤدي ذلك إلى إنشاء مجلد باسم codelab-measure-android-view-performance على جهازك:

$ git clone https://github.com/FirebaseExtended/codelab-measure-android-view-performance.git
$ cd codelab-measure-android-view-performance

إذا لم يكن لديك git على جهازك، يمكنك أيضًا تنزيل الرمز مباشرةً من GitHub.

استورِد مشروع measure-view-performance-start إلى "استوديو Android". من المحتمل أن تظهر لك بعض أخطاء التجميع أو ربما تحذير بشأن ملف google-services.json مفقود. سنصحّح ذلك في القسم التالي من هذه الخطوة.

في هذا الدرس العملي، سنستخدم المكوّن الإضافي مساعد Firebase لتسجيل تطبيق Android في مشروع Firebase وإضافة ملفات الإعداد والمكوّنات الإضافية والتبعيات اللازمة في Firebase إلى مشروع Android، كل ذلك من داخل "استوديو Android".

ربط تطبيقك بمنصّة Firebase

  1. انتقِل إلى استوديو Android/مساعدة > البحث عن تحديثات للتأكّد من أنّك تستخدم أحدث إصدارات "استوديو Android" و"مساعِد Firebase".
  2. انقر على الأدوات > Firebase لفتح لوحة المساعد.
    e791bed0999db1e0.png
  3. اختَر مراقبة الأداء لإضافتها إلى تطبيقك، ثم انقر على البدء في استخدام "مراقبة الأداء".
  4. انقر على الزر لإنشاء مشروع جديد، ثم أدخِل اسم المشروع (على سبيل المثال، Measure Performance Codelab).
  5. انقر على متابعة.
  6. إذا طُلب منك ذلك، راجِع بنود Firebase واقبلها، ثم انقر على متابعة.
  7. (اختياري) فعِّل ميزة "المساعدة المستندة إلى الذكاء الاصطناعي" في وحدة تحكّم Firebase (المعروفة باسم "Gemini في Firebase").
  8. في هذا الدرس العملي، لا تحتاج إلى "إحصاءات Google"، لذا أوقِف خيار "إحصاءات Google".
  9. بعد ذلك، من المفترض أن يظهر لك مربّع حوار ربط تطبيق Firebase الجديد بمشروعك على "استوديو Android".
    42c498d28ead2b77.png
  10. في "استوديو Android"، ضِمن لوحة المساعد، من المفترض أن يظهر لك تأكيد على ربط تطبيقك بمنصة Firebase.
    dda8bdd9488167a0.png

إضافة Performance Monitoring إلى تطبيقك

في لوحة المساعد في "استوديو Android"، انقر على إضافة أداة "مراقبة الأداء" إلى تطبيقك.

من المفترض أن يظهر مربّع حوار قبول التغييرات، وبعد ذلك يجب أن يزامن Android Studio تطبيقك للتأكّد من إضافة جميع التبعيات اللازمة.

9b58145acc4be030.png

أخيرًا، من المفترض أن تظهر لك رسالة النجاح في لوحة المساعد في Android Studio بأنّه تم إعداد جميع التبعيات بشكلٍ صحيح.

aa0d46fc944e0c0b.png

كخطوة إضافية، فعِّل تسجيل بيانات تصحيح الأخطاء باتّباع التعليمات الواردة في الخطوة "(اختياري) تفعيل تسجيل بيانات تصحيح الأخطاء". تتوفّر التعليمات نفسها أيضًا في المستندات المتاحة للجميع.

3- تشغيل التطبيق

إذا تم دمج تطبيقك بنجاح مع حزمة تطوير البرامج (SDK) الخاصة بخدمة Performance Monitoring، من المفترض أن يتم تجميع المشروع الآن. في "استوديو Android"، انقر على تشغيل > تشغيل "التطبيق" لإنشاء التطبيق وتشغيله على جهاز Android أو المحاكي المتصل.

يحتوي التطبيق على زرّين ينقلانك إلى Activity وFragment متوافقَين، على النحو التالي:

410d8686b4f45c33.png

في الخطوات التالية من هذا الدرس العملي، ستتعرّف على كيفية قياس وقت التحميل وأداء عرض الشاشة في النشاط أو الجزء.

4. التعرّف على عملية تحميل نشاط أو جزء

في هذه الخطوة، سنتعرّف على ما يفعله النظام أثناء تحميل نشاط أو جزء.

فهم عملية تحميل نشاط

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

على مستوى عالٍ، عندما يستدعي تطبيقك startActivity(Intent)، ينفِّذ النظام تلقائيًا العمليات التالية. يستغرق كل إجراء وقتًا لإكماله، ما يزيد من المدة الزمنية بين إنشاء النشاط ووقت ظهور واجهة المستخدم الخاصة بالنشاط على شاشة المستخدم.

c20d14b151549937.png

فهم عملية تحميل جزء

على غرار النشاط، يتم تحديد وقت تحميل جزء على أنّه الوقت الذي يبدأ من لحظة ربط الجزء بنشاط المضيف إلى أن يتم رسم اللقطة الأولى لعرض الجزء بالكامل على الشاشة.

5- قياس وقت تحميل نشاط

يمكن أن تؤدي التأخيرات في اللقطة الأولى إلى تجربة سيئة للمستخدم، لذا من المهم معرفة مقدار تأخير التحميل الأولي الذي يواجهه المستخدمون. يمكنك إعداد تتبُّع رمز مخصّص لقياس وقت التحميل هذا:

  1. ابدأ عملية تتبُّع الرمز المخصّص (المسمّى TestActivity-LoadTime) في فئة النشاط بمجرد إنشاء عنصر النشاط.

TestActivity.java

public class TestActivity extends AppCompatActivity {   
    // TODO (1): Start trace recording as soon as the Activity object is created.
    private final Trace viewLoadTrace = FirebasePerformance.startTrace("TestActivity-LoadTime");

    // ...

}
  1. تجاوز onCreate()callback، والحصول على العرض الذي أضافته الطريقة setContentView().
@Override     
public void onCreate(Bundle savedInstanceState) {    
    super.onCreate(savedInstanceState);          

    // Current Activity's main View (as defined in the layout xml file) is inflated after this            
    setContentView(R.layout.activity_test);          

    // ...

    // TODO (2): Get the View added by Activity's setContentView() method.         
    View mainView = findViewById(android.R.id.content);     

    // ...
}
  1. لقد أدرجنا عملية تنفيذ FistDrawListener، والتي تتضمّن دالتَي ردّ: onDrawingStart() وonDrawingFinish() (راجِع القسم التالي أدناه لمزيد من التفاصيل حول FirstDrawListener والعوامل التي يمكن أن تؤثّر في أدائه). سجِّل FirstDrawListener في نهاية onCreate()callback الخاص بـ Activity. يجب إيقاف viewLoadTrace في onDrawingFinish()callback.

TestActivity.java

    // TODO (3): Register the callback to listen for first frame rendering (see
    //  "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when View drawing is
    //  finished.
    FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {              
        @Override             
        public void onDrawingStart() {       
          // In practice you can also record this event separately
        }

        @Override             
        public void onDrawingFinish() {
            // This is when the Activity UI is completely drawn on the screen
            viewLoadTrace.stop();             
        }         
    });
  1. أعِد تشغيل التطبيق، ثم فلتر logcat باستخدام مقياس تتبُّع التسجيل. انقر على الزر LOAD ACTIVITY، وابحث عن السجلات كما هو موضح أدناه:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 تهانينا! لقد نجحت في قياس وقت تحميل أحد الأنشطة وإرسال هذه البيانات إلى "مراقبة أداء Firebase". سنعرض المقياس المسجَّل في وحدة تحكّم Firebase لاحقًا في هذا الدرس البرمجي.

الغرض من FirstDrawListener

في القسم أعلاه مباشرةً، سجّلنا FirstDrawListener. الغرض من FirstDrawListener هو قياس وقت بدء رسم الإطار الأول ووقت انتهائه.

تنفّذ هذه الفئة ViewTreeObserver.OnDrawListener وتتجاوز دالة ردّ الاتصال onDraw() التي يتم استدعاؤها عندما تكون شجرة العرض على وشك الرسم. بعد ذلك، يغلّف النتيجة لتوفير دالتَي ردّ مفيدتَين onDrawingStart() وonDrawingFinish().

يمكنك العثور على الرمز الكامل لـ FirstDrawListener في رمز المصدر الخاص بهذا الدرس العملي.

6. قياس مدة تحميل Fragment

إنّ قياس وقت تحميل Fragment يشبه طريقة قياسه في Activity، ولكن مع بعض الاختلافات البسيطة. مرة أخرى، سنستخدم تتبُّع الرمز المخصّص:

  1. تجاوز وظيفة الاستدعاء onAttach() وبدء تسجيل fragmentLoadTrace. سنسمّي هذا التتبُّع Test-Fragment-LoadTime.

كما هو موضّح في خطوة سابقة، يمكن إنشاء عنصر Fragment في أي وقت، ولكنّه لا يصبح نشطًا إلا عند ربطه بنشاط المضيف.

TestFragment.java

public class TestFragment extends Fragment {

   // TODO (1): Declare the Trace variable.
   private Trace fragmentLoadTrace;

   @Override
   public void onAttach(@NonNull Context context) {
       super.onAttach(context);

       // TODO (2): Start trace recording as soon as the Fragment is attached to its host Activity.
       fragmentLoadTrace = FirebasePerformance.startTrace("TestFragment-LoadTime");
   }
  1. سجِّل FirstDrawListener في onViewCreated()callback. بعد ذلك، أوقِف التتبُّع في onDrawingFinish()، كما هو الحال في مثال "النشاط".

TestFragment.java

@Override
public void onViewCreated(@NonNull View mainView, Bundle savedInstanceState) {
   super.onViewCreated(mainView, savedInstanceState);

   // ...

   // TODO (3): Register the callback to listen for first frame rendering (see
   //  "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when view drawing is
   //  finished.
   FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {

       @Override
       public void onDrawingStart() {
           // In practice you can also record this event separately
       }

       @Override
       public void onDrawingFinish() {
           // This is when the Fragment UI is completely drawn on the screen
           fragmentLoadTrace.stop();
       }
   });
  1. أعِد تشغيل التطبيق، ثم فلتر logcat باستخدام مقياس تتبُّع التسجيل. انقر على الزر LOAD FRAGMENT، وابحث عن السجلات كما هو موضح أدناه:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 تهانينا! لقد نجحت في قياس وقت تحميل Fragment وإرسال هذه البيانات إلى خدمة "مراقبة أداء Firebase". سنعرض المقياس المسجَّل في وحدة تحكّم Firebase لاحقًا في هذا الدرس البرمجي.

7. فهم عرض الشاشة وما هو الإطار البطيء/المجمّد

عرض واجهة المستخدم هو عملية إنشاء لقطة من تطبيقك وعرضها على الشاشة. لضمان سلاسة تفاعل المستخدم مع تطبيقك، يجب أن يعرض تطبيقك اللقطات في أقل من 16 ملي ثانية لتحقيق 60 لقطة في الثانية ( لماذا 60 لقطة في الثانية؟). إذا كان تطبيقك يعاني من بطء عرض واجهة المستخدم، سيضطر النظام إلى تخطّي بعض اللقطات، وسيلاحظ المستخدم حدوث تشوّش في تطبيقك.

وبالمثل، اللقطات المجمدة هي لقطات واجهة المستخدم التي يستغرق عرضها أكثر من 700 ملي ثانية. يُعدّ هذا التأخير مشكلة لأنّ تطبيقك يبدو متوقفًا ولا يستجيب لإدخال المستخدم لمدة ثانية كاملة تقريبًا أثناء عرض اللقطة.

8. قياس اللقطات البطيئة أو المجمّدة في جزء

تسجّل خدمة "مراقبة أداء Firebase" تلقائيًا اللقطات البطيئة أو المجمدة لنشاط معيّن (ولكن فقط إذا كان النشاط يستخدم ميزة "تسريع الأجهزة"). ومع ذلك، لا تتوفّر هذه الميزة حاليًا لـ "اللقطات". يتم تعريف اللقطات البطيئة/المتوقفة لجزء من الشاشة على أنّها اللقطات البطيئة/المتوقفة للنشاط بأكمله بين عمليات معاودة الاتصال onFragmentAttached() وonFragmentDetached() في دورة حياة جزء الشاشة.

استنادًا إلى فئة AppStateMonitor (التي تشكّل جزءًا من حزمة تطوير البرامج (SDK) الخاصة بأداة "مراقبة الأداء" والمسؤولة عن تسجيل عمليات تتبُّع الشاشة في "النشاط")، نفّذنا فئة ScreenTrace (التي تشكّل جزءًا من مستودع الرموز المصدرية لهذا الدرس العملي). يمكن ربط فئة ScreenTrace بدالة معاودة الاتصال لدورة حياة FragmentManager الخاصة بالنشاط لتسجيل اللقطات البطيئة أو المجمدة. توفّر هذه الفئة واجهتَي برمجة تطبيقات متاحتَين للجميع:

  • recordScreenTrace(): بدء تسجيل تتبُّع الشاشة
  • sendScreenTrace(): توقِف تسجيل تتبُّع الشاشة وتُرفِق مقاييس مخصّصة بالسجلّ لإجمالي عدد اللقطات البطيئة والمجمّدة

من خلال إرفاق هذه المقاييس المخصّصة، يمكن التعامل مع عمليات تتبُّع الشاشة الخاصة بـ "اللقطات" بالطريقة نفسها التي يتم بها التعامل مع عمليات تتبُّع الشاشة الخاصة بـ "النشاط"، ويمكن عرضها مع عمليات تتبُّع عرض الشاشة الأخرى في لوحة بيانات الأداء في وحدة تحكّم Firebase.

في ما يلي كيفية تسجيل عمليات تتبُّع الشاشة للجزء:

  1. ابدأ فئة ScreenTrace في النشاط الذي يستضيف التجزئة.

MainActivity.java

// Declare the Fragment tag
private static final String FRAGMENT_TAG = TestFragment.class.getSimpleName();

// TODO (1): Declare the ScreenTrace variable.
private ScreenTrace screenTrace;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // TODO (2): Initialize the ScreenTrace variable.
    screenTrace = new ScreenTrace(this, FRAGMENT_TAG);

    // ...
}
  1. عند تحميل Fragment، سجِّل FragmentLifecycleCallbacks وألغِ onFragmentAttached() وonFragmentDetached(). لقد أجرينا هذا التغيير نيابةً عنك. عليك بدء تسجيل عمليات تتبُّع الشاشة في معاودة الاتصال onFragmentAttached() وإيقاف التسجيل في معاودة الاتصال onFragmentDetached().

MainActivity.java

private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
       new FragmentManager.FragmentLifecycleCallbacks() {

           @Override
           public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) {
               super.onFragmentAttached(fm, f, context);

               // TODO (3): Start recording the screen traces as soon as the Fragment is
               //  attached to its host Activity.
               if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
                   screenTrace.recordScreenTrace();
               }
           }

           @Override
           public void onFragmentDetached(@NonNull FragmentManager fm, @NonNull Fragment f) {
               super.onFragmentDetached(fm, f);

               // TODO (4): Stop recording the screen traces as soon as the Fragment is
               //  detached from its host Activity.
               if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
                   screenTrace.sendScreenTrace();
               }

               // Unregister Fragment lifecycle callbacks after the Fragment is detached
               fm.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks);
           }
       };
  1. أعِد تشغيل التطبيق، ثم انقر على الزر LOAD FRAGMENT. انتظِر بضع ثوانٍ، ثم انقر على back button في شريط التنقّل بأسفل الشاشة.

فلتر سجلّات Logcat باستخدام مقياس تتبُّع التسجيل، ثم ابحث عن سجلّات مشابهة لما يلي:

I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)

فلتر سجلّ logcat باستخدام FireperfViews، ثم ابحث عن سجلّات مشابهة لما يلي:

D/FireperfViews: sendScreenTrace MainActivity-TestFragment, name: _st_MainActivity-TestFragment, total_frames: XX, slow_frames: XX, frozen_frames: XX

🎉 تهانينا! لقد نجحت في قياس اللقطات البطيئة/المتوقفة لجزء من الشاشة وإرسال هذه البيانات إلى "مراقبة أداء Firebase". سنعرض المقاييس المسجّلة في وحدة تحكّم Firebase لاحقًا في هذا الدرس العملي.

9. الاطّلاع على المقاييس في "وحدة تحكّم Firebase"

  1. في logcat، انقر على عنوان URL لوحدة تحكّم Firebase للانتقال إلى صفحة التفاصيل الخاصة بالتتبُّع. ceb9d5ba51bb6e89.jpeg

بدلاً من ذلك، في وحدة تحكّم Firebase، اختَر المشروع الذي يتضمّن تطبيقك. في اللوحة اليمنى، ابحث عن قسم الإصدار والمراقبة، ثم انقر على الأداء.

  • في علامة التبويب الرئيسية لوحة البيانات، انتقِل للأسفل إلى جدول عمليات التتبُّع، ثم انقر على علامة التبويب عمليات التتبُّع المخصّصة. في هذا الجدول، ستظهر لك عمليات تتبُّع الرموز المخصّصة التي أضفناها سابقًا بالإضافة إلى بعض عمليات التتبُّع الجاهزة، مثل عملية تتبُّع _app_start.
  • ابحث عن تتبُّعَي الرموز المخصّصة، TestActivity-LoadTime وTestFragment-LoadTime. انقر على المدة لأي منهما للاطّلاع على مزيد من التفاصيل حول البيانات التي تم جمعها.

a0d8455c5269a590.png

  1. تعرض صفحة التفاصيل لتتبُّع الرمز المخصّص معلومات حول مدة التتبُّع (أي وقت التحميل الذي تم قياسه).

5e92a307b7410d8b.png

  1. يمكنك أيضًا عرض بيانات الأداء لتتبُّع الشاشة المخصّص.
  • ارجع إلى علامة التبويب الرئيسية لوحة البيانات، ثم مرِّر للأسفل إلى جدول عمليات التتبُّع، ثم انقر على علامة التبويب عرض الشاشة. في هذا الجدول، ستظهر لك عمليات تتبُّع الشاشة المخصّصة التي أضفناها سابقًا بالإضافة إلى أي عمليات تتبُّع شاشة جاهزة للاستخدام، مثل عملية تتبُّع MainActivity.
  • ابحث عن تتبُّع الشاشة المخصّص MainActivity-TestFragment. انقر على اسم التتبُّع لعرض البيانات المجمَّعة لعمليات العرض البطيئة والإطارات المجمدة.

ee7890c7e2c28740.png

10. تهانينا

تهانينا! لقد نجحت في قياس وقت التحميل وأداء عرض الشاشة لنشاط وجزء باستخدام "مراقبة أداء Firebase".

إنجازاتك

الخطوات التالية

توفّر خدمة "أداء Firebase" طرقًا إضافية لقياس أداء تطبيقك بخلاف التتبُّع المخصّص. ويقيس تلقائيًا وقت بدء تشغيل التطبيق، وبيانات أداء التطبيق في المقدّمة وفي الخلفية. حان الوقت للاطّلاع على هذه المقاييس في وحدة تحكّم Firebase.

بالإضافة إلى ذلك، توفّر خدمة "مراقبة أداء Firebase" ميزة التتبُّع التلقائي لطلبات شبكة HTTP/S. وبذلك، يمكنك بسهولة قياس طلبات الشبكة بدون كتابة سطر واحد من الرموز البرمجية. هل يمكنك محاولة إرسال بعض طلبات الشبكة من تطبيقك والعثور على المقاييس في وحدة تحكّم Firebase؟

مكافأة

بعد أن تعرّفت على كيفية قياس وقت التحميل وأداء عرض الشاشة في Activity/Fragment باستخدام عمليات تتبُّع الرموز المخصّصة، هل يمكنك استكشاف قاعدة الرموز البرمجية المفتوحة المصدر لمعرفة ما إذا كان بإمكانك تسجيل هذه المقاييس بدون أي إعدادات إضافية لأي Activity/Fragment يشكّل جزءًا من التطبيق؟ يمكنك إرسال طلب السحب إذا أردت ذلك :-)

11. ميزة "التعلّم الإضافي"

سيساعدك فهم ما يحدث أثناء تحميل نشاط على فهم خصائص أداء تطبيقك بشكل أفضل. في خطوة سابقة، وصفنا بشكل عام ما يحدث أثناء تحميل نشاط، ولكن يوضّح المخطّط التالي كل مرحلة بتفاصيل أكثر.

cd61c1495fad7961.png