تضمّن دليل البدء كيفية إنشاء 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();
جدولة مهمة مُعجَّلة
قدّمت الإصدار 2.7.0 من WorkManager مفهوم العمل المعجَّل. ويتيح ذلك لـ WorkManager تنفيذ المهام المهمة مع منح النظام تحكّمًا أفضل في الوصول إلى الموارد.
تتميّز المهام المُعجَّلة بالخصائص التالية:
- الأهمية: يناسب العمل المعجّل المهام المهمة للمستخدم أو التي يبدأها المستخدم.
- السرعة: تناسب المهام السريعة المهام القصيرة التي تبدأ على الفور وتكتمل في غضون بضع دقائق.
- الحصص: تحدّد حصة على مستوى النظام تحدّ من وقت التنفيذ في المقدّمة ما إذا كان يمكن بدء مهمة معجَّلة.
- إدارة الطاقة: من غير المرجّح أن تؤثر قيود إدارة الطاقة، مثل ميزة "توفير شحن البطارية" ووضع "السكون"، في إنجاز العمل بشكل أسرع.
- زمن الاستجابة: ينفّذ النظام العمل المعجّل على الفور، شرط أن يسمح عبء العمل الحالي للنظام بذلك، ما يعني أنّ هذه المهام حساسة لزمن الاستجابة ولا يمكن جدولة تنفيذها لاحقًا.
قد يكون أحد حالات الاستخدام المحتملة للعملية السريعة ضمن تطبيق محادثة عندما يريد المستخدم إرسال رسالة أو صورة مرفقة. وبالمثل، قد يرغب تطبيق يتعامل مع عملية دفع أو اشتراك في استخدام العمل المعجّل. ويرجع ذلك إلى أنّ هذه المهام مهمة للمستخدم، ويتم تنفيذها بسرعة في الخلفية، ويجب أن تبدأ على الفور، ويجب أن تستمر في التنفيذ حتى إذا أغلق المستخدم التطبيق.
الحصص
يجب أن يخصّص النظام وقت تنفيذ لمهمة معجَّلة قبل أن يتمكّن من تشغيلها. وقت التنفيذ ليس غير محدود. بدلاً من ذلك، يحصل كل تطبيق على حصة من وقت التنفيذ. عندما يستخدم تطبيقك وقت التنفيذ ويبلغ الحصة المخصّصة له، لن تتمكّن من تنفيذ العمل المعجّل إلى أن يتم تجديد الحصة. ويتيح ذلك لنظام التشغيل Android تحقيق توازن أكثر فعالية بين موارد التطبيقات.
يعتمد مقدار وقت التنفيذ المتاح للتطبيق على حزمة وضع الاستعداد وأهمية العملية.
يمكنك تحديد ما يحدث عندما لا تسمح حصة التنفيذ بتشغيل مهمة معجّلة على الفور. يُرجى الاطّلاع على المقتطفات التالية لمعرفة التفاصيل.
تنفيذ مهمة مُعجَّلة
بدءًا من الإصدار 2.7 من WorkManager، يمكن لتطبيقك استدعاء setExpedited()
للإشارة إلى أنّ WorkRequest
يجب أن يتم تشغيله بأسرع ما يمكن باستخدام مهمة معجَّلة. يقدّم مقتطف الرمز التالي مثالاً على كيفية استخدام setExpedited()
:
Kotlin
val request = OneTimeWorkRequestBuilder<SyncWorker>()
<b>.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)</b>
.build()
WorkManager.getInstance(context)
.enqueue(request)
Java
OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>()
.setInputData(inputData)
<b>.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)</b>
.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
، ما يؤدي إلى إلغاء الطلب إذا لم تتوفر حصة كافية.
المهمة المُعجَّلة المؤجَّلة
يحاول النظام تنفيذ مهمة معجَّلة معيّنة في أسرع وقت ممكن بعد استدعاء المهمة. ومع ذلك، كما هو الحال مع أنواع الوظائف الأخرى، قد يؤجّل النظام بدء العمل الجديد المعجّل، مثل الحالات التالية:
- التحميل: يكون تحميل النظام مرتفعًا جدًا، ويمكن أن يحدث ذلك عند تشغيل عدد كبير جدًا من المهام أو عندما لا يتوفّر في النظام ذاكرة كافية.
- الحصة: تم تجاوز الحد الأقصى لحصة المهمة المعجّلة. تستخدم العمليات المعجَّلة نظام حصص يستند إلى "حِزم وضع الاستعداد للتطبيق"، ويفرض قيودًا على الحد الأقصى لمدة التنفيذ خلال فترة زمنية متجددة. تكون الحصص المستخدَمة في المهام المعجَّلة أكثر تقييدًا من الحصص المستخدَمة في الأنواع الأخرى من المهام التي تعمل في الخلفية.
جدولة العمل الدوري
قد يتطلّب تطبيقك في بعض الأحيان تنفيذ بعض المهام بشكل دوري. على سبيل المثال، قد تحتاج إلى إجراء نسخ احتياطي دوري لبياناتك أو تنزيل محتوى جديد في تطبيقك أو تحميل السجلات إلى خادم.
في ما يلي كيفية استخدام 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.
الشكل 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
إلى أن يتم استيفاء هذا الشرط. وقد يؤدي ذلك إلى تأخير تنفيذ مهمة معيّنة أو حتى تخطّيها إذا لم يتم استيفاء الشروط خلال الفترة الزمنية المحدّدة للتنفيذ.
قيود العمل
Constraints
التأكّد من تأجيل العمل إلى حين استيفاء الشروط المثالية. تتوفّر القيود التالية في WorkManager:
NetworkType | يفرض قيودًا على نوع الشبكة المطلوب لتشغيل عملك.
على سبيل المثال، شبكة Wi-Fi (UNMETERED ).
|
BatteryNotLow | عند ضبط القيمة على "صحيح"، لن يتم تشغيل عملك إذا كان الجهاز في وضع توفير شحن البطارية. |
RequiresCharging | عند ضبطها على "صحيح"، لن يتم تنفيذ عملك إلا عندما يكون الجهاز قيد الشحن. |
DeviceIdle | عند ضبط هذا الخيار على "صحيح"، يجب أن يكون جهاز المستخدم غير نشط قبل تشغيل العمل. يمكن أن يكون ذلك مفيدًا لتنفيذ عمليات مجمّعة قد تؤثر سلبًا في أداء التطبيقات الأخرى التي تعمل بنشاط على جهاز المستخدم. |
StorageNotLow | عند ضبط القيمة على "صحيح"، لن يتم تشغيل عملك إذا كانت مساحة التخزين المتاحة للمستخدم على الجهاز منخفضة جدًا. |
لإنشاء مجموعة من القيود وربطها ببعض المهام، أنشئ مثيلاً من Constraints
باستخدام Constraints.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 التي يمكن استخدامها لتحديد حالة العمل الحالية.
يوضّح الرمز التالي كيف يمكنك إضافة علامة "تنظيف" إلى عملك:
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
لعرض قيمة عائدة. يتم تناول بيانات الإدخال والإخراج بمزيد من التفصيل في القسم مَعلمات الإدخال والقيم المعروضة.
الخطوات التالية
في صفحة الحالات والمراقبة، ستتعرّف على مزيد من المعلومات حول حالات العمل وكيفية تتبُّع مستوى تقدّم عملك.