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

تناول دليل البدء كيفية إنشاء رمز 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 أكثر ملاءمةً لجدولة العمل الذي يتم تكراره على فترات زمنية معيّنة.

تحديد موعد للعمل لمرة واحدة

بالنسبة إلى الأعمال البسيطة التي لا تتطلب ضبطًا إضافيًا، استخدِم الطريقة الثابتة 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();

جدولة العمل المستعجل

قدم WorkManager 2.7.0 مفهوم العمل الإسراع. يسمح هذا لـ 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 خدمة تعمل في المقدّمة على إصدارات النظام الأساسي الأقدم من 12. يمكن للخدمات التي تعمل في المقدّمة عرض إشعار للمستخدم.

تتيح الطريقتان getForegroundInfoAsync() وgetForegroundInfo() في العامل إلى WorkManager لعرض إشعار عند استدعاء setExpedited() قبل الإصدار Android 12.

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

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

عامل

ولا يعرف العاملون ما إذا كان العمل الذي يؤدونه تم تسريعه أم لا. ويمكن للموظفين عرض إشعار على بعض إصدارات Android عند تسريع عملية WorkRequest.

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

عامل الكوروتين

في حال استخدام 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، تؤدي إلى إلغاء الطلب إذا لم تكن هناك حصة كافية.

نموذج تطبيق

للاطّلاع على مثال كامل لكيفية استخدام WorkManager 2.7.0 للعمل الإسراع، يمكنك مراجعة WorkManagerSample على GitHub.

تأجيل العمل المستعجل

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

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

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

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

إليك طريقة استخدام 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();

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

ويتم تحديد الفترة الزمنية على أنّها أدنى مدة فاصلة بين مرات التكرار. يعتمد الوقت الدقيق الذي سيتم فيه تنفيذ العامل على القيود التي تستخدمها في كائن 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).
البطارية غير منخفضة وعند ضبط هذه السياسة على "صحيح"، لن يتم تنفيذ العمل إذا كان الجهاز في وضع شحن البطارية المنخفض.
يتطلب شحن عند ضبط هذه السياسة على "صحيح"، لن يتم تنفيذ عملك إلا أثناء شحن الجهاز.
DeviceIdle عند ضبط هذه السياسة على "صحيح"، يتطلب ذلك أن يكون جهاز المستخدم غير نشِط لفترة قصيرة قبل بدء العمل. ويمكن أن يكون ذلك مفيدًا لتنفيذ العمليات المجمّعة التي قد يكون لها تأثير سلبي في أداء التطبيقات الأخرى التي تعمل بشكلٍ نشط على جهاز المستخدم.
مساحة التخزين غير منخفضة عند ضبط هذه السياسة على "صحيح"، لن يتم تنفيذ عملك إذا كانت مساحة التخزين للمستخدم على الجهاز منخفضة جدًا.

لإنشاء مجموعة من القيود وربطها ببعض الأعمال، يمكنك إنشاء مثيل 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 لاستخراج قيمة معروضة. يتم تناول بيانات الإدخال والمخرجات بمزيد من التفصيل في القسم معلمات الإدخال والقيم التي تم عرضها.

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

في صفحة الحالات والملاحظة، ستتعرف على حالات العمل وكيفية مراقبة تقدم عملك.