این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کد لبه های دوره در صفحه فرود کد لبه های Android Kotlin Fundamentals فهرست شده اند.
مقدمه
 اکثر برنامه های دنیای واقعی نیاز به انجام کارهای پس زمینه طولانی مدت دارند. به عنوان مثال، یک برنامه ممکن است فایلها را روی سرور آپلود کند، دادهها را از یک سرور همگامسازی کند و در پایگاه داده Room ذخیره کند، گزارشها را به سرور ارسال کند یا عملیات گرانقیمتی را روی دادهها اجرا کند. چنین عملیاتی باید در پس زمینه، خارج از رشته UI (رشته اصلی) انجام شود. کارهای پسزمینه منابع محدود دستگاه مانند رم و باتری را مصرف میکنند. این ممکن است منجر به تجربه ضعیفی برای کاربر در صورت عدم استفاده صحیح شود.
 در این نرم افزار کد، یاد می گیرید که چگونه از WorkManager برای برنامه ریزی یک کار پس زمینه به روشی بهینه و کارآمد استفاده کنید. To learn more about other available solutions for background processing in Android, see Guide to background processing . 
آنچه از قبل باید بدانید
-  نحوه استفاده از ViewModel،LiveDataوRoomAndroid Architecture Components.
-  نحوه انجام تبدیل در کلاس LiveData.
- نحوه ساخت و راه اندازی یک کوروتین
- نحوه استفاده از آداپتورهای اتصال در اتصال داده
- نحوه بارگیری داده های کش با استفاده از الگوی مخزن.
چیزی که یاد خواهید گرفت
-  نحوه ایجاد یک Workerکه نشان دهنده یک واحد کار است.
-  نحوه ایجاد WorkRequestبرای درخواست انجام کار.
-  نحوه اضافه کردن محدودیتها به WorkRequestبرای تعریف نحوه و زمان اجرای یک کارگر.
-  نحوه استفاده از WorkManagerبرای برنامه ریزی وظایف پس زمینه.
کاری که خواهی کرد
- یک کارگر برای اجرای یک کار پس زمینه برای واکشی از قبل لیست پخش ویدیوی DevBytes از شبکه ایجاد کنید.
- کارگر را برنامه ریزی کنید تا به صورت دوره ای کار کند.
-  محدودیت هایی را به WorkRequestاضافه کنید.
-  یک WorkRequestدوره ای را برنامه ریزی کنید که یک بار در روز اجرا می شود.
در این کد لبه، شما روی برنامه DevBytes که در یک کد لبه قبلی توسعه داده اید کار می کنید. (اگر این برنامه را ندارید، می توانید کد شروع این درس را دانلود کنید.)
برنامه DevBytes لیستی از ویدیوهای DevByte را نمایش می دهد که آموزش های کوتاهی توسط تیم ارتباط با توسعه دهندگان Google Android ساخته شده است. این ویدیوها ویژگیهای توسعهدهنده و بهترین شیوههای توسعه اندروید را معرفی میکنند.
با واکشی از قبل ویدیوها یک بار در روز، تجربه کاربری را در برنامه افزایش می دهید. این تضمین می کند که کاربر به محض باز کردن برنامه، محتوای تازه دریافت می کند.

در این کار کد شروع را دانلود و بررسی می کنید.
مرحله 1: برنامه شروع را دانلود و اجرا کنید
میتوانید از طریق برنامه DevBytes که در Codelab قبلی ساختهاید، به کار خود ادامه دهید (اگر آن را دارید). یا می توانید برنامه شروع را دانلود کنید.
در این کار شما اپلیکیشن استارتر را دانلود و اجرا می کنید و کد استارتر را بررسی می کنید.
- اگر قبلاً برنامه DevBytes را ندارید، کد شروع DevBytes را برای این Codelab از پروژه DevBytesRepository از GitHub دانلود کنید.
- کد را از حالت فشرده خارج کرده و پروژه را در اندروید استودیو باز کنید.
- دستگاه آزمایشی یا شبیه ساز خود را به اینترنت وصل کنید، اگر قبلاً متصل نیست. برنامه را بسازید و اجرا کنید. این برنامه لیستی از ویدیوهای DevByte را از شبکه دریافت می کند و آنها را نمایش می دهد.
- در برنامه، روی هر ویدیویی ضربه بزنید تا در برنامه YouTube باز شود.
مرحله 2: کد را کاوش کنید
 برنامه استارتر دارای کدهای زیادی است که در کدهای قبلی معرفی شده بود. کد شروع برای این کد لبه دارای ماژول های شبکه، رابط کاربری، حافظه پنهان آفلاین و ماژول های مخزن است. میتوانید با استفاده از WorkManager روی زمانبندی کار پسزمینه تمرکز کنید.
- در Android Studio، همه بسته ها را گسترش دهید.
-  بسته databaseکاوش کنید. این بسته شامل موجودیت های پایگاه داده و پایگاه داده محلی است که با استفاده ازRoomپیاده سازی می شود.
-  بسته repositoryرا کاوش کنید. این بسته حاوی کلاسVideosRepositoryاست که لایه داده را از بقیه برنامه انتزاعی می کند.
- بقیه کدهای شروع را خودتان و با کمک کدهای قبلی کاوش کنید.
 WorkManager یکی از اجزای معماری اندروید و بخشی از Android Jetpack است. WorkManager برای کارهای پس زمینه ای است که قابل تعویق هستند و به اجرای تضمینی نیاز دارند:
- معوق به این معنی است که کار نیازی به اجرای فوری ندارد. به عنوان مثال، ارسال داده های تحلیلی به سرور یا همگام سازی پایگاه داده در پس زمینه کاری است که می توان آن را به تعویق انداخت.
- اجرای تضمینی به این معنی است که حتی در صورت خروج برنامه یا راه اندازی مجدد دستگاه، کار اجرا می شود.

 در حالی که WorkManager کار پسزمینه را اجرا میکند، از مسائل مربوط به سازگاری و بهترین روشها برای سلامت باتری و سیستم مراقبت میکند. WorkManager سازگاری را به سطح API 14 ارائه می دهد. WorkManager بسته به سطح API دستگاه، روش مناسبی را برای برنامه ریزی یک کار پس زمینه انتخاب می کند. ممکن است از JobScheduler (در API 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برای پیکربندی نحوه و زمان اجرای task worker با کمکConstraintsمانند دستگاه متصل یا Wi-Fi متصل استفاده کنید. شماWorkRequestدر کار بعدی پیاده سازی می کنید.
-  WorkManager
 این کلاسWorkRequestشما را برنامه ریزی و اجرا می کند.WorkManagerدرخواستهای کاری را به گونهای برنامهریزی میکند که بار روی منابع سیستم پخش شود، در حالی که محدودیتهایی را که شما مشخص کردهاید رعایت میکند. شماWorkManagerدر کار بعدی پیاده سازی می کنید.
مرحله 1: یک کارگر ایجاد کنید
 در این کار، یک Worker اضافه میکنید تا لیست پخش ویدیوی DevBytes را از قبل در پسزمینه واکشی کند.
-  در داخل بسته devbyteviewerیک بسته جدید به نامworkایجاد کنید.
-  در بسته work، یک کلاس Kotlin جدید به نامRefreshDataWorkerایجاد کنید.
-  کلاس RefreshDataWorkerاز کلاسCoroutineWorkerگسترش دهید. پاس درcontextوWorkerParametersبه عنوان پارامترهای سازنده.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}-  برای رفع خطای کلاس انتزاعی، متد doWork()در کلاسRefreshDataWorkerلغو کنید.
override suspend fun doWork(): Result {
  return Result.success()
}یک تابع تعلیق عملکردی است که می تواند متوقف شود و بعداً از سر گرفته شود. یک تابع تعلیق می تواند یک عملیات طولانی در حال اجرا را اجرا کند و منتظر بماند تا بدون مسدود کردن رشته اصلی، کامل شود.
مرحله 2: اجرای doWork()
 متد doWork() در داخل کلاس Worker روی یک رشته پس زمینه فراخوانی می شود. این روش کار را به صورت همزمان انجام می دهد و باید یک شی ListenableWorker.Result را برگرداند. سیستم اندروید حداکثر 10 دقیقه به Worker فرصت می دهد تا اجرای خود را تمام کند و یک شی ListenableWorker.Result را برگرداند. پس از اتمام این زمان، سیستم به شدت Worker متوقف می کند.
 برای ایجاد یک شی ListenableWorker.Result ، یکی از روش های ثابت زیر را برای نشان دادن وضعیت تکمیل کار پس زمینه فراخوانی کنید:
-  Result.success()- کار با موفقیت انجام شد.
-  Result.failure()- کار با شکست دائمی کامل شد.
-  Result.retry()- کار با یک شکست گذرا مواجه شد و باید دوباره امتحان شود.
 در این کار، شما متد doWork() را برای واکشی لیست پخش ویدیوی DevBytes از شبکه پیاده سازی می کنید. می توانید از روش های موجود در کلاس VideosRepository برای بازیابی داده ها از شبکه استفاده مجدد کنید.
-  در کلاس RefreshDataWorker، در داخلdoWork()یک شیVideosDatabaseو یک شیVideosRepositoryایجاد و نمونه سازی کنید.
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)
   return Result.success()
}-  در کلاس RefreshDataWorker، در داخلdoWork()در بالای دستورreturn، متدrefreshVideos()را در داخل یک بلوکtryفراخوانی کنید. یک گزارش برای ردیابی زمانی که کارگر اجرا می شود اضافه کنید.
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 برای اجرای worker که در کار قبلی ایجاد کردهاید، تعریف و زمانبندی میکنید. 
مرحله 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: یک WorkRequest با WorkManager برنامه ریزی کنید
 پس از اینکه WorkRequest خود را تعریف کردید، می توانید آن را با WorkManager ، با استفاده از متد enqueueUniquePeriodicWork() زمان بندی کنید. این روش به شما امکان می دهد یک PeriodicWorkRequest با نام منحصر به فرد را به صف اضافه کنید، جایی که فقط یک PeriodicWorkRequest از یک نام خاص می تواند در هر زمان فعال باشد.
برای مثال، ممکن است بخواهید فقط یک عملیات همگام سازی فعال باشد. اگر یک عملیات همگامسازی در حال تعلیق است، میتوانید با استفاده از یک ExistingPeriodicWorkPolicy ، اجازه دهید اجرا شود یا آن را با کار جدیدتان جایگزین کنید.
 برای کسب اطلاعات بیشتر در مورد روشهای زمانبندی WorkRequest ، به مستندات WorkManager مراجعه کنید.
-  در کلاس RefreshDataWorker، در ابتدای کلاس، یک شیء همراه اضافه کنید. یک نام کار برای شناسایی منحصر به فرد این کارگر تعریف کنید.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}-  در کلاس DevByteApplication، در انتهای متدsetupRecurringWork()، کار را با استفاده از متدenqueueUniquePeriodicWork()زمانبندی کنید. از فهرستKEEPبرای ExistingPeriodicWorkPolicy عبور دهید. به عنوان پارامتر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، یک متد جدید به نامdelayedInit()اضافه کنید تا یک Coroutine شروع شود.
private fun delayedInit() {
   applicationScope.launch {
   }
}-  در متد delayedInit()setupRecurringWork()فراخوانی کنید.
-  مقداردهی اولیه Timber را از متد onCreate()به متدdelayedInit()منتقل کنید.
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}-  در کلاس DevByteApplication، در انتهای متدonCreate()یک فراخوانی به متدdelayedInit()اضافه کنید.
override fun onCreate() {
   super.onCreate()
   delayedInit()
}-  پنجره Logcat را در پایین پنجره Android Studio باز کنید. در RefreshDataWorkerفیلتر کنید.
-  برنامه را اجرا کنید. WorkManagerکارهای تکراری شما را فوراً برنامه ریزی می کند.
 در پانل Logcat ، به عبارات گزارشی توجه کنید که نشان می دهد درخواست کار برنامه ریزی شده است، سپس با موفقیت اجرا می شود.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
گزارش WM-WorkerWrapper از کتابخانه WorkManager نمایش داده می شود، بنابراین نمی توانید این پیام گزارش را تغییر دهید. 
مرحله 3: (اختیاری) WorkRequest را برای حداقل فاصله زمانی برنامه ریزی کنید
در این مرحله فاصله زمانی را از 1 روز به 15 دقیقه کاهش می دهید. شما این کار را انجام می دهید تا بتوانید گزارش های مربوط به درخواست کار دوره ای را در عمل مشاهده کنید.
-  در کلاس DevByteApplication، در متدsetupRecurringWork()، تعریفrepeatingRequestفعلی را نظر دهید. یک درخواست کاری جدید با فاصله تکرار دوره ای15دقیقه اضافه کنید.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()-  پنجره Logcat را در Android Studio باز کنید و روی RefreshDataWorkerفیلتر کنید. برای پاک کردن گزارشهای قبلی، روی نماد Clear logcat کلیک کنید . .
-  برنامه را اجرا کنید و WorkManagerفوراً کارهای تکراری شما را برنامه ریزی می کند. در صفحه Logcat ، به گزارشها توجه کنید—درخواست کاری هر 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 باید اجرا شود مشخص کنید. به عنوان مثال، ممکن است بخواهید مشخص کنید که کار فقط زمانی اجرا شود که دستگاه بیکار است، یا فقط زمانی که دستگاه به برق وصل است و به Wi-Fi متصل است. همچنین می توانید یک خط مشی عقب نشینی برای تلاش مجدد کار مشخص کنید. محدودیت های پشتیبانی شده متدهای مجموعه در Constraints.Builder هستند. برای کسب اطلاعات بیشتر، به تعریف درخواست های کاری خود مراجعه کنید.
مرحله 1: یک شی Constraints اضافه کنید و یک محدودیت را تنظیم کنید
 در این مرحله، یک شی Constraints ایجاد میکنید و یک محدودیت بر روی شی تعیین میکنید، یک محدودیت از نوع شبکه. (توجه به گزارشها تنها با یک محدودیت آسانتر است. در مرحله بعد، محدودیتهای دیگری را اضافه میکنید.)
-  در کلاس DevByteApplication، در ابتدایsetupRecurringWork()یکvalاز نوعConstraintsتعریف کنید. از متدConstraints.Builder()استفاده کنید.
val constraints = Constraints.Builder()برای رفع خطا، androidx.work.Constraints را وارد کنید.
-  از متد setRequiredNetworkType()برای اضافه کردن یک محدودیت از نوع شبکه به شیءconstraintsاستفاده کنید. از شمارهUNMETEREDاستفاده کنید تا درخواست کار فقط زمانی اجرا شود که دستگاه در یک شبکه بدون اندازهگیری باشد.
.setRequiredNetworkType(NetworkType.UNMETERED)-  از متد build()برای ایجاد محدودیت ها از سازنده استفاده کنید.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()اکنون باید شی Constraints جدید ایجاد شده را روی درخواست کاری تنظیم کنید.
-  در کلاس DevByteApplication، در داخل متدsetupRecurringWork()، شیConstraintsرا روی درخواست کار دوره ای،repeatingRequestقرار دهید. برای تنظیم محدودیت ها، متدsetConstraints()را بالای فراخوانی متدbuild()اضافه کنید.
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()مرحله 2: برنامه را اجرا کنید و به گزارش ها توجه کنید
در این مرحله، برنامه را اجرا میکنید و متوجه میشوید که درخواست کاری محدود در پسزمینه در فواصل زمانی اجرا میشود.
- برنامه را از دستگاه یا شبیه ساز حذف نصب کنید تا کارهای برنامه ریزی شده قبلی لغو شود.
-  پنجره Logcat را در اندروید استودیو باز کنید. در قسمت 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()استفاده کنید. این محدودیت فقط زمانی درخواست کار را اجرا می کند که کاربر به طور فعال از دستگاه استفاده نمی کند. این ویژگی فقط در اندروید 6.0 (مارشملو) و بالاتر موجود است، بنابراین یک شرط برای 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 کار را برنامه ریزی و اجرا می کند و منابع سیستم را بهینه می کند. کاربران و باتری های آنها بسیار خوشحال خواهند شد.
پروژه Android Studio: DevBytesWorkManager .
-  WorkManagerAPI برنامه ریزی کارهای ناهمزمان و قابل تعویق را که باید به طور قابل اعتماد اجرا شوند را آسان می کند.
-  اکثر برنامه های دنیای واقعی نیاز به انجام کارهای پس زمینه طولانی مدت دارند. برای برنامه ریزی یک کار پس زمینه به روشی بهینه و کارآمد، از WorkManagerاستفاده کنید.
-  The main classes in the WorkManagerlibrary areWorker,WorkRequest, andWorkManager.
-  طبقه Workerنشان دهنده یک واحد کار است. برای پیاده سازی کار پس زمینه، کلاسWorkerرا گسترش دهید و متدdoWork()لغو کنید.
-  کلاس WorkRequestیک درخواست برای انجام یک واحد کار را نشان می دهد.WorkRequestکلاس پایه برای تعیین پارامترهای کاری است که درWorkManagerبرنامه ریزی می کنید.
-  دو پیاده سازی مشخص از کلاس WorkRequestوجود دارد:OneTimeWorkRequestبرای وظایف یکباره، وPeriodicWorkRequestبرای درخواست های کاری دوره ای.
-  هنگام تعریف WorkRequest، میتوانیدConstraintsمشخص کنید که نشان میدهدWorkerچه زمانی باید اجرا شود. محدودیت ها شامل مواردی مانند وصل بودن دستگاه، بیکار بودن دستگاه یا وصل بودن Wi-Fi می شود.
-  برای افزودن محدودیتها به WorkRequest، از روشهای مجموعه فهرست شده در اسنادConstraints.Builderاستفاده کنید. به عنوان مثال، برای نشان دادن اینکهWorkRequestنباید در صورت کم بودن باتری دستگاه اجرا شود، از متدsetRequiresBatteryNotLow()استفاده کنید.
-  پس از تعریف WorkRequest، کار را به سیستم اندروید بسپارید. برای انجام این کار، کار را با استفاده از یکی از متدهایenqueueWorkManagerزمان بندی کنید.
-  زمان دقیق اجرای Workerبه محدودیتهایی که درWorkRequestاستفاده میشود و بهینهسازی سیستم بستگی دارد.WorkManagerبرای ارائه بهترین رفتار ممکن با توجه به این محدودیت ها طراحی شده است.
دوره بی ادبی:
مستندات توسعه دهنده اندروید:
دیگر:
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، کار میکنند، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است، محول کنند.
اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
سوال 1
 پیاده سازی های مشخص کلاس WorkRequest چیست؟
 ▢ OneTimeWorkPeriodicRequest Request
 ▢ OneTimeWorkRequest و PeriodicWorkRequest
 ▢ OneTimeWorkRequest و RecurringWorkRequest
 ▢ OneTimeOffWorkRequest و RecurringWorkRequest
سوال 2
 WorkManager از کدام یک از کلاسهای زیر برای زمانبندی کار پسزمینه در API 23 و بالاتر استفاده میکند؟
 ▢ فقط JobScheduler
 ▢ BroadcastReceiver و AlarmManager
 ▢ AlarmManager و JobScheduler
 ▢ Scheduler و BroadcastReceiver
سوال 3
 از کدام API برای اضافه کردن محدودیتها به WorkRequest استفاده میکنید؟
 ▢ setConstraints()
 ▢ addConstraints()
 ▢ setConstraint()
 ▢ addConstraintsToWorkRequest()
 شروع به درس بعدی: 
برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبههای کد پایه Android Kotlin Fundamentals مراجعه کنید.