Android Kotlin से जुड़े बुनियादी बातें 09.2: WorkManager

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

परिचय

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

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

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

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

आप इन चीज़ों के बारे में जानेंगे

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

आप क्या कर पाएंगे!

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

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

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

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

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

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

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

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

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

दूसरा चरण: कोड के बारे में जानना

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

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

WorkManager, Android आर्किटेक्चर कॉम्पोनेंट में से एक है और यह Android Jetpack का हिस्सा है. WorkManager, बैकग्राउंड काम के लिए है जिसे #39:

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

हालांकि, WorkManager बैकग्राउंड के काम करते हैं, लेकिन इनके साथ काम करने से जुड़ी समस्याओं और बैटरी और सिस्टम की परफ़ॉर्मेंस के लिए सबसे सही तरीकों का ध्यान रखा जाता है. WorkManager, वापस API लेवल 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
    यह क्लास, वर्कर को बैकग्राउंड में चलाने का अनुरोध दिखाती है. Constraints की मदद से, वर्कर काम को कब और कैसे चलाना है, यह कॉन्फ़िगर करने के लिए WorkRequest का इस्तेमाल करें. जैसे, डिवाइस प्लग-इन करना या वाई-फ़ाई से कनेक्ट करना. आप बाद के टास्क में WorkRequest लागू करते हैं.
  • WorkManager
    यह कक्षा आपके WorkRequest को शेड्यूल करती और चलाती है. WorkManager, काम के अनुरोधों को इस तरह शेड्यूल करता है कि आपकी तरफ़ से तय की गई पाबंदियों का पालन करते हुए, सिस्टम के संसाधनों पर लोड फैलता है. आप बाद के टास्क में WorkManager लागू करते हैं.

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

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

  1. devbyteviewer पैकेज में, work नाम का एक नया पैकेज बनाएं.
  2. work पैकेज के अंदर, RefreshDataWorker नाम की एक नई Kotlin क्लास बनाएं.
  3. CoroutineWorker क्लास से RefreshDataWorker क्लास को बढ़ाएं. context और WorkerParameters को कंस्ट्रक्टर पैरामीटर के तौर पर पास करें.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}
  1. ऐब्स्ट्रैक्ट क्लास से जुड़ी गड़बड़ी को ठीक करने के लिए, RefreshDataWorker क्लास में doWork() मेथड को बदलें.
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. setupRecurringWork() तरीके में, समय-समय पर काम से जुड़ा अनुरोध बनाएं और शुरू करें. यह अनुरोध PeriodicWorkRequestBuilder() वाले तरीके से, दिन में एक बार किया जा सकता है. RefreshDataWorker की उस क्लास को पास करें जिसे आपने पिछले टास्क में बनाया था. TimeUnit.DAYS की समय इकाई के साथ, 1 के दोहराव वाले इंटरवल में पास हों.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build()

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

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

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

उदाहरण के लिए, हो सकता है कि आप सिंक करने की सिर्फ़ एक कार्रवाई चालू करना चाहें. अगर सिंक करने की एक कार्रवाई 'मंज़ूरी मिलना बाकी है' के तौर पर होती है, तो आप currentPeriodicWorkPolicy का इस्तेमाल करके, उसे चलाने दें या नए काम से बदलने दें.

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

  1. RefreshDataWorker क्लास में, क्लास की शुरुआत में, कंपैनियन ऑब्जेक्ट जोड़ें. इस वर्कर की पहचान खास तरीके से करने के लिए, किसी काम का नाम तय करें.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
  1. DevByteApplication क्लास में, setupRecurringWork() तरीके के आखिर में, enqueueUniquePeriodicWork() तरीके का इस्तेमाल करके काम को शेड्यूल करें. ExistingPeriodicWorkPolicy के लिए KEEP enum में पास करें. repeatingRequest को PeriodicWorkRequest पैरामीटर के तौर पर पास करें.
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. टिंबर शुरू करने के तरीके को 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 विंडो में सबसे नीचे मौजूद लॉगकैट पैनल खोलें. RefreshDataWorker पर फ़िल्टर करें.
  2. ऐप्लिकेशन चलाएं. WorkManager आपके बार-बार होने वाले काम को तुरंत शेड्यूल कर देता है.

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

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

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

इस कदम में, आप समय अंतराल को 1 दिन से घटाकर 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 में लॉगकैट पैनल खोलें और RefreshDataWorker पर फ़िल्टर करें. पिछले लॉग मिटाने के लिए, लॉगकैट हटाएं आइकॉन पर क्लिक करें .
  2. ऐप्लिकेशन चलाएं और WorkManager के ज़रिए आपके बार-बार होने वाले काम को तुरंत शेड्यूल कर दिया जाता है. लॉगकैट पैनल में, लॉग पर ध्यान दें—काम का अनुरोध हर 15 मिनट में एक बार चलाया जाता है. काम से जुड़े अनुरोध लॉग का दूसरा सेट देखने के लिए 15 मिनट इंतज़ार करें. आप ऐप्लिकेशन को चला सकते हैं या बंद कर सकते हैं; काम का मैनेजर को अब भी चलना चाहिए.

    ध्यान दें कि अंतराल कभी-कभी 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 ऑब्जेक्ट बनाते हैं और ऑब्जेक्ट पर एक कंस्ट्रेंट सेट करते हैं, जो कि नेटवर्क टाइप का कंस्ट्रेंट होता है. {0}इस लॉग में सिर्फ़ एक कंस्ट्रेंट के साथ ध्यान रखना आसान होता है. बाद के चरण में, आप अन्य कंस्ट्रेंट जोड़ते हैं.)

  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() तरीके के अंदर, समय-समय पर काम करने के अनुरोध, repeatingRequest पर Constraints ऑब्जेक्ट सेट करें. कंस्ट्रेंट सेट करने के लिए, build() मेथड के ऊपर setConstraints() मैथड जोड़ें.
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()

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

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

  1. पहले से शेड्यूल किए गए किसी भी टास्क को रद्द करने के लिए, ऐप्लिकेशन को डिवाइस या एम्युलेटर से अनइंस्टॉल करें.
  2. Android Studio में Logcat पैनल खोलें. Logcat पैनल में, बाईं ओर मौजूद लॉगकैट हटाएं आइकॉन पर क्लिक करके, पिछले लॉग मिटाएं. work पर फ़िल्टर करें.
  3. डिवाइस या एम्युलेटर में वाई-फ़ाई बंद करें, ताकि आप देख सकें कि कंस्ट्रेंट कैसे काम करते हैं. मौजूदा कोड सिर्फ़ एक कंस्ट्रेंट सेट करता है, जो यह बताता है कि अनुरोध सिर्फ़ ऐसे नेटवर्क पर चलाया जाना चाहिए जिसे सीमित नहीं किया गया है. वाई-फ़ाई बंद होने की वजह से, डिवाइस नेटवर्क से कनेक्ट नहीं है, सीमित या सीमित डेटा वाला नेटवर्क नहीं है. इसलिए, इस सीमा को पूरा नहीं किया जाएगा.
  4. ऐप्लिकेशन चलाएं और लॉगकैट पैनल देखें. WorkManager बैकग्राउंड टास्क को तुरंत शेड्यूल करता है. नेटवर्क में रुकावट नहीं होने की वजह से यह टास्क नहीं चल सकता.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
  1. डिवाइस या एम्युलेटर में वाई-फ़ाई चालू करें और लॉगकैट पैनल देखें. अब शेड्यूल किए गए बैकग्राउंड टास्क को हर 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 को बेहतरीन व्यवहार देने के लिए डिज़ाइन किया गया है.

Udcity कोर्स:

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

अन्य:

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

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

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

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

पहला सवाल

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 की बुनियादी बातें कोडलैब का लैंडिंग पेज देखें.