بعد تحديد
Worker
وWorkRequest
،
تتمثّل الخطوة الأخيرة في وضع عملك في قائمة الانتظار. أبسط طريقة لإضافة عمل إلى قائمة الانتظار هي استدعاء طريقة enqueue()
في WorkManager، مع تمرير WorkRequest
الذي تريد تنفيذه.
Kotlin
val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)
Java
WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);
يجب توخّي الحذر عند إضافة مهام إلى قائمة الانتظار لتجنُّب التكرار. على سبيل المثال، قد يحاول تطبيق تحميل سجلاته إلى خدمة خلفية كل 24 ساعة. إذا لم تكن حريصًا، قد ينتهي بك الأمر إلى إضافة المهمة نفسها إلى قائمة الانتظار عدة مرات، على الرغم من أنّ المهمة تحتاج إلى التنفيذ مرة واحدة فقط. لتحقيق هذا الهدف، يمكنك جدولة العمل على أنّه عمل فريد.
العمل الفريد
العمل الفريد هو مفهوم قوي يضمن عدم توفّر سوى نسخة واحدة من العمل بالاسم نفسه في كل مرة. على عكس المعرّفات، تكون الأسماء الفريدة قابلة للقراءة من قِبل المستخدم ويحدّدها المطوّر بدلاً من أن يتم إنشاؤها تلقائيًا بواسطة WorkManager. على عكس العلامات، لا ترتبط الأسماء الفريدة إلا بنسخة واحدة من العمل.
يمكن تطبيق العمل الفريد على كل من العمل لمرة واحدة والعمل الدوري. يمكنك إنشاء تسلسل عمل فريد من خلال استدعاء إحدى هاتين الطريقتين، وذلك حسب ما إذا كنت ستجدول عملًا متكررًا أو عملًا لمرة واحدة.
WorkManager.enqueueUniqueWork()
للعمل لمرة واحدةWorkManager.enqueueUniquePeriodicWork()
للعمل الدوري
تقبل كلتا الطريقتين 3 وسيطات:
- uniqueWorkName:
String
يُستخدَم لتحديد طلب العمل بشكل فريد. - existingWorkPolicy: هي
enum
تحدّد لـ WorkManager الإجراء الذي يجب اتّخاذه إذا كانت هناك سلسلة غير مكتملة من المهام تحمل هذا الاسم الفريد. لمزيد من المعلومات، يُرجى الاطّلاع على سياسة حلّ التعارض. - استبدِل work بـ
WorkRequest
لتحديد موعد.
باستخدام العمل الفريد، يمكننا حلّ مشكلة الجدولة المكرّرة التي أشرنا إليها سابقًا.
Kotlin
val sendLogsWorkRequest =
PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS)
.setConstraints(Constraints.Builder()
.setRequiresCharging(true)
.build()
)
.build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"sendLogs",
ExistingPeriodicWorkPolicy.KEEP,
sendLogsWorkRequest
)
Java
PeriodicWorkRequest sendLogsWorkRequest = new
PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS)
.setConstraints(new Constraints.Builder()
.setRequiresCharging(true)
.build()
)
.build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"sendLogs",
ExistingPeriodicWorkPolicy.KEEP,
sendLogsWorkRequest);
الآن، إذا تم تنفيذ الرمز البرمجي بينما كانت مهمة sendLogs في قائمة الانتظار، سيتم الاحتفاظ بالمهمة الحالية ولن تتم إضافة مهمة جديدة.
يمكن أن تكون تسلسلات العمل الفريدة مفيدة أيضًا إذا كنت بحاجة إلى إنشاء سلسلة طويلة من المهام بشكل تدريجي. على سبيل المثال، قد يتيح تطبيق تعديل الصور للمستخدمين التراجع عن سلسلة طويلة من الإجراءات. قد تستغرق كل عملية من عمليات التراجع هذه بعض الوقت، ولكن يجب تنفيذها بالترتيب الصحيح. في هذه الحالة، يمكن للتطبيق إنشاء سلسلة "تراجع" وإضافة كل عملية تراجع إلى السلسلة حسب الحاجة. يُرجى الاطّلاع على تسلسل العمل لمزيد من التفاصيل.
سياسة حلّ النزاعات
عند جدولة عمل فريد، عليك إخبار WorkManager بالإجراء الذي يجب اتخاذه عند حدوث تعارض. يمكنك إجراء ذلك من خلال تمرير تعداد عند وضع العمل في قائمة الانتظار.
بالنسبة إلى العمل لمرة واحدة، عليك تقديم
ExistingWorkPolicy
،
الذي يتيح 4 خيارات للتعامل مع التعارض.
REPLACE
يجب أن تتوافق المهام الحالية مع المهام الجديدة. يؤدي هذا الخيار إلى إلغاء العمل الحالي.KEEP
العمل الحالي وتجاهل العمل الجديدAPPEND
العمل الجديد في نهاية العمل الحالي. ستؤدي هذه السياسة إلى ربط عملك الجديد بالعمل الحالي، وسيتم تنفيذه بعد انتهاء العمل الحالي.
يصبح العمل الحالي شرطًا أساسيًا للعمل الجديد. إذا كان العمل الحالي CANCELLED
أو FAILED
، سيكون العمل الجديد أيضًا CANCELLED
أو FAILED
.
إذا كنت تريد تشغيل العمل الجديد بغض النظر عن حالة العمل الحالي، استخدِم APPEND_OR_REPLACE
بدلاً من ذلك.
- تعمل الدالة
APPEND_OR_REPLACE
بطريقة مشابهة للدالةAPPEND
، إلا أنّها لا تعتمد على حالة العمل المسبق. إذا كان العمل الحاليCANCELLED
أوFAILED
، سيستمر تشغيل العمل الجديد.
بالنسبة إلى العمل الدوري، عليك تقديم
ExistingPeriodicWorkPolicy
،
الذي يتيح خيارَين، REPLACE
وKEEP
. تعمل هذه الخيارات بالطريقة نفسها التي تعمل بها الخيارات المشابهة في ExistingWorkPolicy.
ملاحظة عملك
في أي وقت بعد إضافة العمل إلى قائمة الانتظار، يمكنك التحقّق من حالته من خلال طلب البحث من WorkManager باستخدام name
أو id
أو tag
مرتبط به.
Kotlin
// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
Java
// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>
يعرض طلب البحث
ListenableFuture
لكائن WorkInfo
، والذي يتضمّن
id
للعمل، وعلاماته، وState
الحالي، وأي مجموعة بيانات ناتجة باستخدام
Result.success(outputData)
.
تتيح لك صيغتا LiveData
وFlow
لكل طريقة مراقبة التغييرات التي تطرأ على
WorkInfo
من خلال تسجيل أداة معالجة. على سبيل المثال، إذا أردت عرض رسالة للمستخدم عند انتهاء بعض العمليات بنجاح، يمكنك إعدادها على النحو التالي:
Kotlin
workManager.getWorkInfoByIdFlow(syncWorker.id)
.collect{ workInfo ->
if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
Snackbar.make(requireView(),
R.string.work_completed, Snackbar.LENGTH_SHORT)
.show()
}
}
Java
workManager.getWorkInfoByIdLiveData(syncWorker.id)
.observe(getViewLifecycleOwner(), workInfo -> {
if (workInfo.getState() != null &&
workInfo.getState() == WorkInfo.State.SUCCEEDED) {
Snackbar.make(requireView(),
R.string.work_completed, Snackbar.LENGTH_SHORT)
.show();
}
});
طلبات البحث المعقّدة المتعلقة بالعمل
يتيح الإصدار 2.4.0 من WorkManager والإصدارات الأحدث إجراء طلبات بحث معقّدة عن المهام التي تمت إضافتها إلى قائمة الانتظار باستخدام عناصر
WorkQuery
. تتيح WorkQuery البحث عن العمل من خلال مجموعة من علاماته وحالته واسم العمل الفريد.
يوضّح المثال التالي كيف يمكنك العثور على جميع المهام التي تحمل العلامة "syncTag"، والتي تكون في الحالة FAILED
أو CANCELLED
، والتي تحمل اسمًا فريدًا إما "preProcess" أو "sync".
Kotlin
val workQuery = WorkQuery.Builder
.fromTags(listOf("syncTag"))
.addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
.addUniqueWorkNames(listOf("preProcess", "sync")
)
.build()
val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)
Java
WorkQuery workQuery = WorkQuery.Builder
.fromTags(Arrays.asList("syncTag"))
.addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
.addUniqueWorkNames(Arrays.asList("preProcess", "sync")
)
.build();
ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);
يتم ربط كل مكوّن (علامة أو حالة أو اسم) في WorkQuery
ببقية المكوّنات باستخدام AND
. يتم OR
كل قيمة في أحد المكوّنات، على سبيل المثال: (name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
.
تعمل WorkQuery
أيضًا مع ما يعادل LiveData، وهو getWorkInfosLiveData()
، وما يعادل Flow، وهو getWorkInfosFlow()
.
إلغاء العمل وإيقافه
إذا لم تعُد بحاجة إلى تنفيذ العمل الذي سبق أن تمت إضافته إلى قائمة الانتظار، يمكنك طلب إلغائه. يمكن إلغاء العمل من خلال name
أو id
أو tag
المرتبط به.
Kotlin
// by id
workManager.cancelWorkById(syncWorker.id)
// by name
workManager.cancelUniqueWork("sync")
// by tag
workManager.cancelAllWorkByTag("syncTag")
Java
// by id
workManager.cancelWorkById(syncWorker.id);
// by name
workManager.cancelUniqueWork("sync");
// by tag
workManager.cancelAllWorkByTag("syncTag");
في الخلفية، يتحقّق WorkManager من
State
للعمل. إذا كان العمل
منتهيًا،
لن يحدث أي شيء. بخلاف ذلك، سيتم تغيير حالة العمل إلى
CANCELLED
ولن يتم تشغيل العمل في المستقبل. أي مهام WorkRequest
تعتمد على هذا العمل سيتم CANCELLED
أيضًا.
يتلقّى حساب العمل RUNNING
مكالمة إلى ListenableWorker.onStopped()
.
يمكنك إلغاء هذه الطريقة للتعامل مع أي عملية تنظيف محتملة. يمكنك الاطّلاع على إيقاف عامل قيد التشغيل لمزيد من المعلومات.
إيقاف عامل قيد التشغيل
هناك بعض الأسباب المختلفة التي قد تؤدي إلى إيقاف Worker
قيد التشغيل بواسطة WorkManager:
- طلبت إلغاءه بشكل صريح (من خلال الاتصال بالرقم
WorkManager.cancelWorkById(UUID)
مثلاً). - في حالة العمل الفريد،
عليك إضافة
WorkRequest
جديد بشكل صريح إلى قائمة الانتظار باستخدامExistingWorkPolicy
بقيمةREPLACE
. يتم على الفور اعتبار الاشتراك القديمWorkRequest
مُلغى. - لم يعُد عملك يستوفي القيود.
- أصدر النظام تعليمات إلى تطبيقك لإيقاف عملك لسبب ما. يمكن أن يحدث ذلك إذا تجاوزت الموعد النهائي للتنفيذ البالغ 10 دقائق. سيتم إعادة محاولة تنفيذ المهمة في وقت لاحق.
في ظلّ هذه الشروط، يتم إيقاف العامل.
عليك إيقاف أي عمل كنت بصدد تنفيذه بشكل تعاوني وإتاحة أي موارد يحتفظ بها العامل. على سبيل المثال، يجب إغلاق المقابض المفتوحة لقواعد البيانات والملفات في هذه المرحلة. تتوفّر آليتان يمكنك استخدامهما لمعرفة وقت توقّف العامل.
onStopped() callback
يستدعي WorkManager
ListenableWorker.onStopped()
فور إيقاف Worker. يمكنك تجاهل هذه الطريقة لإغلاق
أي موارد قد تحتفظ بها.
السمة isStopped()
يمكنك استدعاء الطريقة
ListenableWorker.isStopped()
للتحقّق مما إذا كان العامل قد تم إيقافه. إذا كنت تنفّذ عمليات طويلة الأمد أو متكرّرة في
Worker، عليك التحقّق من هذه السمة بشكل متكرّر واستخدامها كإشارة
لإيقاف العمل في أقرب وقت ممكن.
ملاحظة: تتجاهل WorkManager قيمة
Result
التي تم ضبطها بواسطة Worker
تلقّى الإشارة onStop، لأنّ Worker يُعدّ متوقفًا.
مراقبة حالة سبب الإيقاف
لتحديد سبب توقّف Worker
، يمكنك تسجيل سبب التوقّف من خلال استدعاء WorkInfo.getStopReason()
:
Kotlin
workManager.getWorkInfoByIdFlow(syncWorker.id)
.collect { workInfo ->
if (workInfo != null) {
val stopReason = workInfo.stopReason
logStopReason(syncWorker.id, stopReason)
}
}
Java
workManager.getWorkInfoByIdLiveData(syncWorker.id)
.observe(getViewLifecycleOwner(), workInfo -> {
if (workInfo != null) {
int stopReason = workInfo.getStopReason();
logStopReason(syncWorker.id, workInfo.getStopReason());
}
});