تحديد طلبات العمل

تناول دليل البدء كيفية إنشاء WorkRequest بسيط وإضافته إلى "قائمة المحتوى التالي".

في هذا الدليل، ستتعرّف على كيفية تحديد عناصر WorkRequest وتخصيصها للتعامل مع حالات الاستخدام الشائعة، مثل كيفية:

  • جدولة المهام لمرة واحدة ومهام متكررة
  • ضبط قيود العمل، مثل طلب شبكة Wi-Fi أو الشحن
  • ضمان الحد الأدنى من التأخير في تنفيذ العمل
  • ضبط استراتيجيات إعادة المحاولة والتراجع
  • تمرير بيانات الإدخال إلى العمل
  • تجميع الأعمال ذات الصلة معًا باستخدام العلامات

نظرة عامة

يتم تحديد العمل في WorkManager من خلال WorkRequest. لتحديد موعد لأي عمل باستخدام WorkManager، عليك أولاً إنشاء عنصر WorkRequest ثم إضافته إلى "قائمة الانتظار".

Kotlin

val myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest)

Java

WorkRequest myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest);

يحتوي عنصر WorkRequest على جميع المعلومات التي يحتاجها WorkManager لتحديد موعد تنفيذ عملك وتنفيذه. ويشمل ذلك القيود التي يجب استيفاؤها لتشغيل عملك، ومعلومات الجدولة، مثل التأخيرات أو الفواصل الزمنية المتكررة، وإعدادات المحاولة مجددًا، وقد يتضمّن بيانات الإدخال إذا كان عملك يعتمد عليها.

WorkRequest نفسها هي فئة أساسية مجردة. هناك نوعان من عمليات التنفيذ المشتقة من هذه الفئة يمكنك استخدامهما لإنشاء الطلب، وهو OneTimeWorkRequest وPeriodicWorkRequest. كما يشير الاسمان، يكون الخيار OneTimeWorkRequest مفيدًا لجدولة المهام غير المتكرّرة، في حين يكون الخيار PeriodicWorkRequest أكثر ملاءمةً لجدولة المهام المتكرّرة على فترات زمنية معيّنة.

جدولة عمل لمرة واحدة

بالنسبة إلى الأعمال البسيطة التي لا تتطلّب أيّ إعدادات إضافية، استخدِم الطريقة static from:

Kotlin

val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)

Java

WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);

بالنسبة إلى الأعمال الأكثر تعقيدًا، يمكنك استخدام أداة إنشاء:

Kotlin

val uploadWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       // Additional configuration
       .build()

Java

WorkRequest uploadWorkRequest =
   new OneTimeWorkRequest.Builder(MyWork.class)
       // Additional configuration
       .build();

جدولة العمل المُعجَّل

طرحت الإصدار 2.7.0 من WorkManager مفهوم "المهام المُعجَّلة". يتيح ذلك لـ WorkManager تنفيذ المهام المهمة مع منح النظام مزيدًا من التحكّم في الوصول إلى الموارد.

تتميز المهام المُعجَّلة بالخصائص التالية:

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

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

الحصص

يجب أن يخصّص النظام وقت التنفيذ لمهمة سريعة قبل أن تتمكّن من التشغيل. وقت التنفيذ ليس غير محدود. بدلاً من ذلك، يحصل كل تطبيق على حصة من وقت التنفيذ. عندما يستخدم تطبيقك وقت التنفيذ ويصل إلى المساحة المخصّصة له، لن تتمكّن من تنفيذ العمل المُسرَّع إلى أن تتم إعادة تحميل المساحة. يتيح ذلك لنظام التشغيل Android موازنة الموارد بين التطبيقات بفعالية أكبر.

يعتمد مقدار وقت التنفيذ المتاح للتطبيق على الحزمة الاحتياطية وأهمية العملية.

يمكنك تحديد ما يحدث عندما لا تسمح حصة التنفيذ بتنفيذ مهمة مُسرَّعة على الفور. اطّلِع على المقتطفات أدناه لمعرفة التفاصيل.

تنفيذ المهام المُعجَّلة

بدءًا من الإصدار 2.7 من WorkManager، يمكن لتطبيقك استدعاء setExpedited() للإشارة إلى أنّه ينبغي تنفيذ WorkRequest في أسرع وقت ممكن باستخدام مهمة مُسرَّعة. يقدّم مقتطف الرمز التالي مثالاً على كيفية استخدام setExpedited():

Kotlin

val request = OneTimeWorkRequestBuilder<SyncWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

WorkManager.getInstance(context)
    .enqueue(request)

Java

OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>()
    .setInputData(inputData)
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build();

في هذا المثال، نبدأ في تهيئة مثيل من OneTimeWorkRequest ونُجري عليه الإجراء setExpedited(). ويصبح هذا الطلب بعد ذلك من النوع المُعجل. إذا كانت الحصة تسمح بذلك، سيبدأ تشغيله على الفور في الخلفية. إذا تم استخدام الحصة، تشير المَعلمة OutOfQuotaPolicy إلى أنّه يجب تنفيذ الطلب كالمعتاد بدون تسريع.

التوافق مع الإصدارات السابقة والخدمات التي تعمل في المقدّمة

للحفاظ على التوافق مع الأنظمة القديمة للمهام المُسرَّعة، قد يشغِّل WorkManager خدمة تعمل في المقدّمة على إصدارات النظام الأساسي الأقدم من Android 12. يمكن للخدمات التي تعمل في المقدّمة عرض إشعار للمستخدم.

تُمكِّن الطريقتان getForegroundInfoAsync() وgetForegroundInfo() في Worker تطبيق WorkManager من عرض إشعار عند استدعاء setExpedited() قبل Android 12.

يجب أن تنفِّذ أي ListenableWorker طريقة getForegroundInfo إذا أردت طلب تنفيذ المهمة كعملية مُسرَّعة.

عند استهداف الإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث، تظلّ الخدمات التي تعمل في المقدّمة متاحة لك من خلال طريقة setForeground المقابلة.

عامل

لا يعرف العمال ما إذا كان العمل الذي يُجرونه مُسرَّعًا أم لا. يمكن للموظفين، مع ذلك، عرض إشعار على بعض إصدارات Android عند تسريع عملية WorkRequest.

لتفعيل ذلك، يقدّم WorkManager طريقة getForegroundInfoAsync()، التي يجب تنفيذها ليتمكّن WorkManager من عرض إشعار لبدء ForegroundService عند الضرورة.

CoroutineWorker

إذا كنت تستخدم CoroutineWorker، عليك تنفيذ getForegroundInfo(). بعد ذلك، تتم إحالة الطلب إلى setForeground() في غضون doWork(). سيؤدي ذلك إلى إنشاء الإشعار في إصدارات Android الأقدم من 12.

راجِع المثال التالي:

  class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
   CoroutineWorker(appContext, workerParams) {

   override suspend fun getForegroundInfo(): ForegroundInfo {
       return ForegroundInfo(
           NOTIFICATION_ID, createNotification()
       )
   }

   override suspend fun doWork(): Result {
       TODO()
   }

    private fun createNotification() : Notification {
       TODO()
    }

}

سياسات الحصص

يمكنك التحكّم في ما يحدث للعمل المُسرَّع عندما يصل تطبيقك إلى حصة التنفيذ. للمتابعة، يمكنك إجراء ما يلي:setExpedited()

  • OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST، ما يؤدي إلى تنفيذ المهمة كطلب عمل عادي. يوضّح المقتطف أعلاه ذلك.
  • OutOfQuotaPolicy.DROP_WORK_REQUEST، ما يؤدي إلى إلغاء الطلب في حال عدم توفّر حصة كافية.

العمل المُعجَّل المؤجَّل

يحاول النظام تنفيذ مهمة مُسرَّعة معيّنة في أقرب وقت ممكن بعد invocation of the job. ومع ذلك، كما هو الحال مع الأنواع الأخرى من الوظائف، قد يُرجئ النظام بدء العمل الجديد المُعجل، مثل الحالات التالية:

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

جدولة العمل الدوري

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

في ما يلي كيفية استخدام PeriodicWorkRequest لإنشاء كائن WorkRequest يتم تنفيذه بشكل دوري:

Kotlin

val saveRequest =
       PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
    // Additional configuration
           .build()

Java

PeriodicWorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS)
           // Constraints
           .build();

في هذا المثال، تم جدولة العمل بفاصل زمني قدره ساعة واحدة.

يتم تحديد فترة الفاصل على أنّها الحد الأدنى للوقت بين التكرارات. يعتمد الوقت الدقيق الذي سيتم فيه تنفيذ Worker على القيود التي تستخدمها في عنصر WorkRequest وعلى التحسينات التي يجريها النظام.

فواصل جري مرنة

إذا كانت طبيعة عملك حسّاسة لتوقيت التنفيذ، يمكنك ضبط PeriodicWorkRequest ليعمل خلال فترة مرنة داخل كل فترة فاصل، كما هو موضّح في الشكل 1.

يمكنك ضبط فاصل مرن لمهمة دورية. يمكنك تحديد فاصل تكرار،
وفاصل مرن يحدّد مقدارًا معيّنًا من الوقت في نهاية
فاصل التكرار. يحاول WorkManager تنفيذ مهمتك في وقت معيّن أثناء
الفاصل الزمني المرن في كل دورة.

الشكل 1: يعرض المخطّط البياني فواصل زمنية متكرّرة مع الفترة المرنة التي يمكن فيها تنفيذ العمل.

لتحديد عمل دوري مع فترة مرنة، يمكنك تمرير flexInterval مع repeatInterval عند إنشاء PeriodicWorkRequest. تبدأ فترة المرونة في repeatInterval - flexInterval وتستمر إلى نهاية الفاصل.

في ما يلي مثال على عمل دوري يمكن تنفيذه خلال آخر 15 دقيقة من كل ساعة.

Kotlin

val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(
       1, TimeUnit.HOURS, // repeatInterval (the period cycle)
       15, TimeUnit.MINUTES) // flexInterval
    .build()

Java

WorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class,
               1, TimeUnit.HOURS,
               15, TimeUnit.MINUTES)
           .build();

يجب أن يكون فاصل التكرار أكبر من أو يساوي PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS ويجب أن يكون فاصل المرونة أكبر من أو يساوي PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS.

تأثير القيود على العمل الدوري

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

قيود العمل

تضمن القيود تأجيل العمل إلى أن يتم استيفاء الشروط المثلى. تتوفّر القيود التالية لخدمة WorkManager.

NetworkType تقييد نوع الشبكة المطلوب لتشغيل عملك على سبيل المثال، شبكة Wi-Fi (UNMETERED).
BatteryNotLow عند ضبطها على "صحيح"، لن يتم تنفيذ عملك إذا كان الجهاز في وضع البطارية المنخفضة.
RequiresCharging عند ضبطها على "صحيح"، لن يتم تنفيذ عملك إلا عندما يكون الجهاز قيد الشحن.
DeviceIdle عند ضبط هذا الخيار على "صحيح"، يجب أن يكون جهاز المستخدم غير نشط قبل تنفيذ العمل. يمكن أن يكون ذلك مفيدًا لتشغيل عمليات مجمّعة قد تؤثر سلبًا في أداء التطبيقات الأخرى التي تعمل بشكل نشط على جهاز المستخدم.
StorageNotLow عند ضبط هذا الإعداد على true، لن يتم تشغيل عملك إذا كانت مساحة التخزين للمستخدم على الجهاز منخفضة جدًا.

لإنشاء مجموعة من القيود وربطها ببعض الأعمال، أنشئ مثيلًا لمحاولة Constraints باستخدام Contraints.Builder() واضبطه على WorkRequest.Builder().

على سبيل المثال، تنشئ التعليمة البرمجية التالية طلب عمل لا يتم تنفيذه إلا عندما يكون جهاز المستخدم قيد الشحن ومتصلاً بشبكة Wi-Fi:

Kotlin

val constraints = Constraints.Builder()
   .setRequiredNetworkType(NetworkType.UNMETERED)
   .setRequiresCharging(true)
   .build()

val myWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       .setConstraints(constraints)
       .build()

Java

Constraints constraints = new Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresCharging(true)
       .build();

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setConstraints(constraints)
               .build();

عند تحديد قيود متعدّدة، لن يتم تنفيذ عملك إلا عند استيفاء جميع القيود.

في حال عدم استيفاء أحد القيود أثناء تنفيذ عملك، سيوقف WorkManager العامل. ستتم إعادة محاولة تنفيذ العمل عند استيفاء جميع القيود.

العمل المتأخر

في حال عدم توفّر أي قيود على عملك أو استيفاء جميع القيود عند إدراج عملك في "قائمة الانتظار"، قد يختار النظام تنفيذ العمل على الفور. إذا كنت لا تريد تنفيذ العمل على الفور، يمكنك تحديد بدء عملك بعد مرور حد أدنى من الوقت.

في ما يلي مثال على كيفية ضبط عملك لتشغيله بعد 10 دقائق على الأقل من إضافته إلى "قائمة الانتظار".

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .setInitialDelay(10, TimeUnit.MINUTES)
   .build()

Java

WorkRequest myWorkRequest =
      new OneTimeWorkRequest.Builder(MyWork.class)
               .setInitialDelay(10, TimeUnit.MINUTES)
               .build();

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

سياسة إعادة المحاولة والانتظار

إذا كنت بحاجة إلى أن يعيد WorkManager محاولة تنفيذ عملك، يمكنك إرجاع قيمة Result.retry() من العامل. تتم بعد ذلك إعادة جدولة عملك وفقًا لتأخير التراجع وسياسة التراجع.

  • يحدِّد تأخُّر التراجع الحد الأدنى للوقت الذي يجب الانتظار خلاله قبل إعادة محاولة عملك بعد المحاولة الأولى. لا يمكن أن تقل هذه القيمة عن 10 ثوانٍ (أو MIN_BACKOFF_MILLIS).

  • تحدِّد سياسة الانتظار كيفية زيادة وقت الانتظار بمرور الوقت لمحاولة إعادة المحاولة التالية. يتيح WorkManager سياستَي انتظار، هما LINEAR و EXPONENTIAL.

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

في ما يلي مثال على تخصيص سياسة ووقت الانتظار في حالة التراجع.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .setBackoffCriteria(
       BackoffPolicy.LINEAR,
       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
       TimeUnit.MILLISECONDS)
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setBackoffCriteria(
                       BackoffPolicy.LINEAR,
                       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                       TimeUnit.MILLISECONDS)
               .build();

في هذا المثال، تم ضبط الحد الأدنى لتأخير الانتظار على الحد الأدنى المسموح به، وهو 10 ثوانٍ. بما أنّ السياسة هي LINEAR، سيزداد الفاصل الزمني لإعادة المحاولة بمقدار 10 ثوانٍ تقريبًا مع كل محاولة جديدة. على سبيل المثال، سيتمّ إعادة محاولة الإجراء الأول الذي يليه Result.retry() بعد 10 ثوانٍ، يليه 20 و30 و40 ثانية وما إلى ذلك، إذا استمرّ العمل في عرضResult.retry() بعد المحاولات اللاحقة. في حال ضبط سياسة الانتظار على EXPONENTIAL، سيكون تسلسل مدة إعادة المحاولة أقرب إلى 20 و40 و80 وما إلى ذلك.

الإشارة إلى عمل

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

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

على سبيل المثال، تلغي WorkManager.cancelAllWorkByTag(String) كل طلبات العمل التي تحمل علامة معيّنة، وWorkManager.getWorkInfosByTag(String) تعرض قائمة بعناصر WorkInfo التي يمكن استخدامها لتحديد حالة العمل الحالية.

يوضّح الرمز التالي كيفية إضافة علامة "cleanup" إلى عملك:

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .addTag("cleanup")
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
       .addTag("cleanup")
       .build();

أخيرًا، يمكن إضافة علامات متعددة إلى طلب عمل واحد. يتم تخزين هذه العلامات داخليًا كمجموعة من السلاسل. للحصول على مجموعة العلامات المرتبطة بـ WorkRequest، يمكنك استخدام WorkInfo.getTags()‎.

من فئة Worker، يمكنك استرداد مجموعة علاماتها من خلال ListenableWorker.getTags()‎.

تحديد بيانات الإدخال

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

يتم تخزين قيم الإدخال كأزواج مفتاح/قيمة في عنصر Data ويمكن ضبطها في طلب العمل. سيرسل WorkManager الإدخال Data إلى عملك عند تنفيذه. يمكن لفئة Worker الوصول إلى وسيطات الإدخال من خلال استدعاء Worker.getInputData(). يوضّح الرمز البرمجي أدناه كيفية إنشاء مثيل Worker الذي يحتاج إلى إدخال البيانات وكيفية إرساله في طلب العمل.

Kotlin

// Define the Worker requiring input
class UploadWork(appContext: Context, workerParams: WorkerParameters)
   : Worker(appContext, workerParams) {

   override fun doWork(): Result {
       val imageUriInput =
           inputData.getString("IMAGE_URI") ?: return Result.failure()

       uploadFile(imageUriInput)
       return Result.success()
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
val myUploadWork = OneTimeWorkRequestBuilder<UploadWork>()
   .setInputData(workDataOf(
       "IMAGE_URI" to "http://..."
   ))
   .build()

Java

// Define the Worker requiring input
public class UploadWork extends Worker {

   public UploadWork(Context appContext, WorkerParameters workerParams) {
       super(appContext, workerParams);
   }

   @NonNull
   @Override
   public Result doWork() {
       String imageUriInput = getInputData().getString("IMAGE_URI");
       if(imageUriInput == null) {
           return Result.failure();
       }

       uploadFile(imageUriInput);
       return Result.success();
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
WorkRequest myUploadWork =
      new OneTimeWorkRequest.Builder(UploadWork.class)
           .setInputData(
               new Data.Builder()
                   .putString("IMAGE_URI", "http://...")
                   .build()
           )
           .build();

وبالمثل، يمكن استخدام فئة Data لإخراج قيمة معروضة. يتم تناول بيانات الإدخال والإخراج بمزيد من التفصيل في قسم مَعلمات الإدخال والقيم المعروضة.

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

في صفحة الحالات والملاحظات، يمكنك الاطّلاع على مزيد من المعلومات عن حالات العمل وكيفية تتبُّع مستوى تقدّمك.