Android Kotlin Fundamentals 09.2: WorkManager

यह कोडलैब, Android Kotlin Fundamentals कोर्स का हिस्सा है. अगर कोडलैब को क्रम से पूरा किया जाता है, तो आपको इस कोर्स से सबसे ज़्यादा फ़ायदा मिलेगा. कोर्स के सभी कोडलैब, Android Kotlin Fundamentals कोडलैब के लैंडिंग पेज पर दिए गए हैं.

परिचय

ज़्यादातर ऐप्लिकेशन को लंबे समय तक चलने वाले बैकग्राउंड टास्क करने पड़ते हैं. उदाहरण के लिए, कोई ऐप्लिकेशन सर्वर पर फ़ाइलें अपलोड कर सकता है, सर्वर से डेटा सिंक कर सकता है, और उसे Room डेटाबेस में सेव कर सकता है. इसके अलावा, वह सर्वर को लॉग भेज सकता है या डेटा पर ज़्यादा संसाधन इस्तेमाल करने वाली कार्रवाइयां कर सकता है. इस तरह की कार्रवाइयां, बैकग्राउंड में यूज़र इंटरफ़ेस (यूआई) थ्रेड (मुख्य थ्रेड) से अलग होनी चाहिए. बैकग्राउंड में चल रहे टास्क, डिवाइस के सीमित संसाधनों का इस्तेमाल करते हैं. जैसे, रैम और बैटरी. अगर इसे सही तरीके से मैनेज नहीं किया जाता है, तो इससे उपयोगकर्ता को खराब अनुभव मिल सकता है.

इस कोडलैब में, आपको WorkManager का इस्तेमाल करके, बैकग्राउंड टास्क को ऑप्टिमाइज़ और बेहतर तरीके से शेड्यूल करने का तरीका बताया गया है. Android में बैकग्राउंड प्रोसेसिंग के लिए उपलब्ध अन्य समाधानों के बारे में ज़्यादा जानने के लिए, बैकग्राउंड प्रोसेसिंग के बारे में गाइड देखें.

आपको पहले से क्या पता होना चाहिए

  • Android आर्किटेक्चर के कॉम्पोनेंट, ViewModel, LiveData, और Room का इस्तेमाल कैसे करें.
  • LiveData क्लास पर ट्रांसफ़ॉर्मेशन करने का तरीका.
  • कोरूटीन बनाने और लॉन्च करने का तरीका.
  • डेटा बाइंडिंग में बाइंडिंग अडैप्टर का इस्तेमाल कैसे करें.
  • रिपॉज़िटरी पैटर्न का इस्तेमाल करके, कैश मेमोरी में सेव किया गया डेटा लोड करने का तरीका.

आपको क्या सीखने को मिलेगा

  • Worker बनाने का तरीका, जो काम की एक यूनिट को दिखाता है.
  • काम करने का अनुरोध करने के लिए, WorkRequest बनाने का तरीका.
  • WorkRequest में constraints जोड़ने का तरीका, ताकि यह तय किया जा सके कि वर्कर को कब और कैसे चलाना है.
  • बैकग्राउंड में होने वाले टास्क शेड्यूल करने के लिए, WorkManager का इस्तेमाल कैसे करें.

आपको क्या करना होगा

  • नेटवर्क से DevBytes वीडियो प्लेलिस्ट को पहले से फ़ेच करने के लिए, बैकग्राउंड टास्क को पूरा करने वाला वर्कर बनाएं.
  • वर्कर को समय-समय पर चलाने के लिए शेड्यूल करें.
  • WorkRequest में कंस्ट्रेंट जोड़ें.
  • समय-समय पर होने वाले WorkRequest को शेड्यूल करें. यह हर दिन एक बार लागू होता है.

इस कोडलैब में, आपको DevBytes ऐप्लिकेशन पर काम करना है. इसे आपने पिछले कोडलैब में बनाया था. (अगर आपके पास यह ऐप्लिकेशन नहीं है, तो इस लेसन के लिए शुरुआती कोड डाउनलोड किया जा सकता है.)

DevBytes ऐप्लिकेशन में, DevByte वीडियो की सूची दिखती है. ये छोटे ट्यूटोरियल, Google की Android डेवलपर रिलेशंस टीम ने बनाए हैं. इन वीडियो में, Android डेवलपमेंट के लिए डेवलपर की सुविधाओं और सबसे सही तरीकों के बारे में बताया गया है.

वीडियो को दिन में एक बार पहले से फ़ेच करके, ऐप्लिकेशन में उपयोगकर्ता अनुभव को बेहतर बनाया जा सकता है. इससे यह पक्का होता है कि उपयोगकर्ता को ऐप्लिकेशन खोलते ही नया कॉन्टेंट मिल जाए.

इस टास्क में, आपको स्टार्टर कोड डाउनलोड करना होगा और उसकी जांच करनी होगी.

पहला चरण: स्टार्टर ऐप्लिकेशन डाउनलोड और रन करना

अगर आपने पिछले कोडलैब में DevBytes ऐप्लिकेशन बनाया है, तो उस पर काम जारी रखा जा सकता है. इसके अलावा, स्टार्टर ऐप्लिकेशन को डाउनलोड भी किया जा सकता है.

इस टास्क में, आपको स्टार्टर ऐप्लिकेशन डाउनलोड करके चलाना होगा. साथ ही, स्टार्टर कोड की जांच करनी होगी.

  1. अगर आपके पास DevBytes ऐप्लिकेशन पहले से नहीं है, तो GitHub पर मौजूद DevBytesRepository प्रोजेक्ट से, इस कोडलैब के लिए DevBytes का स्टार्टर कोड डाउनलोड करें.
  2. कोड को अनज़िप करें और Android Studio में प्रोजेक्ट खोलें.
  3. अगर आपका टेस्ट डिवाइस या एम्युलेटर पहले से इंटरनेट से कनेक्ट नहीं है, तो उसे कनेक्ट करें. ऐप्लिकेशन बनाएं और उसे चलाएं. ऐप्लिकेशन, नेटवर्क से DevByte वीडियो की सूची फ़ेच करता है और उन्हें दिखाता है.
  4. ऐप्लिकेशन में, किसी वीडियो पर टैप करके उसे YouTube ऐप्लिकेशन में खोलें.

दूसरा चरण: कोड एक्सप्लोर करना

स्टार्टर ऐप्लिकेशन में, पिछले कोडलैब में पेश किया गया बहुत सारा कोड शामिल होता है. इस कोडलैब के स्टार्टर कोड में नेटवर्किंग, यूज़र इंटरफ़ेस, ऑफ़लाइन कैश मेमोरी, और रिपॉज़िटरी मॉड्यूल शामिल हैं. WorkManager का इस्तेमाल करके, बैकग्राउंड टास्क को शेड्यूल करने पर फ़ोकस किया जा सकता है.

  1. Android Studio में, सभी पैकेज बड़ा करें.
  2. database पैकेज एक्सप्लोर करें. इस पैकेज में डेटाबेस की इकाइयां और लोकल डेटाबेस शामिल होता है. इसे Room का इस्तेमाल करके लागू किया जाता है.
  3. repository पैकेज एक्सप्लोर करें. इस पैकेज में VideosRepository क्लास होती है, जो डेटा लेयर को बाकी ऐप्लिकेशन से एब्स्ट्रैक्ट करती है.
  4. स्टार्टर कोड के बाकी हिस्से को खुद से एक्सप्लोर करें. इसके लिए, पिछले कोडलैब की मदद लें.

WorkManager, Android आर्किटेक्चर कॉम्पोनेंट में से एक है. साथ ही, यह Android Jetpack का हिस्सा है. WorkManager का इस्तेमाल, ऐसे बैकग्राउंड टास्क के लिए किया जाता है जिन्हें बाद में पूरा किया जा सकता है और जिन्हें गारंटी के साथ पूरा करना ज़रूरी होता है:

  • टाली जा सकने वाली का मतलब है कि काम को तुरंत पूरा करने की ज़रूरत नहीं है. उदाहरण के लिए, सर्वर को विश्लेषण से जुड़ा डेटा भेजना या बैकग्राउंड में डेटाबेस को सिंक करना, ऐसे काम हैं जिन्हें टाला जा सकता है.
  • गारंटी के साथ एक्ज़ीक्यूशन का मतलब है कि ऐप्लिकेशन बंद होने या डिवाइस रीस्टार्ट होने पर भी टास्क चलेगा.

WorkManager बैकग्राउंड में काम करता है. साथ ही, यह बैटरी और सिस्टम की परफ़ॉर्मेंस को बेहतर बनाने के लिए, सबसे सही तरीकों का इस्तेमाल करता है और यह भी ध्यान रखता है कि ऐप्लिकेशन, डिवाइस के साथ काम करे. WorkManager, एपीआई लेवल 14 के साथ काम करता है. WorkManager डिवाइस के एपीआई लेवल के हिसाब से, बैकग्राउंड टास्क को शेड्यूल करने का सही तरीका चुनता है. यह JobScheduler (एपीआई 23 और उसके बाद के वर्शन पर) या AlarmManager और BroadcastReceiver को मिलाकर इस्तेमाल कर सकता है.

WorkManager की मदद से, यह तय किया जा सकता है कि बैकग्राउंड टास्क कब चलेगा. उदाहरण के लिए, हो सकता है कि आपको टास्क को सिर्फ़ तब चलाना हो, जब बैटरी की स्थिति, नेटवर्क की स्थिति या चार्जिंग की स्थिति कुछ शर्तों को पूरा करती हो. इस कोडलैब में, बाद में आपको कंस्ट्रेंट सेट करने का तरीका बताया जाएगा.

इस कोडलैब में, आपको एक टास्क शेड्यूल करना है. इससे DevBytes वीडियो प्लेलिस्ट को नेटवर्क से दिन में एक बार पहले से फ़ेच किया जा सकेगा. इस टास्क को शेड्यूल करने के लिए, WorkManager लाइब्रेरी का इस्तेमाल किया जाता है.

  1. build.gradle (Module:app) फ़ाइल खोलें और प्रोजेक्ट में WorkManager डिपेंडेंसी जोड़ें.

    अगर लाइब्रेरी के नए वर्शन का इस्तेमाल किया जाता है, तो समाधान ऐप्लिकेशन को उम्मीद के मुताबिक कंपाइल किया जाना चाहिए. अगर ऐसा नहीं होता है, तो समस्या हल करने की कोशिश करें या लाइब्रेरी के उस वर्शन पर वापस जाएं जो यहां दिखाया गया है.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"
  1. अपने प्रोजेक्ट को सिंक करें और पक्का करें कि कंपाइल करने से जुड़ी कोई गड़बड़ी न हो.

प्रोजेक्ट में कोड जोड़ने से पहले, WorkManager लाइब्रेरी में मौजूद इन क्लास के बारे में जान लें:

  • Worker
    इस क्लास में, बैकग्राउंड में चलने वाले टास्क को तय किया जाता है. इस क्लास को एक्सटेंड किया जाता है और doWork() तरीके को बदला जाता है. doWork() तरीके में, बैकग्राउंड में किए जाने वाले कोड को रखा जाता है. जैसे, सर्वर के साथ डेटा सिंक करना या इमेज प्रोसेस करना. इस टास्क में Worker को लागू करें.
  • WorkRequest
    यह क्लास, वर्कर को बैकग्राउंड में चलाने के अनुरोध को दिखाती है. WorkRequest का इस्तेमाल करके, यह कॉन्फ़िगर करें कि वर्कर टास्क कब और कैसे चलाया जाए. इसके लिए, Constraints का इस्तेमाल करें. जैसे, डिवाइस प्लग इन हो या वाई-फ़ाई से कनेक्ट हो. WorkRequest को बाद के टास्क में लागू किया जाता है.
  • WorkManager
    यह क्लास, आपके WorkRequest को शेड्यूल करती है और उसे चलाती है. WorkManager, वर्क रिक्वेस्ट को इस तरह से शेड्यूल करता है कि सिस्टम के संसाधनों पर लोड कम हो. साथ ही, यह आपके तय किए गए कंस्ट्रेंट का पालन करता है. WorkManager को बाद के टास्क में लागू किया जाता है.

पहला चरण: वर्कर बनाना

इस टास्क में, बैकग्राउंड में DevBytes वीडियो प्लेलिस्ट को पहले से फ़ेच करने के लिए, Worker जोड़ा जाता है.

  1. devbyteviewer पैकेज में, work नाम का एक नया पैकेज बनाएं.
  2. work पैकेज में, RefreshDataWorker नाम की नई Kotlin क्लास बनाएं.
  3. RefreshDataWorker क्लास को CoroutineWorker क्लास से एक्सटेंड करें. कंस्ट्रक्टर पैरामीटर के तौर पर context और WorkerParameters पास करें.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}
  1. ऐब्सट्रैक्ट क्लास की गड़बड़ी को ठीक करने के लिए, doWork() क्लास में मौजूद doWork() मैथड को बदलें.RefreshDataWorker
override suspend fun doWork(): Result {
  return Result.success()
}

सस्पेंडिंग फ़ंक्शन ऐसा फ़ंक्शन होता है जिसे रोका जा सकता है और बाद में फिर से शुरू किया जा सकता है. निलंबित करने वाला फ़ंक्शन, लंबे समय तक चलने वाली कार्रवाई को पूरा कर सकता है. साथ ही, मुख्य थ्रेड को ब्लॉक किए बिना, कार्रवाई के पूरा होने का इंतज़ार कर सकता है.

दूसरा चरण: doWork() को लागू करना

Worker क्लास में मौजूद doWork() तरीके को बैकग्राउंड थ्रेड पर कॉल किया जाता है. यह तरीका, काम को सिंक्रोनस तरीके से करता है. साथ ही, इसे ListenableWorker.Result ऑब्जेक्ट दिखाना चाहिए. Android सिस्टम, Worker को ज़्यादा से ज़्यादा 10 मिनट देता है, ताकि वह अपना काम पूरा कर सके और ListenableWorker.Result ऑब्जेक्ट वापस भेज सके. यह समय खत्म होने के बाद, सिस्टम Worker को बंद कर देता है.

ListenableWorker.Result ऑब्जेक्ट बनाने के लिए, इनमें से किसी एक स्टैटिक तरीके को कॉल करें. इससे बैकग्राउंड में चल रहे काम के पूरा होने की स्थिति का पता चलता है:

  • Result.success()—काम पूरा हो गया है.
  • Result.failure()—काम पूरा हो गया है, लेकिन हमेशा के लिए गड़बड़ी हुई है.
  • Result.retry()—काम में कुछ समय के लिए गड़बड़ी हुई है. इसलिए, इसे फिर से आज़माएं.

इस टास्क में, आपको नेटवर्क से DevBytes वीडियो प्लेलिस्ट फ़ेच करने के लिए, doWork() तरीके को लागू करना होगा. नेटवर्क से डेटा वापस पाने के लिए, VideosRepository क्लास में मौजूद तरीकों का फिर से इस्तेमाल किया जा सकता है.

  1. RefreshDataWorker क्लास में, doWork() के अंदर, VideosDatabase ऑब्जेक्ट और VideosRepository ऑब्जेक्ट बनाएं और इंस्टैंशिएट करें.
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)

   return Result.success()
}
  1. RefreshDataWorker क्लास में, doWork() के अंदर, return स्टेटमेंट के ऊपर, try ब्लॉक में refreshVideos() तरीके को कॉल करें. यह लॉग जोड़ें, ताकि यह ट्रैक किया जा सके कि वर्कर कब चलता है.
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
}

"अनसुलझा रेफ़रंस" गड़बड़ी को ठीक करने के लिए, retrofit2.HttpException इंपोर्ट करें.

  1. आपकी जानकारी के लिए, यहां पूरी RefreshDataWorker क्लास दी गई है:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {

   override suspend fun doWork(): Result {
       val database = getDatabase(applicationContext)
       val repository = VideosRepository(database)
       try {
           repository.refreshVideos()
       } catch (e: HttpException) {
           return Result.retry()
       }
       return Result.success()
   }
}

Worker किसी काम की इकाई के बारे में बताता है. वहीं, WorkRequest यह तय करता है कि काम कब और कैसे किया जाना चाहिए. WorkRequest क्लास को दो तरह से लागू किया जा सकता है:

  • OneTimeWorkRequest क्लास का इस्तेमाल, एक बार में एक टास्क करने के लिए किया जाता है. (एक बार किया जाने वाला टास्क सिर्फ़ एक बार होता है.)
  • PeriodicWorkRequest क्लास का इस्तेमाल, बार-बार होने वाले काम के लिए किया जाता है. यह काम, तय समय पर दोहराया जाता है.

टास्क एक बार या समय-समय पर किए जा सकते हैं. इसलिए, क्लास को इसके हिसाब से चुनें. बार-बार होने वाले काम को शेड्यूल करने के बारे में ज़्यादा जानने के लिए, बार-बार होने वाले काम से जुड़ा दस्तावेज़ देखें.

इस टास्क में, आपको WorkRequest को तय करना और शेड्यूल करना होगा, ताकि पिछले टास्क में बनाया गया वर्कर चल सके.

पहला चरण: बार-बार किए जाने वाले काम सेट अप करना

Android ऐप्लिकेशन में, Application क्लास एक बेस क्लास होती है. इसमें अन्य सभी कॉम्पोनेंट शामिल होते हैं. जैसे, ऐक्टिविटी और सेवाएं. जब आपके ऐप्लिकेशन या पैकेज के लिए प्रोसेस बनाई जाती है, तो Application क्लास (या Application की कोई भी सबक्लास) को किसी अन्य क्लास से पहले इंस्टैंशिएट किया जाता है.

इस सैंपल ऐप्लिकेशन में, DevByteApplication क्लास, Application क्लास की सबक्लास है. DevByteApplication क्लास में WorkManager को शेड्यूल करना सही होता है.

  1. DevByteApplication क्लास में, setupRecurringWork() नाम का एक तरीका बनाएं, ताकि बार-बार होने वाले बैकग्राउंड टास्क को सेट अप किया जा सके.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}
  1. PeriodicWorkRequestBuilder() तरीके का इस्तेमाल करके, setupRecurringWork() तरीके के अंदर, हर दिन में एक बार चलने वाले बार-बार होने वाले काम के अनुरोध को बनाएं और उसे शुरू करें. पिछले टास्क में बनाई गई RefreshDataWorker क्लास पास करें. TimeUnit.DAYS टाइम यूनिट के साथ, 1 का दोहराव वाला इंटरवल पास करें.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build()

इस गड़बड़ी को ठीक करने के लिए, java.util.concurrent.TimeUnit इंपोर्ट करें.

दूसरा चरण: WorkManager की मदद से WorkRequest शेड्यूल करना

WorkRequest तय करने के बाद, इसे WorkManager के साथ शेड्यूल किया जा सकता है. इसके लिए, enqueueUniquePeriodicWork() तरीके का इस्तेमाल करें. इस तरीके से, आपको एक यूनीक नाम वाला PeriodicWorkRequest, क्यू में जोड़ने की अनुमति मिलती है. इसमें एक समय में, किसी खास नाम का सिर्फ़ एक PeriodicWorkRequest चालू हो सकता है.

उदाहरण के लिए, हो सकता है कि आपको सिर्फ़ एक सिंक ऑपरेशन चालू रखना हो. अगर एक सिंक ऑपरेशन पूरा नहीं हुआ है, तो आपके पास उसे पूरा होने देने या ExistingPeriodicWorkPolicy का इस्तेमाल करके, उसे अपने नए काम से बदलने का विकल्प होता है.

WorkRequest को शेड्यूल करने के तरीकों के बारे में ज़्यादा जानने के लिए, WorkManager दस्तावेज़ देखें.

  1. RefreshDataWorker क्लास में, क्लास की शुरुआत में कंपैनियन ऑब्जेक्ट जोड़ें. इस वर्कर की पहचान करने के लिए, कोई यूनीक नाम तय करें.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
  1. DevByteApplication क्लास में, setupRecurringWork() तरीके के आखिर में, enqueueUniquePeriodicWork() तरीके का इस्तेमाल करके काम शेड्यूल करें. ExistingPeriodicWorkPolicy के लिए, KEEP enum में पास करें. PeriodicWorkRequest पैरामीटर के तौर पर repeatingRequest पास करें.
WorkManager.getInstance().enqueueUniquePeriodicWork(
       RefreshDataWorker.WORK_NAME,
       ExistingPeriodicWorkPolicy.KEEP,
       repeatingRequest)

अगर उसी नाम का कोई ऐसा मौजूदा काम है जो पूरा नहीं (अधूरा) हुआ है, तो ExistingPeriodicWorkPolicy.KEEP पैरामीटर की वजह से WorkManager, बार-बार होने वाले पिछले काम को बनाए रखता है और नए काम के अनुरोध को खारिज कर देता है.

  1. DevByteApplication क्लास की शुरुआत में, CoroutineScope ऑब्जेक्ट बनाएं. कंस्ट्रक्टर पैरामीटर के तौर पर Dispatchers.Default पास करें.
private val applicationScope = CoroutineScope(Dispatchers.Default)
  1. कोरूटीन शुरू करने के लिए, DevByteApplication क्लास में delayedInit() नाम का एक नया तरीका जोड़ें.
private fun delayedInit() {
   applicationScope.launch {
   }
}
  1. delayedInit() वाले तरीके में, setupRecurringWork() को कॉल करें.
  2. Timber को शुरू करने की प्रोसेस को onCreate() तरीके से delayedInit() तरीके पर ले जाएं.
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}
  1. DevByteApplication क्लास में, onCreate() तरीके के आखिर में, delayedInit() तरीके को कॉल करने का तरीका जोड़ें.
override fun onCreate() {
   super.onCreate()
   delayedInit()
}
  1. Android Studio विंडो में सबसे नीचे मौजूद, Logcat पैन खोलें. RefreshDataWorker पर फ़िल्टर करें.
  2. ऐप्लिकेशन चलाएं. WorkManager आपके बार-बार किए जाने वाले काम को तुरंत शेड्यूल कर देता है.

    Logcat पैन में, लॉग स्टेटमेंट देखें. इनसे पता चलता है कि वर्क अनुरोध शेड्यूल किया गया है और फिर वह सही तरीके से पूरा हुआ है.
D/RefreshDataWorker: Work request for sync is run
I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]

WM-WorkerWrapper लॉग, WorkManager लाइब्रेरी से दिखता है. इसलिए, इस लॉग मैसेज को बदला नहीं जा सकता.

तीसरा चरण: (ज़रूरी नहीं) WorkRequest को कम से कम इंटरवल के लिए शेड्यूल करना

इस चरण में, समयावधि को एक दिन से घटाकर 15 मिनट कर दिया जाता है. ऐसा इसलिए किया जाता है, ताकि बार-बार होने वाले काम के अनुरोध के लॉग देखे जा सकें.

  1. DevByteApplication क्लास में, setupRecurringWork() मैथड के अंदर, मौजूदा repeatingRequest की परिभाषा को टिप्पणी के तौर पर मार्क करें. 15 मिनट के इंटरवल पर बार-बार होने वाले काम के लिए, नया अनुरोध जोड़ें.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()
  1. Android Studio में Logcat पैनल खोलें और RefreshDataWorker पर फ़िल्टर करें. पिछले लॉग मिटाने के लिए, Clear logcat आइकॉन पर क्लिक करें .
  2. ऐप्लिकेशन चलाएं. इसके बाद, WorkManager आपके बार-बार किए जाने वाले काम को तुरंत शेड्यूल कर देगा. Logcat पैन में, लॉग देखें. वर्क रिक्वेस्ट को हर 15 मिनट में एक बार चलाया जाता है. काम के अनुरोध से जुड़े लॉग का दूसरा सेट देखने के लिए, 15 मिनट इंतज़ार करें. ऐप्लिकेशन को चालू या बंद किया जा सकता है. हालांकि, WorkManager को चालू रहना चाहिए.

    ध्यान दें कि कभी-कभी इंटरवल 15 मिनट से कम होता है और कभी-कभी 15 मिनट से ज़्यादा होता है. (सटीक समय, ओएस के बैटरी ऑप्टिमाइज़ेशन पर निर्भर करता है.)
12:44:40 D/RefreshDataWorker: Work request for sync is run
12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
12:59:24 D/RefreshDataWorker: Work request for sync is run
12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:15:03 D/RefreshDataWorker: Work request for sync is run
13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:29:22 D/RefreshDataWorker: Work request for sync is run
13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:44:26 D/RefreshDataWorker: Work request for sync is run
13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
 

बधाई हो! आपने एक वर्कर बनाया है और WorkManager के साथ काम के अनुरोध को शेड्यूल किया है. हालांकि, इसमें एक समस्या है: आपने कोई शर्त नहीं बताई है. WorkManager दिन में एक बार काम शेड्यूल करेगा. भले ही, डिवाइस की बैटरी कम हो, वह स्लीप मोड में हो या उसमें नेटवर्क कनेक्शन न हो. इससे डिवाइस की बैटरी और परफ़ॉर्मेंस पर असर पड़ेगा. साथ ही, उपयोगकर्ता को खराब अनुभव मिल सकता है.

अगले टास्क में, आपको कुछ शर्तें जोड़कर इस समस्या को हल करना है.

पिछले टास्क में, आपने काम के अनुरोध को शेड्यूल करने के लिए WorkManager का इस्तेमाल किया था. इस टास्क में, यह तय किया जाता है कि काम कब पूरा किया जाएगा.

WorkRequest को तय करते समय, Worker को कब चलना चाहिए, इस बारे में कंस्ट्रेंट तय किए जा सकते हैं. उदाहरण के लिए, हो सकता है कि आप यह बताना चाहें कि काम सिर्फ़ तभी चलना चाहिए, जब डिवाइस इस्तेमाल में न हो, या सिर्फ़ तब, जब डिवाइस प्लग इन हो और वाई-फ़ाई से कनेक्ट किया हुआ हो. काम को फिर से करने की कोशिश के लिए, बैकऑफ़ नीति भी तय की जा सकती है. Constraints.Builder में सेट किए गए तरीके, इस्तेमाल की जा सकने वाली पाबंदियां हैं. ज़्यादा जानने के लिए, काम के अनुरोधों को तय करना लेख पढ़ें.

पहला चरण: Constraints ऑब्जेक्ट जोड़ें और एक कंस्ट्रेंट सेट करें

इस चरण में, एक Constraints ऑब्जेक्ट बनाया जाता है. साथ ही, ऑब्जेक्ट पर एक नेटवर्क-टाइप की पाबंदी सेट की जाती है. (सिर्फ़ एक शर्त होने पर, लॉग को आसानी से देखा जा सकता है. बाद के चरण में, अन्य पाबंदियां जोड़ी जाती हैं.)

  1. DevByteApplication क्लास में, setupRecurringWork() की शुरुआत में, Constraints टाइप का val तय करें. Constraints.Builder() तरीके का इस्तेमाल करें.
val constraints = Constraints.Builder()

इस गड़बड़ी को ठीक करने के लिए, androidx.work.Constraints इंपोर्ट करें.

  1. constraints ऑब्जेक्ट में नेटवर्क टाइप की पाबंदी जोड़ने के लिए, setRequiredNetworkType() तरीके का इस्तेमाल करें. UNMETERED enum का इस्तेमाल करें, ताकि काम का अनुरोध सिर्फ़ तब पूरा हो, जब डिवाइस किसी ऐसे नेटवर्क से कनेक्ट हो जिस पर डेटा के इस्तेमाल की कोई सीमा नहीं है.
.setRequiredNetworkType(NetworkType.UNMETERED)
  1. बिल्डर से पाबंदियां जनरेट करने के लिए, build() तरीके का इस्तेमाल करें.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()

अब आपको नई बनाई गई Constraints ऑब्जेक्ट को वर्क अनुरोध पर सेट करना होगा.

  1. DevByteApplication क्लास में, setupRecurringWork() तरीके के अंदर, Constraints ऑब्जेक्ट को बार-बार होने वाले काम के अनुरोध, repeatingRequest पर सेट करें. सीमाएं सेट करने के लिए, build() तरीके के कॉल के ऊपर setConstraints() तरीका जोड़ें.
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()

दूसरा चरण: ऐप्लिकेशन चलाएं और लॉग देखें

इस चरण में, ऐप्लिकेशन को चलाया जाता है. साथ ही, यह देखा जाता है कि बैकग्राउंड में काम करने का अनुरोध, तय समय पर हो रहा है या नहीं.

  1. पहले से शेड्यूल किए गए किसी भी टास्क को रद्द करने के लिए, डिवाइस या एम्युलेटर से ऐप्लिकेशन को अनइंस्टॉल करें.
  2. Android Studio में Logcat पैन खोलें. Logcat पैनल में, बाईं ओर मौजूद Logcat मिटाएं आइकॉन पर क्लिक करके, पिछले लॉग मिटाएं. work पर फ़िल्टर करें.
  3. डिवाइस या एम्युलेटर में वाई-फ़ाई बंद करें, ताकि आपको पता चल सके कि पाबंदियां कैसे काम करती हैं. मौजूदा कोड में सिर्फ़ एक शर्त सेट की गई है. इससे पता चलता है कि अनुरोध सिर्फ़ ऐसे नेटवर्क पर चलना चाहिए जिसमें डेटा के इस्तेमाल की कोई सीमा नहीं है. वाई-फ़ाई बंद होने की वजह से, डिवाइस किसी नेटवर्क से कनेक्ट नहीं है. भले ही, वह नेटवर्क मीटर किया गया हो या नहीं. इसलिए, इस शर्त को पूरा नहीं किया जा सकेगा.
  4. ऐप्लिकेशन चलाएँ और Logcat पैन पर ध्यान दें. WorkManager बैकग्राउंड टास्क को तुरंत शेड्यूल करता है. नेटवर्क की ज़रूरी शर्तें पूरी न होने की वजह से, टास्क पूरा नहीं किया जा सका.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
  1. डिवाइस या एम्युलेटर में वाई-फ़ाई चालू करें और Logcat पैन देखें. अब शेड्यूल किया गया बैकग्राउंड टास्क, करीब हर 15 मिनट में चलता है. हालांकि, ऐसा तब तक होता है, जब तक नेटवर्क की ज़रूरी शर्तें पूरी होती हैं.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
11:31:47 D/RefreshDataWorker: Work request for sync is run
11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
11:46:45 D/RefreshDataWorker: Work request for sync is run
11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:03:05 D/RefreshDataWorker: Work request for sync is run
12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:16:45 D/RefreshDataWorker: Work request for sync is run
12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:31:45 D/RefreshDataWorker: Work request for sync is run
12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:47:05 D/RefreshDataWorker: Work request for sync is run
12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
13:01:45 D/RefreshDataWorker: Work request for sync is run
13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]

तीसरा चरण: और पाबंदियां जोड़ना

इस चरण में, PeriodicWorkRequest में ये पाबंदियां जोड़ी जाती हैं:

  • बैटरी का लेवल कम नहीं है.
  • डिवाइस को चार्ज करना.
  • डिवाइस का इस्तेमाल नहीं किया जा रहा है; यह सुविधा सिर्फ़ एपीआई लेवल 23 (Android M) और इसके बाद के वर्शन में उपलब्ध है.

DevByteApplication क्लास में यहां दी गई जानकारी लागू करें.

  1. DevByteApplication क्लास में, setupRecurringWork() तरीके के अंदर यह बताएं कि वर्क रिक्वेस्ट सिर्फ़ तब चलनी चाहिए, जब बैटरी का लेवल कम न हो. build() तरीके को कॉल करने से पहले, कंस्ट्रेंट जोड़ें और setRequiresBatteryNotLow() तरीके का इस्तेमाल करें.
.setRequiresBatteryNotLow(true)
  1. काम के अनुरोध को अपडेट करें, ताकि यह सिर्फ़ तब चले, जब डिवाइस चार्ज हो रहा हो. build() तरीके को कॉल करने से पहले, कंस्ट्रेंट जोड़ें और setRequiresCharging() तरीके का इस्तेमाल करें.
.setRequiresCharging(true)
  1. काम के अनुरोध को अपडेट करें, ताकि यह सिर्फ़ तब चले, जब डिवाइस का इस्तेमाल न किया जा रहा हो. build() तरीके को कॉल करने से पहले, कंस्ट्रेंट जोड़ें और setRequiresDeviceIdle() तरीके का इस्तेमाल करें. इस कंस्ट्रेंट से, काम के अनुरोध को सिर्फ़ तब पूरा किया जाता है, जब उपयोगकर्ता डिवाइस का इस्तेमाल न कर रहा हो. यह सुविधा सिर्फ़ Android 6.0 (Marshmallow) और इसके बाद के वर्शन पर उपलब्ध है. इसलिए, SDK टूल के M और इसके बाद के वर्शन के लिए एक शर्त जोड़ें.
.apply {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       setRequiresDeviceIdle(true)
   }
}

यहां constraints ऑब्जेक्ट की पूरी जानकारी दी गई है.

val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresBatteryNotLow(true)
       .setRequiresCharging(true)
       .apply {
           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               setRequiresDeviceIdle(true)
           }
       }
       .build()
  1. setupRecurringWork() तरीके में, अनुरोध के इंटरवल को बदलकर फिर से दिन में एक बार करें.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .setConstraints(constraints)
       .build()

यहां setupRecurringWork() तरीके को पूरी तरह से लागू किया गया है. साथ ही, इसमें एक लॉग भी शामिल है, ताकि यह ट्रैक किया जा सके कि समय-समय पर किए जाने वाले काम के अनुरोध को कब शेड्यूल किया गया है.

private fun setupRecurringWork() {

       val constraints = Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .setRequiresBatteryNotLow(true)
               .setRequiresCharging(true)
               .apply {
                   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                       setRequiresDeviceIdle(true)
                   }
               }
               .build()
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
               .setConstraints(constraints)
               .build()
       
       Timber.d("Periodic Work request for sync is scheduled")
       WorkManager.getInstance().enqueueUniquePeriodicWork(
               RefreshDataWorker.WORK_NAME,
               ExistingPeriodicWorkPolicy.KEEP,
               repeatingRequest)
   }
  1. पहले से शेड्यूल की गई काम से जुड़ी अनुरोध को हटाने के लिए, अपने डिवाइस या एम्युलेटर से DevBytes ऐप्लिकेशन को अनइंस्टॉल करें.
  2. ऐप्लिकेशन चलाएं. इसके बाद, WorkManager तुरंत काम के अनुरोध को शेड्यूल कर देता है. सभी कंस्ट्रेंट को पूरा करने पर, काम का अनुरोध दिन में एक बार चलता है.
  3. यह टास्क, बैकग्राउंड में तब तक चलता रहेगा, जब तक ऐप्लिकेशन इंस्टॉल है. भले ही, ऐप्लिकेशन न चल रहा हो. इसलिए, आपको अपने फ़ोन से ऐप्लिकेशन को अनइंस्टॉल कर देना चाहिए.

बहुत बढ़िया! आपने DevBytes ऐप्लिकेशन में वीडियो को हर दिन पहले से फ़ेच करने के लिए, बैटरी के हिसाब से काम करने वाले अनुरोध को लागू किया और शेड्यूल किया. WorkManager सिस्टम के संसाधनों को ऑप्टिमाइज़ करके, काम को शेड्यूल और पूरा करेगा. आपके उपयोगकर्ताओं और उनकी बैटरी को बहुत खुशी मिलेगी.

Android Studio प्रोजेक्ट: DevBytesWorkManager.

  • WorkManager एपीआई की मदद से, ऐसे एसिंक्रोनस टास्क को आसानी से शेड्यूल किया जा सकता है जिन्हें बाद में पूरा किया जा सकता है. साथ ही, यह भी पक्का किया जा सकता है कि वे टास्क भरोसेमंद तरीके से पूरे हों.
  • ज़्यादातर ऐप्लिकेशन को लंबे समय तक चलने वाले बैकग्राउंड टास्क करने पड़ते हैं. बैकग्राउंड टास्क को ऑप्टिमाइज़ और बेहतर तरीके से शेड्यूल करने के लिए, WorkManager का इस्तेमाल करें.
  • WorkManager लाइब्रेरी में मुख्य क्लास Worker, WorkRequest, और WorkManager हैं.
  • Worker क्लास, काम की एक यूनिट को दिखाता है. बैकग्राउंड टास्क लागू करने के लिए, Worker क्लास को बढ़ाएं और doWork() तरीके को बदलें.
  • WorkRequest क्लास, काम की एक यूनिट को पूरा करने के अनुरोध को दिखाती है. WorkRequest, WorkManager में शेड्यूल किए गए काम के लिए पैरामीटर तय करने वाली बेस क्लास है.
  • WorkRequest क्लास को दो तरीके से लागू किया जा सकता है: OneTimeWorkRequest का इस्तेमाल एक बार किए जाने वाले टास्क के लिए किया जाता है और PeriodicWorkRequest का इस्तेमाल बार-बार होने वाले काम के अनुरोधों के लिए किया जाता है.
  • WorkRequest तय करते समय, Constraints तय किया जा सकता है. इससे यह पता चलता है कि Worker कब चलना चाहिए. पाबंदियों में ये चीज़ें शामिल होती हैं: डिवाइस प्लग इन है या नहीं, डिवाइस इस्तेमाल में नहीं है या नहीं या वाई-फ़ाई कनेक्ट है या नहीं.
  • WorkRequest में शर्तें जोड़ने के लिए, Constraints.Builder के दस्तावेज़ में दिए गए सेट तरीकों का इस्तेमाल करें. उदाहरण के लिए, अगर आपको यह बताना है कि डिवाइस की बैटरी कम होने पर WorkRequest नहीं चलना चाहिए, तो setRequiresBatteryNotLow() सेट करने के तरीके का इस्तेमाल करें.
  • WorkRequest को तय करने के बाद, टास्क को Android सिस्टम को सौंप दें. इसके लिए, WorkManager enqueue तरीकों में से किसी एक का इस्तेमाल करके, टास्क को शेड्यूल करें.
  • Worker को एक्ज़ीक्यूट किए जाने का सटीक समय, WorkRequest में इस्तेमाल किए गए कंस्ट्रेंट और सिस्टम के ऑप्टिमाइज़ेशन पर निर्भर करता है. WorkManager को इन पाबंदियों को ध्यान में रखकर, सबसे अच्छा परफ़ॉर्म करने के लिए डिज़ाइन किया गया है.

Udacity का कोर्स:

Android डेवलपर का दस्तावेज़:

अन्य:

इस सेक्शन में, उन छात्र-छात्राओं के लिए होमवर्क असाइनमेंट की सूची दी गई है जो किसी शिक्षक के कोर्स के हिस्से के तौर पर इस कोडलैब पर काम कर रहे हैं. शिक्षक के पास ये विकल्प होते हैं:

  • अगर ज़रूरी हो, तो होमवर्क असाइन करें.
  • छात्र-छात्राओं को बताएं कि होमवर्क असाइनमेंट कैसे सबमिट किए जाते हैं.
  • होमवर्क असाइनमेंट को ग्रेड दें.

शिक्षक इन सुझावों का इस्तेमाल अपनी ज़रूरत के हिसाब से कर सकते हैं. साथ ही, वे चाहें, तो कोई दूसरा होमवर्क भी दे सकते हैं.

अगर आपको यह कोडलैब खुद से पूरा करना है, तो अपनी जानकारी की जांच करने के लिए, इन होमवर्क असाइनमेंट का इस्तेमाल करें.

पहला सवाल

WorkRequest क्लास को लागू करने के कौन-कौनसे तरीके हैं?

OneTimeWorkPeriodicRequest

OneTimeWorkRequest और PeriodicWorkRequest

OneTimeWorkRequest और RecurringWorkRequest

OneTimeOffWorkRequest और RecurringWorkRequest

दूसरा सवाल

एपीआई 23 और उसके बाद के वर्शन पर बैकग्राउंड टास्क को शेड्यूल करने के लिए, WorkManager इनमें से किस क्लास का इस्तेमाल करता है?

▢ सिर्फ़ JobScheduler

BroadcastReceiver और AlarmManager

AlarmManager और JobScheduler

Scheduler और BroadcastReceiver

तीसरा सवाल

WorkRequest में पाबंदियां जोड़ने के लिए, किस एपीआई का इस्तेमाल किया जाता है?

setConstraints()

addConstraints()

setConstraint()

addConstraintsToWorkRequest()

अगला लेसन शुरू करें: 10.1 स्टाइल और थीम

इस कोर्स में मौजूद अन्य कोडलैब के लिंक के लिए, Android Kotlin Fundamentals कोडलैब का लैंडिंग पेज देखें.