تناول دليل البدء كيفية إنشاء 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();
جدولة العمل المُعجَّل
قدم 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 خدمة تعمل في المقدّمة على إصدارات النظام الأساسي الأقدم من 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
، ما يؤدي إلى إلغاء الطلب في حال عدم توفّر حصة كافية.
نموذج تطبيق
للاطّلاع على مثال كامل لكيفية استخدام WorkManager 2.7.0 للعمل الإسراع، يمكنك مراجعة WorkManagerSample على GitHub.
تأجيل العمل المستعجل
يحاول النظام تنفيذ مهمة مُسرَّعة معيّنة في أقرب وقت ممكن بعد 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();
في هذا المثال، تتم جدولة العمل بفاصل ساعة واحدة.
ويتم تحديد الفترة الزمنية على أنّها أدنى مدّة زمنية بين مرّات التكرار. يعتمد الوقت الدقيق الذي سيتم فيه تنفيذ العامل على القيود التي تستخدمها في كائن 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
إلى أن يتم استيفاء هذا الشرط. وقد يؤدي ذلك إلى تأخّر تنفيذ عملية معيّنة من عملك أو تخطّيها في حال عدم استيفاء الشروط خلال فاصل التنفيذ.
قيود العمل
تضمن القيود تأجيل العمل إلى أن يتم استيفاء الشروط المثلى. تتوفر القيود التالية لـ WorkManager.
NetworkType | تقيد نوع الشبكة المطلوبة لتشغيل عملك.
على سبيل المثال، شبكة Wi-Fi (UNMETERED ).
|
البطارية غير منخفضة | عند ضبطها على "صحيح"، لن يتم تنفيذ عملك إذا كان الجهاز في وضع البطارية المنخفضة. |
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
لإخراج قيمة معروضة. يتمّ تناول بيانات الإدخال
والإخراج بمزيد من التفصيل في قسم مَعلمات الإدخال
والقيم المعروضة.
الخطوات التالية
في صفحة الحالات والملاحظة، ستتعرف على حالات العمل وكيفية مراقبة تقدم عملك.