هنگامی که Worker
و WorkRequest
خود را تعریف کردید، آخرین مرحله این است که کار خود را در صف قرار دهید. سادهترین راه برای صفبندی کار، فراخوانی متد WorkManager enqueue()
است و WorkRequest
که میخواهید اجرا کنید ارسال کنید.
کاتلین
val myWork: WorkRequest = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork)
جاوا
WorkRequest myWork = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork);
برای جلوگیری از تکراری شدن کار، احتیاط کنید. به عنوان مثال، یک برنامه ممکن است سعی کند گزارش های خود را هر 24 ساعت در یک سرویس پشتیبان آپلود کند. اگر مراقب نباشید، ممکن است در نهایت بارها یک کار را در نوبت قرار دهید، حتی اگر کار فقط یک بار اجرا شود. برای رسیدن به این هدف، می توانید کار را به عنوان یک کار منحصر به فرد برنامه ریزی کنید.
کار بی نظیر
کار منحصر به فرد یک مفهوم قدرتمند است که تضمین می کند که شما در هر زمان فقط یک نمونه از کار با نام خاصی دارید. برخلاف شناسهها، نامهای منحصربهفرد برای انسان قابل خواندن هستند و بهجای اینکه بهطور خودکار توسط WorkManager تولید شوند، توسط توسعهدهنده مشخص میشوند. برخلاف برچسبها ، نامهای منحصربهفرد تنها با یک نمونه کار مرتبط هستند.
کار منحصر به فرد را می توان برای کارهای یک بار و دوره ای اعمال کرد. بسته به اینکه در حال برنامه ریزی برای انجام کارهای تکراری یا یک بار کاری هستید، می توانید با فراخوانی یکی از این روش ها یک دنباله کاری منحصر به فرد ایجاد کنید.
-
WorkManager.enqueueUniqueWork()
برای یک بار کار -
WorkManager.enqueueUniquePeriodicWork()
برای کارهای دوره ای
هر دوی این روش ها 3 آرگومان را می پذیرند:
- uniqueWorkName -
String
که برای شناسایی منحصر به فرد درخواست کار استفاده می شود. - existingWorkPolicy -
enum
که به WorkManager میگوید اگر در حال حاضر یک زنجیره کار ناتمام با آن نام منحصربهفرد وجود دارد، چه کاری انجام دهد. برای اطلاعات بیشتر به سیاست حل تعارض مراجعه کنید. - work -
WorkRequest
برای برنامه ریزی.
با استفاده از کار منحصربهفرد، میتوانیم مشکل زمانبندی تکراری خود را که قبلاً ذکر شد برطرف کنیم.
کاتلین
val sendLogsWorkRequest = PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS) .setConstraints(Constraints.Builder() .setRequiresCharging(true) .build() ) .build() WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest )
جاوا
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 بگویید در صورت بروز تضاد چه اقدامی انجام دهد. این کار را با ارسال یک enum هنگام قرار دادن کار انجام می دهید.
برای کار یکباره، یک ExistingWorkPolicy
ارائه میکنید که از 4 گزینه برای مدیریت تضاد پشتیبانی میکند.
- کار موجود را با کار جدید
REPLACE
. این گزینه کار موجود را لغو می کند. - کار موجود
KEEP
و کار جدید را نادیده بگیرید. - کار جدید را به انتهای کار موجود
APPEND
. این خطمشی باعث میشود کار جدید شما به کار موجود زنجیر شود و پس از اتمام کار موجود اجرا شود.
کار موجود پیش نیاز کار جدید می شود. اگر کار موجود CANCELLED
یا FAILED
شود، کار جدید نیز CANCELLED
یا FAILED
است. اگر میخواهید کار جدید بدون توجه به وضعیت کار موجود اجرا شود، به جای آن از APPEND_OR_REPLACE
استفاده کنید.
- عملکرد
APPEND_OR_REPLACE
مشابهAPPEND
است، با این تفاوت که به وضعیت کار پیش نیاز وابسته نیست. اگر کار موجودCANCELLED
یاFAILED
باشد، کار جدید همچنان اجرا می شود.
برای کارهای دوره ای، یک ExistingPeriodicWorkPolicy
ارائه می کنید که از 2 گزینه، REPLACE
و KEEP
پشتیبانی می کند. این گزینه ها مانند همتایان ExistingWorkPolicy خود عمل می کنند.
مشاهده کار شما
در هر نقطه پس از صف بندی کار، می توانید وضعیت آن را با پرس و جو از WorkManager با name
، id
یا tag
مرتبط با آن بررسی کنید.
کاتلین
// by id workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo> // by name workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>> // by tag workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
جاوا
// 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
از هر یک از روش ها به شما امکان می دهد تا با ثبت یک شنونده ، تغییرات در WorkInfo
را مشاهده کنید . به عنوان مثال، اگر می خواهید زمانی که برخی از کارها با موفقیت به پایان رسید، پیامی را برای کاربر نمایش دهید، می توانید آن را به صورت زیر تنظیم کنید:
کاتلین
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(viewLifecycleOwner) { workInfo -> if(workInfo?.state == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show() } }
جاوا
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(); } });
پرس و جوهای کاری پیچیده
WorkManager 2.4.0 و بالاتر از پرس و جوی پیچیده برای کارهای ردیف شده با استفاده از اشیاء WorkQuery
پشتیبانی می کند. WorkQuery از پرس و جو برای کار با ترکیبی از برچسب(ها)، وضعیت و نام کار منحصر به فرد پشتیبانی می کند.
مثال زیر نشان میدهد که چگونه میتوانید همه کارها را با برچسب، "syncTag" ، که در حالت FAILED
یا CANCELLED
است و دارای نام کاری منحصر به فرد " preProcess " یا " sync " است، پیدا کنید.
کاتلین
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)
جاوا
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
-ed است. به عنوان مثال: (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
.
WorkQuery
همچنین با معادل LiveData، getWorkInfosLiveData()
کار می کند.
لغو و توقف کار
اگر دیگر برای اجرا نیازی به کار قبلی خود ندارید، میتوانید درخواست لغو آن را کنید. کار را می توان با name
، id
یا tag
مرتبط با آن لغو کرد.
کاتلین
// by id workManager.cancelWorkById(syncWorker.id) // by name workManager.cancelUniqueWork("sync") // by tag workManager.cancelAllWorkByTag("syncTag")
جاوا
// 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
ofREPLACE
قرار دادهاید.WorkRequest
قدیمی بلافاصله لغو شده در نظر گرفته می شود. - محدودیت های کار شما دیگر برآورده نمی شود.
- سیستم به برنامه شما دستور داده است که کار شما را به دلایلی متوقف کند. اگر از مهلت اجرای 10 دقیقه تجاوز کنید، ممکن است این اتفاق بیفتد. کار برای امتحان مجدد در زمان بعدی برنامه ریزی شده است.
تحت این شرایط، Worker شما متوقف می شود.
شما باید با همکاری هر کاری را که در حال انجام بودید متوقف کنید و منابعی را که کارگر شما در اختیار دارد آزاد کنید. به عنوان مثال، در این مرحله باید دستگیره های باز را روی پایگاه داده ها و فایل ها ببندید. دو مکانیسم در اختیار شما وجود دارد تا متوجه شوید که کارگر شما در حال توقف است.
پاسخ به تماس onStoped().
WorkManager به محض اینکه Worker شما متوقف شد ListenableWorker.onStopped()
را فراخوانی می کند. این روش را نادیده بگیرید تا هر منبعی را که ممکن است نگه داشته اید ببندید.
ویژگی isStoppped().
می توانید متد ListenableWorker.isStopped()
را فراخوانی کنید تا بررسی کنید که آیا کارگر شما قبلاً متوقف شده است یا خیر. اگر عملیات طولانی مدت یا تکراری را در Worker خود انجام می دهید، باید این ویژگی را مرتباً بررسی کنید و از آن به عنوان سیگنالی برای توقف کار در اسرع وقت استفاده کنید.
توجه: WorkManager Result
تنظیم شده توسط Worker که سیگنال onStop را دریافت کرده است را نادیده می گیرد، زیرا Worker قبلاً متوقف شده در نظر گرفته می شود.