अपने Worker
और अपने WorkRequest
को तय करने के बाद, आखिरी चरण में अपने काम को कतार में लगाएं. WorkManager enqueue()
तरीके को कॉल करके, काम को सबसे आसानी से कतार में लगाया जा सकता है. इसके लिए, आपको वह 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()
इन दोनों तरीकों में तीन तर्क इस्तेमाल किए जा सकते हैं:
- 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 को यह बताना होगा कि टकराव होने पर क्या कार्रवाई करनी है. काम को लाइन में लगाते समय, enum पास करके ऐसा किया जाता है.
एक बार किए जाने वाले काम के लिए, आपको ExistingWorkPolicy
देना होगा. इसमें टकराव को हल करने के लिए, चार विकल्प दिए गए हैं.
REPLACE
मौजूदा काम को नए काम के साथ जोड़ें. इस विकल्प से मौजूदा काम रद्द हो जाता है.KEEP
मौजूदा काम को जारी रखो और नए काम को अनदेखा करो.APPEND
नए काम को मौजूदा काम के आखिर में जोड़ें. इस नीति की वजह से, आपका नया काम मौजूदा काम से जुड़ जाएगा. यह मौजूदा काम के खत्म होने के बाद चलेगा.
मौजूदा काम, नए काम के लिए ज़रूरी शर्त बन जाता है. अगर मौजूदा काम CANCELLED
या FAILED
हो जाता है, तो नया काम भी CANCELLED
या FAILED
हो जाता है.
अगर आपको मौजूदा काम की स्थिति के बावजूद नया काम शुरू करना है, तो APPEND_OR_REPLACE
का इस्तेमाल करें.
APPEND_OR_REPLACE
,APPEND
की तरह ही काम करता है. हालांकि, यह prerequisite के वर्क स्टेटस पर निर्भर नहीं करता. अगर मौजूदा काम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>>
क्वेरी, WorkInfo
ऑब्जेक्ट का ListenableFuture
दिखाती है. इसमें काम का 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();
}
});
काम से जुड़ी मुश्किल क्वेरी
WorkManager 2.4.0 और इसके बाद के वर्शन में, कतार में लगे कामों के लिए मुश्किल क्वेरी की जा सकती हैं. इसके लिए, 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()
से कॉल आता है.
संभावित क्लीनअप को मैनेज करने के लिए, इस तरीके को बदलें. ज़्यादा जानकारी के लिए, चल रहे वर्कर को रोकना लेख पढ़ें.
चालू वर्कर को रोकना
WorkManager, आपकी चल रही Worker
को इन वजहों से रोक सकता है:
- आपने साफ़ तौर पर इसे रद्द करने के लिए कहा हो. उदाहरण के लिए, आपने
WorkManager.cancelWorkById(UUID)
को कॉल करके ऐसा कहा हो. - यूनीक वर्क के मामले में, आपने
REPLACE
केExistingWorkPolicy
के साथ एक नयाWorkRequest
साफ़ तौर पर कतार में लगाया है. पुरानीWorkRequest
को तुरंत रद्द कर दिया जाता है. - अब आपके काम की शर्तों को पूरा नहीं किया जा रहा है.
- सिस्टम ने किसी वजह से आपके ऐप्लिकेशन को काम बंद करने का निर्देश दिया है. ऐसा तब हो सकता है, जब टास्क पूरा करने की समयसीमा 10 मिनट से ज़्यादा हो जाए. इस काम को बाद में फिर से करने के लिए शेड्यूल किया गया है.
इन शर्तों के तहत, आपके वर्कर को रोक दिया जाता है.
आपको अपने वर्कर के ज़रिए किए जा रहे काम को बंद कर देना चाहिए. साथ ही, वर्कर के पास मौजूद सभी संसाधनों को रिलीज़ कर देना चाहिए. उदाहरण के लिए, इस समय आपको डेटाबेस और फ़ाइलों के खुले हुए हैंडल बंद कर देने चाहिए. आपके पास यह समझने के लिए दो तरीके हैं कि आपका वर्कर कब रुक रहा है.
onStopped() कॉलबैक
आपका वर्कर बंद होने के तुरंत बाद, WorkManager ListenableWorker.onStopped()
को शुरू कर देता है. इस तरीके को बदलकर, उन सभी संसाधनों को बंद करें जिनका इस्तेमाल किया जा रहा है.
isStopped() प्रॉपर्टी
ListenableWorker.isStopped()
तरीके को कॉल करके देखा जा सकता है कि वर्कर को पहले ही रोका जा चुका है या नहीं. अगर आपको अपने वर्कर में लंबे समय तक चलने वाले या बार-बार होने वाले ऑपरेशन करने हैं, तो आपको इस प्रॉपर्टी की वैल्यू को बार-बार देखना चाहिए. साथ ही, इसका इस्तेमाल काम को जल्द से जल्द रोकने के सिग्नल के तौर पर करना चाहिए.
ध्यान दें: WorkManager, ऐसे वर्कर के सेट किए गए Result
को अनदेखा करता है जिसे onStop सिग्नल मिला है. ऐसा इसलिए, क्योंकि वर्कर को पहले ही बंद माना जाता है.
रोकने की वजह का स्टेटस देखना
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());
}
});