काम मैनेज करना

अपने 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 अपने-आप जनरेट नहीं करता, बल्कि डेवलपर तय करता है. टैग के उलट, खास नाम सिर्फ़ एक बार इस्तेमाल किए जा सकते हैं.

यूनीक वर्क को एक बार और बार-बार होने वाले काम, दोनों पर लागू किया जा सकता है. इनमें से किसी एक तरीके का इस्तेमाल करके, काम करने का एक यूनीक क्रम बनाया जा सकता है. यह इस बात पर निर्भर करता है कि आपको बार-बार होने वाले काम को शेड्यूल करना है या एक बार होने वाले काम को.

इन दोनों तरीकों में तीन तर्क इस्तेमाल किए जा सकते हैं:

  • 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());
        }
  });