এই কোডল্যাবটি অ্যান্ড্রয়েড কোটলিন ফান্ডামেন্টাল কোর্সের অংশ। আপনি যদি ক্রমানুসারে কোডল্যাবগুলির মাধ্যমে কাজ করেন তবে আপনি এই কোর্সের সর্বাধিক মূল্য পাবেন৷ সমস্ত কোর্স কোডল্যাব অ্যান্ড্রয়েড কোটলিন ফান্ডামেন্টাল কোডল্যাব ল্যান্ডিং পৃষ্ঠায় তালিকাভুক্ত করা হয়েছে।
ভূমিকা
 বেশিরভাগ বাস্তব-বিশ্বের অ্যাপ্লিকেশনগুলির দীর্ঘ-চলমান ব্যাকগ্রাউন্ড কাজগুলি সম্পাদন করতে হবে। উদাহরণস্বরূপ, একটি অ্যাপ একটি সার্ভারে ফাইল আপলোড করতে পারে, একটি সার্ভার থেকে ডেটা সিঙ্ক করতে পারে এবং এটি একটি Room ডাটাবেসে সংরক্ষণ করতে পারে, একটি সার্ভারে লগ পাঠাতে পারে, বা ডেটাতে ব্যয়বহুল ক্রিয়াকলাপ চালাতে পারে। এই ধরনের ক্রিয়াকলাপগুলি ব্যাকগ্রাউন্ডে, UI থ্রেডের বাইরে (প্রধান থ্রেড) করা উচিত। পটভূমির কাজগুলি ডিভাইসের সীমিত সংস্থানগুলি ব্যবহার করে, যেমন RAM এবং ব্যাটারি। সঠিকভাবে পরিচালনা না করা হলে এটি ব্যবহারকারীর জন্য একটি খারাপ অভিজ্ঞতা হতে পারে।
 এই কোডল্যাবে, আপনি কীভাবে একটি অপ্টিমাইজ করা এবং দক্ষ উপায়ে একটি ব্যাকগ্রাউন্ড টাস্ক শিডিউল করতে WorkManager ব্যবহার করবেন তা শিখবেন। অ্যান্ড্রয়েডে পটভূমি প্রক্রিয়াকরণের জন্য উপলব্ধ অন্যান্য সমাধান সম্পর্কে আরও জানতে, পটভূমি প্রক্রিয়াকরণের নির্দেশিকা দেখুন। 
আপনি ইতিমধ্যে কি জানা উচিত
-  ViewModel,LiveDataএবংRoomঅ্যান্ড্রয়েড আর্কিটেকচার উপাদানগুলি কীভাবে ব্যবহার করবেন।
-  কিভাবে একটি LiveDataক্লাসে রূপান্তর করতে হয়।
- কিভাবে একটি করোটিন তৈরি এবং চালু করবেন।
- ডাটা বাইন্ডিং এ বাইন্ডিং অ্যাডাপ্টার কিভাবে ব্যবহার করবেন।
- একটি সংগ্রহস্থল প্যাটার্ন ব্যবহার করে ক্যাশে ডেটা কীভাবে লোড করবেন।
আপনি কি শিখবেন
-  কীভাবে একজন Workerতৈরি করবেন, যা কাজের একটি ইউনিটকে প্রতিনিধিত্ব করে।
-  কাজ সম্পাদন করার অনুরোধ করার জন্য কিভাবে একটি WorkRequestতৈরি করবেন।
-  কিভাবে এবং কখন একজন কর্মী চালানো উচিত তা নির্ধারণ করার জন্য WorkRequestএ কীভাবে সীমাবদ্ধতা যুক্ত করবেন।
-  ব্যাকগ্রাউন্ড টাস্ক শিডিউল করতে WorkManagerকিভাবে ব্যবহার করবেন।
আপনি কি করবেন
- নেটওয়ার্ক থেকে DevBytes ভিডিও প্লেলিস্ট প্রাক-আনয়নের জন্য একটি ব্যাকগ্রাউন্ড টাস্ক চালানোর জন্য একজন কর্মী তৈরি করুন।
- কর্মীকে পর্যায়ক্রমে চালানোর জন্য নির্ধারিত করুন।
-  WorkRequestএ সীমাবদ্ধতা যোগ করুন।
-  একটি পর্যায়ক্রমিক WorkRequestসময়সূচী করুন যা দিনে একবার কার্যকর করা হয়।
এই কোডল্যাবে, আপনি DevBytes অ্যাপে কাজ করেন যা আপনি আগের কোডল্যাবে তৈরি করেছেন। (যদি আপনার কাছে এই অ্যাপটি না থাকে, আপনি এই পাঠের জন্য স্টার্টার কোড ডাউনলোড করতে পারেন।)
DevBytes অ্যাপটি DevByte ভিডিওগুলির একটি তালিকা প্রদর্শন করে, যা Google Android ডেভেলপার রিলেশনস টিমের তৈরি করা ছোট টিউটোরিয়াল। ভিডিওগুলি Android বিকাশের জন্য বিকাশকারী বৈশিষ্ট্য এবং সর্বোত্তম অনুশীলনগুলি উপস্থাপন করে৷
আপনি দিনে একবার ভিডিওগুলি প্রাক-আনয়নের মাধ্যমে অ্যাপে ব্যবহারকারীর অভিজ্ঞতা বাড়ান। এটি নিশ্চিত করে যে ব্যবহারকারীরা অ্যাপটি খোলার সাথে সাথে তাজা সামগ্রী পান।

এই টাস্কে, আপনি স্টার্টার কোড ডাউনলোড এবং পরিদর্শন করুন।
ধাপ 1: স্টার্টার অ্যাপটি ডাউনলোড করুন এবং চালান
আপনি আগের কোডল্যাবে তৈরি করা DevBytes অ্যাপের মাধ্যমে কাজ চালিয়ে যেতে পারেন (যদি আপনার কাছে থাকে)। বিকল্পভাবে আপনি স্টার্টার অ্যাপটি ডাউনলোড করতে পারেন।
এই টাস্কে, আপনি স্টার্টার অ্যাপ ডাউনলোড করে রান করুন এবং স্টার্টার কোড পরীক্ষা করুন।
- আপনার যদি ইতিমধ্যেই DevBytes অ্যাপ না থাকে, তাহলে GitHub থেকে DevBytesRepository প্রকল্প থেকে এই কোডল্যাবের জন্য DevBytes স্টার্টার কোডটি ডাউনলোড করুন।
- কোডটি আনজিপ করুন এবং অ্যান্ড্রয়েড স্টুডিওতে প্রকল্পটি খুলুন।
- আপনার পরীক্ষা ডিভাইস বা এমুলেটরকে ইন্টারনেটের সাথে সংযুক্ত করুন, যদি এটি ইতিমধ্যে সংযুক্ত না থাকে। অ্যাপটি তৈরি করুন এবং চালান। অ্যাপটি নেটওয়ার্ক থেকে DevByte ভিডিওগুলির তালিকা নিয়ে আসে এবং সেগুলি প্রদর্শন করে।
- অ্যাপে, YouTube অ্যাপে খুলতে যেকোনো ভিডিওতে ট্যাপ করুন।
ধাপ 2: কোডটি অন্বেষণ করুন
 স্টার্টার অ্যাপটি অনেক কোড নিয়ে আসে যা আগের কোডল্যাবে চালু করা হয়েছিল। এই কোডল্যাবের স্টার্টার কোডে নেটওয়ার্কিং, ইউজার ইন্টারফেস, অফলাইন ক্যাশে এবং রিপোজিটরি মডিউল রয়েছে। আপনি WorkManager ব্যবহার করে ব্যাকগ্রাউন্ড টাস্ক শিডিউল করার উপর ফোকাস করতে পারেন।
- অ্যান্ড্রয়েড স্টুডিওতে, সমস্ত প্যাকেজ প্রসারিত করুন।
-  databaseপ্যাকেজ অন্বেষণ. প্যাকেজটিতে ডাটাবেস সত্তা এবং স্থানীয় ডাটাবেস রয়েছে, যাRoomব্যবহার করে বাস্তবায়িত হয়।
-  repositoryপ্যাকেজ অন্বেষণ. প্যাকেজটিতেVideosRepositoryক্লাস রয়েছে যা অ্যাপের বাকি অংশ থেকে ডেটা স্তরকে বিমূর্ত করে।
- স্টার্টার কোডের বাকি অংশ নিজে নিজে এবং পূর্ববর্তী কোডল্যাবের সাহায্যে অন্বেষণ করুন।
 WorkManager হল Android আর্কিটেকচার উপাদানগুলির মধ্যে একটি এবং Android Jetpack এর অংশ৷ WorkManager হল ব্যাকগ্রাউন্ডের কাজের জন্য যা স্থগিত করা যায় এবং নিশ্চিতভাবে সম্পাদনের প্রয়োজন হয়:
- Deferrable মানে কাজটি অবিলম্বে চালানোর প্রয়োজন নেই। উদাহরণস্বরূপ, সার্ভারে বিশ্লেষণাত্মক ডেটা পাঠানো বা পটভূমিতে ডাটাবেস সিঙ্ক করা এমন কাজ যা পিছিয়ে যেতে পারে।
- গ্যারান্টিড এক্সিকিউশন মানে অ্যাপটি প্রস্থান করলে বা ডিভাইস রিস্টার্ট করলেও টাস্কটি চলবে।

 যখন WorkManager ব্যাকগ্রাউন্ডের কাজ চালায়, এটি সামঞ্জস্যের সমস্যা এবং ব্যাটারি এবং সিস্টেমের স্বাস্থ্যের জন্য সর্বোত্তম অনুশীলনের যত্ন নেয়। WorkManager API স্তর 14-এ ফিরে সামঞ্জস্যের প্রস্তাব দেয়৷ WorkManager একটি ব্যাকগ্রাউন্ড টাস্ক শিডিউল করার জন্য একটি উপযুক্ত উপায় বেছে নেয়, ডিভাইস API স্তরের উপর নির্ভর করে৷ এটি JobScheduler ব্যবহার করতে পারে (এপিআই 23 এবং উচ্চতর) বা AlarmManager এবং BroadcastReceiver এর সংমিশ্রণ। 
 WorkManager আপনাকে ব্যাকগ্রাউন্ড টাস্ক চলাকালীন মানদণ্ড সেট করতে দেয়। উদাহরণস্বরূপ, আপনি ব্যাটারি স্ট্যাটাস, নেটওয়ার্ক স্ট্যাটাস বা চার্জ স্টেট নির্দিষ্ট মানদণ্ড পূরণ করলেই কাজটি চালানোর জন্য চাইতে পারেন। আপনি এই কোডল্যাবে পরে কীভাবে সীমাবদ্ধতা সেট করবেন তা শিখবেন।
 এই কোডল্যাবে, আপনি দিনে একবার নেটওয়ার্ক থেকে DevBytes ভিডিও প্লেলিস্ট প্রাক-আনয়নের জন্য একটি টাস্ক নির্ধারণ করেন। এই টাস্ক শিডিউল করতে, আপনি WorkManager লাইব্রেরি ব্যবহার করুন। 
-  build.gradle (Module:app)ফাইলটি খুলুন এবং প্রকল্পেWorkManagerনির্ভরতা যোগ করুন।
 আপনি যদি লাইব্রেরির সর্বশেষ সংস্করণ ব্যবহার করেন, তাহলে সমাধান অ্যাপটি প্রত্যাশা অনুযায়ী কম্পাইল করা উচিত। যদি এটি না হয়, সমস্যাটি সমাধান করার চেষ্টা করুন, অথবা নীচে দেখানো লাইব্রেরি সংস্করণে ফিরে যান৷
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"- আপনার প্রকল্প সিঙ্ক করুন এবং নিশ্চিত করুন যে কোন সংকলন ত্রুটি নেই।
 আপনি প্রকল্পে কোড যোগ করার আগে, WorkManager লাইব্রেরিতে নিম্নলিখিত ক্লাসগুলির সাথে নিজেকে পরিচিত করুন:
-  Worker
 এই ক্লাসটি যেখানে আপনি পটভূমিতে চালানোর জন্য প্রকৃত কাজ (টাস্ক) সংজ্ঞায়িত করেন। আপনি এই ক্লাসটি প্রসারিত করুন এবংdoWork()পদ্ধতিটি ওভাররাইড করুন।doWork()পদ্ধতি হল যেখানে আপনি পটভূমিতে সঞ্চালনের জন্য কোড রাখেন, যেমন সার্ভারের সাথে ডেটা সিঙ্ক করা বা ছবি প্রসেস করা। আপনি এই কাজেWorkerবাস্তবায়ন করুন।
-  WorkRequest
 এই শ্রেণীটি কর্মীকে ব্যাকগ্রাউন্ডে চালানোর অনুরোধের প্রতিনিধিত্ব করে। কিভাবে এবং কখন কর্মী টাস্ক চালাতে হবে তা কনফিগার করতেWorkRequestব্যবহার করুন, যেমন ডিভাইস প্লাগ ইন বা Wi-Fi কানেক্ট করাConstraintsসাহায্যে। আপনি পরবর্তী টাস্কেWorkRequestবাস্তবায়ন করুন।
-  WorkManager
 এই ক্লাস সময়সূচী এবং আপনারWorkRequestচালায়.WorkManagerএমনভাবে কাজের অনুরোধের সময়সূচী করে যা আপনার নির্দিষ্ট করা সীমাবদ্ধতাগুলিকে সম্মান করার সময় সিস্টেম সংস্থানগুলির উপর লোড ছড়িয়ে দেয়। আপনি পরবর্তী টাস্কেWorkManagerপ্রয়োগ করুন।
ধাপ 1: একজন কর্মী তৈরি করুন
 এই টাস্কে, আপনি ব্যাকগ্রাউন্ডে DevBytes ভিডিও প্লেলিস্ট প্রাক-আনয়নের জন্য একজন Worker যোগ করুন।
-  devbyteviewerপ্যাকেজের ভিতরে,workনামে একটি নতুন প্যাকেজ তৈরি করুন।
-  workপ্যাকেজের ভিতরে,RefreshDataWorkerনামে একটি নতুন কোটলিন ক্লাস তৈরি করুন।
-  CoroutineWorkerক্লাস থেকেRefreshDataWorkerক্লাস প্রসারিত করুন। কনস্ট্রাক্টর প্যারামিটার হিসাবেcontextএবংWorkerParametersপাস করুন।
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}-  বিমূর্ত শ্রেণীর ত্রুটি সমাধান করতে, RefreshDataWorkerক্লাসের মধ্যেdoWork()পদ্ধতিটি ওভাররাইড করুন।
override suspend fun doWork(): Result {
  return Result.success()
}একটি সাসপেন্ডিং ফাংশন হল একটি ফাংশন যা বিরাম দেওয়া এবং পরে আবার শুরু করা যায়। একটি সাসপেন্ডিং ফাংশন একটি দীর্ঘ চলমান অপারেশন চালাতে পারে এবং মূল থ্রেড ব্লক না করে এটি সম্পূর্ণ হওয়ার জন্য অপেক্ষা করতে পারে।
ধাপ 2: doWork () বাস্তবায়ন করুন
 Worker ক্লাসের ভিতরে doWork() পদ্ধতিটিকে একটি ব্যাকগ্রাউন্ড থ্রেডে ডাকা হয়। পদ্ধতিটি সিঙ্ক্রোনাসভাবে কাজ করে এবং একটি ListenableWorker.Result অবজেক্ট ফেরত দেওয়া উচিত। অ্যান্ড্রয়েড সিস্টেম একজন Worker তার কার্য সম্পাদন শেষ করতে এবং একটি ListenableWorker.Result অবজেক্ট ফেরত দিতে সর্বোচ্চ 10 মিনিট সময় দেয়। এই সময়ের মেয়াদ শেষ হওয়ার পরে, সিস্টেম জোর করে Worker থামিয়ে দেয়।
 একটি ListenableWorker.Result অবজেক্ট তৈরি করতে, পটভূমি কাজের সমাপ্তির স্থিতি নির্দেশ করতে নিম্নলিখিত স্ট্যাটিক পদ্ধতিগুলির মধ্যে একটিতে কল করুন:
-  Result.success()—কাজ সফলভাবে সম্পন্ন হয়েছে।
-  Result.failure()— একটি স্থায়ী ব্যর্থতার সাথে কাজ সম্পন্ন হয়েছে।
-  Result.retry()—কাজ একটি ক্ষণস্থায়ী ব্যর্থতার সম্মুখীন হয়েছে এবং পুনরায় চেষ্টা করা উচিত।
 এই টাস্কে, আপনি নেটওয়ার্ক থেকে DevBytes ভিডিও প্লেলিস্ট আনতে doWork() পদ্ধতি প্রয়োগ করেন। আপনি নেটওয়ার্ক থেকে ডেটা পুনরুদ্ধার করতে VideosRepository ক্লাসে বিদ্যমান পদ্ধতিগুলি পুনরায় ব্যবহার করতে পারেন।
-  RefreshDataWorkerক্লাসে,doWork()ভিতরে, একটিVideosDatabaseঅবজেক্ট এবং একটিVideosRepositoryঅবজেক্ট তৈরি এবং ইনস্ট্যান্টিয়েট করুন।
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)
   return Result.success()
}-  RefreshDataWorkerক্লাসে,doWork()এর ভিতরে,returnস্টেটমেন্টের উপরে, একটিtryব্লকের ভিতরেrefreshVideos()পদ্ধতিতে কল করুন। কর্মী চালানো হলে ট্র্যাক করতে একটি লগ যোগ করুন।
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
} "অমীমাংসিত রেফারেন্স" ত্রুটি সমাধান করতে, retrofit2.HttpException আমদানি করুন।
-  এখানে আপনার রেফারেন্সের জন্য সম্পূর্ণ 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 সংজ্ঞায়িত এবং সময়সূচী করেন। 
ধাপ 1: পুনরাবৃত্ত কাজ সেট আপ করুন
 একটি অ্যান্ড্রয়েড অ্যাপের মধ্যে, Application ক্লাস হল বেস ক্লাস যাতে অন্যান্য সমস্ত উপাদান থাকে, যেমন কার্যকলাপ এবং পরিষেবাগুলি। যখন আপনার অ্যাপ্লিকেশন বা প্যাকেজের জন্য প্রক্রিয়াটি তৈরি করা হয়, তখন Application ক্লাস (বা Application যেকোনো সাবক্লাস) অন্য কোনো ক্লাসের আগে ইনস্ট্যান্ট করা হয়।
 এই নমুনা অ্যাপে, DevByteApplication ক্লাস হল Application ক্লাসের একটি সাবক্লাস। DevByteApplication ক্লাস WorkManager নির্ধারণ করার জন্য একটি ভাল জায়গা।
-  DevByteApplicationক্লাসে, পুনরাবৃত্ত ব্যাকগ্রাউন্ড কাজ সেট আপ করতেsetupRecurringWork()নামে একটি পদ্ধতি তৈরি করুন।
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}-  setupRecurringWork()পদ্ধতির ভিতরে,PeriodicWorkRequestBuilder()পদ্ধতি ব্যবহার করে দিনে একবার চালানোর জন্য একটি পর্যায়ক্রমিক কাজের অনুরোধ তৈরি করুন এবং শুরু করুন।RefreshDataWorkerক্লাসে পাস করুন যা আপনি আগের টাস্কে তৈরি করেছিলেন। টাইম ইউনিটের টাইম ইউনিটের সাথে1এর পুনরাবৃত্তি ব্যবধানে পাস করুনTimeUnit.DAYS
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build() ত্রুটি সমাধান করতে, java.util.concurrent.TimeUnit আমদানি করুন। 
ধাপ 2: WorkManager-এর সাথে একটি কাজের অনুরোধের সময় নির্ধারণ করুন
 আপনি আপনার WorkRequest সংজ্ঞায়িত করার পরে, আপনি enqueueUniquePeriodicWork() পদ্ধতি ব্যবহার করে WorkManager এর সাথে এটি নির্ধারণ করতে পারেন। এই পদ্ধতিটি আপনাকে সারিতে একটি অনন্যভাবে নামযুক্ত PeriodicWorkRequest যোগ করতে দেয়, যেখানে একটি নির্দিষ্ট নামের শুধুমাত্র একটি PeriodicWorkRequest একবারে সক্রিয় হতে পারে।
উদাহরণস্বরূপ, আপনি শুধুমাত্র একটি সিঙ্ক অপারেশন সক্রিয় করতে চাইতে পারেন৷ যদি একটি সিঙ্ক অপারেশন মুলতুবি থাকে, আপনি একটি ExistingPeriodicWorkPolicy ব্যবহার করে এটিকে চালানো বা আপনার নতুন কাজের সাথে প্রতিস্থাপন করতে বেছে নিতে পারেন।
 একটি WorkRequest সময়সূচী করার উপায় সম্পর্কে আরও জানতে, WorkManager ডকুমেন্টেশন দেখুন।
-  RefreshDataWorkerক্লাসে, ক্লাসের শুরুতে, একটি সহচর বস্তু যোগ করুন। এই কর্মীকে স্বতন্ত্রভাবে সনাক্ত করার জন্য একটি কাজের নাম নির্ধারণ করুন।
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}-  DevByteApplicationক্লাসে,setupRecurringWork()পদ্ধতির শেষে,enqueueUniquePeriodicWork()পদ্ধতি ব্যবহার করে কাজের সময় নির্ধারণ করুন। Existing PeriodicWork Policy-এর জন্যKEEPenum-এ পাস করুন।PeriodicWorkRequestপ্যারামিটার হিসাবেrepeatingRequestপাস করুন।
WorkManager.getInstance().enqueueUniquePeriodicWork(
       RefreshDataWorker.WORK_NAME,
       ExistingPeriodicWorkPolicy.KEEP,
       repeatingRequest)যদি মুলতুবি (অসম্পূর্ণ) কাজ একই নামের সাথে বিদ্যমান থাকে, ExistingPeriodicWorkPolicy. KEEP প্যারামিটার WorkManager পূর্ববর্তী পর্যায়ক্রমিক কাজ রাখতে এবং নতুন কাজের অনুরোধ বাতিল করে দেয়।
-  DevByteApplicationক্লাসের শুরুতে, একটিCoroutineScopeঅবজেক্ট তৈরি করুন।Dispatchers.Defaultপাস করুন। কনস্ট্রাক্টর প্যারামিটার হিসাবে ডিফল্ট।
private val applicationScope = CoroutineScope(Dispatchers.Default)-  DevByteApplicationক্লাসে, coroutine শুরু করতেdelayedInit()নামে একটি নতুন পদ্ধতি যোগ করুন।
private fun delayedInit() {
   applicationScope.launch {
   }
}-  delayedInit()পদ্ধতির ভিতরে,setupRecurringWork()কল করুন।
-  টিম্বার ইনিশিয়ালাইজেশনটিকে onCreate()পদ্ধতি থেকেdelayedInit()পদ্ধতিতে সরান।
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}-  DevByteApplicationক্লাসে,onCreate()পদ্ধতির শেষে,delayedInit()পদ্ধতিতে একটি কল যোগ করুন।
override fun onCreate() {
   super.onCreate()
   delayedInit()
}-  অ্যান্ড্রয়েড স্টুডিও উইন্ডোর নীচে লগক্যাট ফলকটি খুলুন। RefreshDataWorkerএ ফিল্টার করুন।
-  অ্যাপটি চালান। WorkManagerঅবিলম্বে আপনার পুনরাবৃত্তি কাজ সময়সূচী.
 Logcat প্যানে, লগ স্টেটমেন্টগুলি লক্ষ্য করুন যা দেখায় যে কাজের অনুরোধটি নির্ধারিত হয়েছে, তারপর সফলভাবে চলে।
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
WM-WorkerWrapper লগটি WorkManager লাইব্রেরি থেকে প্রদর্শিত হয়, তাই আপনি এই লগ বার্তাটি পরিবর্তন করতে পারবেন না। 
ধাপ 3: (ঐচ্ছিক) একটি ন্যূনতম ব্যবধানের জন্য কাজের অনুরোধের সময়সূচী করুন
এই ধাপে, আপনি সময়ের ব্যবধান 1 দিন থেকে 15 মিনিটে কমিয়ে আনবেন। আপনি এটি করেন যাতে আপনি একটি পর্যায়ক্রমিক কাজের অনুরোধের জন্য লগ দেখতে পারেন।
-  DevByteApplicationক্লাসে,setupRecurringWork()পদ্ধতির ভিতরে, বর্তমানrepeatingRequestসংজ্ঞাটি মন্তব্য করুন।15মিনিটের পর্যায়ক্রমিক পুনরাবৃত্তি ব্যবধানের সাথে একটি নতুন কাজের অনুরোধ যোগ করুন।
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()-  অ্যান্ড্রয়েড স্টুডিওতে লগক্যাট প্যানটি খুলুন এবং RefreshDataWorkerফিল্টার করুন। পূর্ববর্তী লগগুলি সাফ করতে, সাফ লগক্যাট আইকনে ক্লিক করুন৷ . .
-  অ্যাপটি চালান, এবং WorkManagerঅবিলম্বে আপনার পুনরাবৃত্ত কাজের সময়সূচী করে। Logcat ফলকে, লগগুলি লক্ষ্য করুন—কাজের অনুরোধটি প্রতি 15 মিনিটে একবার চালানো হয়। কাজের অনুরোধ লগের আরেকটি সেট দেখতে 15 মিনিট অপেক্ষা করুন। আপনি অ্যাপ্লিকেশন চলমান ছেড়ে বা এটি বন্ধ করতে পারেন; কাজের ব্যবস্থাপক এখনও চালানো উচিত.
 লক্ষ্য করুন যে ব্যবধান কখনও কখনও 15 মিনিটের কম, এবং কখনও কখনও 15 মিনিটের বেশি। (সঠিক সময় OS ব্যাটারি অপ্টিমাইজেশান সাপেক্ষে।)
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 কখন চালানো উচিত তার জন্য আপনি সীমাবদ্ধতা নির্দিষ্ট করতে পারেন। উদাহরণস্বরূপ, আপনি নির্দিষ্ট করতে চাইতে পারেন যে কাজটি কেবল তখনই চালানো উচিত যখন ডিভাইসটি নিষ্ক্রিয় থাকে, বা শুধুমাত্র যখন ডিভাইসটি প্লাগ ইন করা থাকে এবং Wi-Fi এর সাথে সংযুক্ত থাকে৷ আপনি আবার কাজ করার জন্য একটি ব্যাকঅফ নীতি নির্দিষ্ট করতে পারেন। সমর্থিত সীমাবদ্ধতা হল Constraints.Builder এ সেট করা পদ্ধতি। আরও জানতে, আপনার কাজের অনুরোধ সংজ্ঞায়িত করা দেখুন।
ধাপ 1: একটি সীমাবদ্ধতা বস্তু যোগ করুন এবং একটি সীমাবদ্ধতা সেট করুন
 এই ধাপে, আপনি একটি Constraints অবজেক্ট তৈরি করুন এবং বস্তুর উপর একটি সীমাবদ্ধতা সেট করুন, একটি নেটওয়ার্ক-টাইপ সীমাবদ্ধতা। (শুধুমাত্র একটি সীমাবদ্ধতার সাথে লগগুলি লক্ষ্য করা সহজ। পরবর্তী ধাপে, আপনি অন্যান্য সীমাবদ্ধতা যোগ করুন।)
-  DevByteApplicationক্লাসে,setupRecurringWork()এর শুরুতে,Constraintsপ্রকারের একটিvalসংজ্ঞায়িত করুন।Constraints.Builder()পদ্ধতি ব্যবহার করুন।
val constraints = Constraints.Builder()ত্রুটি সমাধান করতে, androidx.work.Constraints আমদানি করুন।
-  constraintsঅবজেক্টে নেটওয়ার্ক-টাইপ সীমাবদ্ধতা যোগ করতেsetRequiredNetworkType()পদ্ধতিটি ব্যবহার করুন।UNMETEREDenum ব্যবহার করুন যাতে কাজের অনুরোধটি তখনই চলবে যখন ডিভাইসটি একটি মিটারবিহীন নেটওয়ার্কে থাকে৷
.setRequiredNetworkType(NetworkType.UNMETERED)-  বিল্ডার থেকে সীমাবদ্ধতা তৈরি করতে build()পদ্ধতি ব্যবহার করুন।
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()এখন আপনাকে কাজের অনুরোধে নতুন তৈরি করা Constraints অবজেক্ট সেট করতে হবে।
-  DevByteApplicationক্লাসে,setupRecurringWork()পদ্ধতির ভিতরে, পর্যায়ক্রমিক কাজের অনুরোধের জন্যConstraintsঅবজেক্ট সেট করুন,repeatingRequest। সীমাবদ্ধতা সেট করতে,build()মেথড কলের উপরেsetConstraints()মেথড যোগ করুন।
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()ধাপ 2: অ্যাপটি চালান এবং লগগুলি লক্ষ্য করুন
এই ধাপে, আপনি অ্যাপটি চালান এবং লক্ষ্য করুন যে সীমাবদ্ধ কাজের অনুরোধটি ব্যাকগ্রাউন্ডে বিরতিতে চালানো হচ্ছে।
- পূর্বে নির্ধারিত কোনো কাজ বাতিল করতে ডিভাইস বা এমুলেটর থেকে অ্যাপটি আনইনস্টল করুন।
-  অ্যান্ড্রয়েড স্টুডিওতে লগক্যাট প্যানটি খুলুন। Logcat প্যানে, Clear logcat আইকনে ক্লিক করে আগের লগগুলি সাফ করুন  বাম দিকে বাম দিকেworkফিল্টার করুন।
- ডিভাইস বা এমুলেটরে Wi-Fi বন্ধ করুন, যাতে আপনি দেখতে পারেন কিভাবে সীমাবদ্ধতা কাজ করে। বর্তমান কোড শুধুমাত্র একটি সীমাবদ্ধতা সেট করে, যা নির্দেশ করে যে অনুরোধটি শুধুমাত্র একটি মিটারবিহীন নেটওয়ার্কে চালানো উচিত। যেহেতু Wi-Fi বন্ধ আছে, ডিভাইসটি নেটওয়ার্কের সাথে সংযুক্ত নয়, মিটার করা বা আনমিটার করা নেই৷ অতএব, এই সীমাবদ্ধতা পূরণ করা হবে না.
-  অ্যাপটি চালান এবং Logcat ফলকটি লক্ষ্য করুন। WorkManagerঅবিলম্বে ব্যাকগ্রাউন্ড টাস্ক নির্ধারণ করে। কারণ নেটওয়ার্কের সীমাবদ্ধতা পূরণ হয় না, কাজটি চালানো হয় না।
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- ডিভাইস বা এমুলেটরে Wi-Fi চালু করুন এবং 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 [...]
ধাপ 3: আরও সীমাবদ্ধতা যোগ করুন
 এই ধাপে, আপনি PeriodicWorkRequest এ নিম্নলিখিত সীমাবদ্ধতা যোগ করুন:
- ব্যাটারি কম নয়।
- ডিভাইস চার্জিং।
- ডিভাইস নিষ্ক্রিয়; শুধুমাত্র API স্তর 23 (Android M) এবং উচ্চতর তে উপলব্ধ।
 DevByteApplication ক্লাসে নিম্নলিখিতগুলি প্রয়োগ করুন।
-  DevByteApplicationক্লাসে,setupRecurringWork()পদ্ধতির ভিতরে, নির্দেশ করে যে ব্যাটারি কম না হলেই কাজের অনুরোধ চালানো উচিত।build()মেথড কলের আগে সীমাবদ্ধতা যোগ করুন এবংsetRequiresBatteryNotLow()পদ্ধতি ব্যবহার করুন।
.setRequiresBatteryNotLow(true)-  কাজের অনুরোধ আপডেট করুন যাতে ডিভাইসটি চার্জ হওয়ার সময়ই এটি চলে। build()মেথড কলের আগে সীমাবদ্ধতা যোগ করুন এবংsetRequiresCharging()পদ্ধতি ব্যবহার করুন।
.setRequiresCharging(true)-  কাজের অনুরোধ আপডেট করুন যাতে ডিভাইসটি নিষ্ক্রিয় থাকলেই এটি চলে। 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()-  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)
   }- পূর্বে নির্ধারিত কাজের অনুরোধ সরাতে, আপনার ডিভাইস বা এমুলেটর থেকে DevBytes অ্যাপ আনইনস্টল করুন।
-  অ্যাপটি চালান, এবং WorkManagerঅবিলম্বে কাজের অনুরোধের সময়সূচী করে। কাজের অনুরোধ দিনে একবার চলে, যখন সমস্ত সীমাবদ্ধতা পূরণ হয়।
- এই কাজের অনুরোধটি ব্যাকগ্রাউন্ডে চলবে যতক্ষণ পর্যন্ত অ্যাপটি ইনস্টল থাকবে, এমনকি অ্যাপটি চালু না থাকলেও। সেই কারণে, আপনার ফোন থেকে অ্যাপটি আনইনস্টল করা উচিত।
 দারুণ কাজ! আপনি DevBytes অ্যাপে প্রতিদিনের প্রাক-আনয়নের ভিডিওর জন্য একটি ব্যাটারি-বান্ধব কাজের অনুরোধ বাস্তবায়িত এবং শিডিউল করেছেন। WorkManager সিস্টেমের সংস্থানগুলিকে অপ্টিমাইজ করে কাজটি শিডিউল করবে এবং চালাবে। আপনার ব্যবহারকারী এবং তাদের ব্যাটারি খুব খুশি হবে.
অ্যান্ড্রয়েড স্টুডিও প্রকল্প: DevBytesWorkManager ।
-  WorkManagerAPI এটিকে স্থগিত করা, অ্যাসিঙ্ক্রোনাস কাজগুলির সময়সূচী করা সহজ করে যেগুলি অবশ্যই নির্ভরযোগ্যভাবে চালানো উচিত।
-  বেশিরভাগ বাস্তব-বিশ্বের অ্যাপ্লিকেশনগুলির দীর্ঘ-চলমান ব্যাকগ্রাউন্ড কাজগুলি সম্পাদন করতে হবে। একটি অপ্টিমাইজ করা এবং দক্ষ উপায়ে একটি ব্যাকগ্রাউন্ড টাস্ক নির্ধারণ করতে, WorkManagerব্যবহার করুন।
-  WorkManagerলাইব্রেরির প্রধান ক্লাসগুলি হলWorker,WorkRequest, এবংWorkManager৷
-  Workerশ্রেণী কাজের একককে প্রতিনিধিত্ব করে। ব্যাকগ্রাউন্ড টাস্ক বাস্তবায়ন করতে,Workerক্লাস প্রসারিত করুন এবংdoWork()পদ্ধতিটি ওভাররাইড করুন।
-  WorkRequestশ্রেণীটি কাজের একটি ইউনিট সঞ্চালনের অনুরোধের প্রতিনিধিত্ব করে।WorkRequestহল কাজের জন্য পরামিতি নির্দিষ্ট করার জন্য বেস ক্লাস যা আপনিWorkManagerএ শিডিউল করেন।
-  WorkRequestক্লাসের দুটি কংক্রিট বাস্তবায়ন রয়েছে:OneTimeWorkRequestওয়ান-অফ টাস্ক এবং পর্যায়ক্রমিক কাজের অনুরোধের জন্যPeriodicWorkRequest।
-  WorkRequestসংজ্ঞায়িত করার সময়,Workerকখন চালানো উচিত তা নির্দেশ করে আপনিConstraintsনির্দিষ্ট করতে পারেন। সীমাবদ্ধতার মধ্যে ডিভাইসটি প্লাগ ইন করা আছে কিনা, ডিভাইসটি নিষ্ক্রিয় কিনা বা Wi-Fi কানেক্ট করা আছে কিনা ইত্যাদি বিষয় অন্তর্ভুক্ত।
-  WorkRequestএ সীমাবদ্ধতা যোগ করতে,Constraints.Builderডকুমেন্টেশনে তালিকাভুক্ত সেট পদ্ধতি ব্যবহার করুন। উদাহরণস্বরূপ, ডিভাইসের ব্যাটারি কম থাকলেWorkRequestচালানো উচিত নয় তা নির্দেশ করার জন্য,setRequiresBatteryNotLow()সেট পদ্ধতি ব্যবহার করুন।
-  আপনি WorkRequestসংজ্ঞায়িত করার পরে, Android সিস্টেমে কাজটি হস্তান্তর করুন৷ এটি করার জন্য,WorkManagerenqueueপদ্ধতিগুলির একটি ব্যবহার করে কাজটি নির্ধারণ করুন।
-  Workerকার্যকর করার সঠিক সময়WorkRequestএবং সিস্টেম অপ্টিমাইজেশানে ব্যবহৃত সীমাবদ্ধতার উপর নির্ভর করে।WorkManagerএই বিধিনিষেধের পরিপ্রেক্ষিতে সর্বোত্তম সম্ভাব্য আচরণ দেওয়ার জন্য ডিজাইন করা হয়েছে।
উদাসীনতা কোর্স:
অ্যান্ড্রয়েড বিকাশকারী ডকুমেন্টেশন:
- আপনার কাজের অনুরোধ সংজ্ঞায়িত করা
-  WorkManager
- WorkManager দিয়ে শুরু করা
- পুনরাবৃত্ত কাজ
- পটভূমি প্রক্রিয়াকরণের জন্য নির্দেশিকা
অন্যান্য:
এই বিভাগে একজন প্রশিক্ষকের নেতৃত্বে একটি কোর্সের অংশ হিসাবে এই কোডল্যাবের মাধ্যমে কাজ করা শিক্ষার্থীদের জন্য সম্ভাব্য হোমওয়ার্ক অ্যাসাইনমেন্ট তালিকাভুক্ত করা হয়েছে। নিম্নলিখিতগুলি করা প্রশিক্ষকের উপর নির্ভর করে:
- প্রয়োজনে হোমওয়ার্ক বরাদ্দ করুন।
- শিক্ষার্থীদের সাথে যোগাযোগ করুন কিভাবে হোমওয়ার্ক অ্যাসাইনমেন্ট জমা দিতে হয়।
- হোমওয়ার্ক অ্যাসাইনমেন্ট গ্রেড.
প্রশিক্ষকরা এই পরামর্শগুলি যতটা কম বা যতটা চান ততটা ব্যবহার করতে পারেন, এবং তাদের উপযুক্ত মনে করে অন্য কোনও হোমওয়ার্ক বরাদ্দ করতে নির্দ্বিধায় করা উচিত।
আপনি যদি নিজে থেকে এই কোডল্যাবের মাধ্যমে কাজ করে থাকেন, তাহলে আপনার জ্ঞান পরীক্ষা করার জন্য এই হোমওয়ার্ক অ্যাসাইনমেন্টগুলিকে নির্দ্বিধায় ব্যবহার করুন৷
প্রশ্ন 1
 WorkRequest ক্লাসের কংক্রিট বাস্তবায়ন কি?
 ▢ OneTimeWorkPeriodicRequest
 ▢ OneTimeWorkRequest এবং PeriodicWorkRequest
 ▢ OneTimeWorkRequest এবং RecurringWorkRequest
 ▢ OneTimeOffWorkRequest এবং RecurringWorkRequest
প্রশ্ন 2
 API 23 এবং উচ্চতর ব্যাকগ্রাউন্ড টাস্ক শিডিউল করতে WorkManager নিচের কোন ক্লাস ব্যবহার করে?
 ▢ শুধুমাত্র JobScheduler
 ▢ BroadcastReceiver এবং AlarmManager
 ▢ AlarmManager এবং JobScheduler
 ▢ Scheduler এবং BroadcastReceiver
প্রশ্ন 3
 একটি WorkRequest এ সীমাবদ্ধতা যোগ করতে আপনি কোন API ব্যবহার করেন?
 ▢ setConstraints()
 ▢ addConstraints()
 ▢ setConstraint()
 ▢ addConstraintsToWorkRequest() 
 পরবর্তী পাঠ শুরু করুন: 
এই কোর্সে অন্যান্য কোডল্যাবগুলির লিঙ্কগুলির জন্য, Android Kotlin Fundamentals codelabs ল্যান্ডিং পৃষ্ঠাটি দেখুন।