Android Kotlin Fundamentals 09.2: WorkManager

این کد لبه بخشی از دوره آموزشی 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 و Room Android Architecture Components.
  • نحوه انجام تبدیل در کلاس LiveData .
  • نحوه ساخت و راه اندازی یک کوروتین
  • نحوه استفاده از آداپتورهای اتصال در اتصال داده
  • نحوه بارگیری داده های کش با استفاده از الگوی مخزن.

چیزی که یاد خواهید گرفت

  • نحوه ایجاد یک Worker که نشان دهنده یک واحد کار است.
  • نحوه ایجاد WorkRequest برای درخواست انجام کار.
  • نحوه اضافه کردن محدودیت‌ها به WorkRequest برای تعریف نحوه و زمان اجرای یک کارگر.
  • نحوه استفاده از WorkManager برای برنامه ریزی وظایف پس زمینه.

کاری که خواهی کرد

  • یک کارگر برای اجرای یک کار پس زمینه برای واکشی از قبل لیست پخش ویدیوی DevBytes از شبکه ایجاد کنید.
  • کارگر را برنامه ریزی کنید تا به صورت دوره ای کار کند.
  • محدودیت هایی را به WorkRequest اضافه کنید.
  • یک WorkRequest دوره ای را برنامه ریزی کنید که یک بار در روز اجرا می شود.

در این کد لبه، شما روی برنامه DevBytes که در یک کد لبه قبلی توسعه داده اید کار می کنید. (اگر این برنامه را ندارید، می توانید کد شروع این درس را دانلود کنید.)

برنامه DevBytes لیستی از ویدیوهای DevByte را نمایش می دهد که آموزش های کوتاهی توسط تیم ارتباط با توسعه دهندگان Google Android ساخته شده است. این ویدیوها ویژگی‌های توسعه‌دهنده و بهترین شیوه‌های توسعه اندروید را معرفی می‌کنند.

با واکشی از قبل ویدیوها یک بار در روز، تجربه کاربری را در برنامه افزایش می دهید. این تضمین می کند که کاربر به محض باز کردن برنامه، محتوای تازه دریافت می کند.

در این کار کد شروع را دانلود و بررسی می کنید.

مرحله 1: برنامه شروع را دانلود و اجرا کنید

می‌توانید از طریق برنامه DevBytes که در Codelab قبلی ساخته‌اید، به کار خود ادامه دهید (اگر آن را دارید). یا می توانید برنامه شروع را دانلود کنید.

در این کار شما اپلیکیشن استارتر را دانلود و اجرا می کنید و کد استارتر را بررسی می کنید.

  1. اگر قبلاً برنامه DevBytes را ندارید، کد شروع DevBytes را برای این Codelab از پروژه DevBytesRepository از GitHub دانلود کنید.
  2. کد را از حالت فشرده خارج کرده و پروژه را در اندروید استودیو باز کنید.
  3. دستگاه آزمایشی یا شبیه ساز خود را به اینترنت وصل کنید، اگر قبلاً متصل نیست. برنامه را بسازید و اجرا کنید. این برنامه لیستی از ویدیوهای DevByte را از شبکه دریافت می کند و آنها را نمایش می دهد.
  4. در برنامه، روی هر ویدیویی ضربه بزنید تا در برنامه YouTube باز شود.

مرحله 2: کد را کاوش کنید

برنامه استارتر دارای کدهای زیادی است که در کدهای قبلی معرفی شده بود. کد شروع برای این کد لبه دارای ماژول های شبکه، رابط کاربری، حافظه پنهان آفلاین و ماژول های مخزن است. می‌توانید با استفاده از WorkManager روی زمان‌بندی کار پس‌زمینه تمرکز کنید.

  1. در Android Studio، همه بسته ها را گسترش دهید.
  2. بسته database کاوش کنید. این بسته شامل موجودیت های پایگاه داده و پایگاه داده محلی است که با استفاده از Room پیاده سازی می شود.
  3. بسته repository را کاوش کنید. این بسته حاوی کلاس VideosRepository است که لایه داده را از بقیه برنامه انتزاعی می کند.
  4. بقیه کدهای شروع را خودتان و با کمک کدهای قبلی کاوش کنید.

WorkManager یکی از اجزای معماری اندروید و بخشی از Android Jetpack است. WorkManager برای کارهای پس زمینه ای است که قابل تعویق هستند و به اجرای تضمینی نیاز دارند:

  • معوق به این معنی است که کار نیازی به اجرای فوری ندارد. به عنوان مثال، ارسال داده های تحلیلی به سرور یا همگام سازی پایگاه داده در پس زمینه کاری است که می توان آن را به تعویق انداخت.
  • اجرای تضمینی به این معنی است که حتی در صورت خروج برنامه یا راه اندازی مجدد دستگاه، کار اجرا می شود.

در حالی که WorkManager کار پس‌زمینه را اجرا می‌کند، از مسائل مربوط به سازگاری و بهترین روش‌ها برای سلامت باتری و سیستم مراقبت می‌کند. WorkManager سازگاری را به سطح API 14 ارائه می دهد. WorkManager بسته به سطح API دستگاه، روش مناسبی را برای برنامه ریزی یک کار پس زمینه انتخاب می کند. ممکن است از JobScheduler (در API 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 برای پیکربندی نحوه و زمان اجرای task worker با کمک Constraints مانند دستگاه متصل یا Wi-Fi متصل استفاده کنید. شما WorkRequest در کار بعدی پیاده سازی می کنید.
  • WorkManager
    این کلاس WorkRequest شما را برنامه ریزی و اجرا می کند. WorkManager درخواست‌های کاری را به گونه‌ای برنامه‌ریزی می‌کند که بار روی منابع سیستم پخش شود، در حالی که محدودیت‌هایی را که شما مشخص کرده‌اید رعایت می‌کند. شما WorkManager در کار بعدی پیاده سازی می کنید.

مرحله 1: یک کارگر ایجاد کنید

در این کار، یک Worker اضافه می‌کنید تا لیست پخش ویدیوی DevBytes را از قبل در پس‌زمینه واکشی کند.

  1. در داخل بسته devbyteviewer یک بسته جدید به نام work ایجاد کنید.
  2. در بسته work ، یک کلاس Kotlin جدید به نام RefreshDataWorker ایجاد کنید.
  3. کلاس RefreshDataWorker از کلاس CoroutineWorker گسترش دهید. پاس در context و WorkerParameters به عنوان پارامترهای سازنده.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}
  1. برای رفع خطای کلاس انتزاعی، متد 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 برای بازیابی داده ها از شبکه استفاده مجدد کنید.

  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 ، متد refreshVideos() را در داخل یک بلوک try فراخوانی کنید. یک گزارش برای ردیابی زمانی که کارگر اجرا می شود اضافه کنید.
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 برای اجرای worker که در کار قبلی ایجاد کرده‌اید، تعریف و زمان‌بندی می‌کنید.

مرحله 1: کار تکراری را تنظیم کنید

در یک برنامه اندروید، کلاس 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 که در کار قبلی ایجاد کردید، عبور کنید. در یک بازه تکرار 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 مراجعه کنید.

  1. در کلاس RefreshDataWorker ، در ابتدای کلاس، یک شیء همراه اضافه کنید. یک نام کار برای شناسایی منحصر به فرد این کارگر تعریف کنید.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
  1. در کلاس DevByteApplication ، در انتهای متد setupRecurringWork() ، کار را با استفاده از متد enqueueUniquePeriodicWork() زمان‌بندی کنید. از فهرست KEEP برای ExistingPeriodicWorkPolicy عبور دهید. به عنوان پارامتر 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() اضافه کنید تا یک Coroutine شروع شود.
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. پنجره Logcat را در پایین پنجره Android Studio باز کنید. در RefreshDataWorker فیلتر کنید.
  2. برنامه را اجرا کنید. 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 دقیقه کاهش می دهید. شما این کار را انجام می دهید تا بتوانید گزارش های مربوط به درخواست کار دوره ای را در عمل مشاهده کنید.

  1. در کلاس DevByteApplication ، در متد setupRecurringWork() ، تعریف repeatingRequest فعلی را نظر دهید. یک درخواست کاری جدید با فاصله تکرار دوره ای 15 دقیقه اضافه کنید.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()
  1. پنجره Logcat را در Android Studio باز کنید و روی RefreshDataWorker فیلتر کنید. برای پاک کردن گزارش‌های قبلی، روی نماد Clear logcat کلیک کنید .
  2. برنامه را اجرا کنید و 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 ایجاد می‌کنید و یک محدودیت بر روی شی تعیین می‌کنید، یک محدودیت از نوع شبکه. (توجه به گزارش‌ها تنها با یک محدودیت آسان‌تر است. در مرحله بعد، محدودیت‌های دیگری را اضافه می‌کنید.)

  1. در کلاس DevByteApplication ، در ابتدای setupRecurringWork() یک val از نوع Constraints تعریف کنید. از متد Constraints.Builder() استفاده کنید.
val constraints = Constraints.Builder()

برای رفع خطا، androidx.work.Constraints را وارد کنید.

  1. از متد setRequiredNetworkType() برای اضافه کردن یک محدودیت از نوع شبکه به شیء constraints استفاده کنید. از شماره UNMETERED استفاده کنید تا درخواست کار فقط زمانی اجرا شود که دستگاه در یک شبکه بدون اندازه‌گیری باشد.
.setRequiredNetworkType(NetworkType.UNMETERED)
  1. از متد build() برای ایجاد محدودیت ها از سازنده استفاده کنید.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()

اکنون باید شی Constraints جدید ایجاد شده را روی درخواست کاری تنظیم کنید.

  1. در کلاس DevByteApplication ، در داخل متد setupRecurringWork() ، شی Constraints را روی درخواست کار دوره ای، repeatingRequest قرار دهید. برای تنظیم محدودیت ها، متد setConstraints() را بالای فراخوانی متد build() اضافه کنید.
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()

مرحله 2: برنامه را اجرا کنید و به گزارش ها توجه کنید

در این مرحله، برنامه را اجرا می‌کنید و متوجه می‌شوید که درخواست کاری محدود در پس‌زمینه در فواصل زمانی اجرا می‌شود.

  1. برنامه را از دستگاه یا شبیه ساز حذف نصب کنید تا کارهای برنامه ریزی شده قبلی لغو شود.
  2. پنجره Logcat را در اندروید استودیو باز کنید. در قسمت Logcat ، با کلیک بر روی نماد Clear logcat ، گزارش های قبلی را پاک کنید در سمت چپ فیلتر در work
  3. Wi-Fi را در دستگاه یا شبیه ساز خاموش کنید تا بتوانید نحوه عملکرد محدودیت ها را ببینید. کد فعلی فقط یک محدودیت را تعیین می کند که نشان می دهد درخواست فقط باید در یک شبکه بدون اندازه گیری اجرا شود. از آنجایی که Wi-Fi خاموش است، دستگاه به شبکه متصل نیست، اندازه گیری شده یا بدون متر است. بنابراین، این محدودیت برآورده نخواهد شد.
  4. برنامه را اجرا کنید و به صفحه Logcat توجه کنید. WorkManager کار پس‌زمینه را فوراً زمان‌بندی می‌کند. از آنجا که محدودیت شبکه برآورده نمی شود، وظیفه اجرا نمی شود.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
  1. 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 پیاده سازی کنید.

  1. در کلاس DevByteApplication ، در متد setupRecurringWork() ، نشان دهید که درخواست کاری باید فقط در صورتی اجرا شود که باتری کم نباشد. قبل از فراخوانی متد build() محدودیت را اضافه کنید و از متد setRequiresBatteryNotLow() استفاده کنید.
.setRequiresBatteryNotLow(true)
  1. درخواست کار را به‌روزرسانی کنید تا فقط زمانی که دستگاه در حال شارژ شدن است اجرا شود. قبل از فراخوانی متد build() محدودیت را اضافه کنید و از متد setRequiresCharging() استفاده کنید.
.setRequiresCharging(true)
  1. درخواست کار را به‌روزرسانی کنید تا فقط زمانی که دستگاه غیرفعال است اجرا شود. قبل از فراخوانی متد 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()
  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 API برنامه ریزی کارهای ناهمزمان و قابل تعویق را که باید به طور قابل اعتماد اجرا شوند را آسان می کند.
  • اکثر برنامه های دنیای واقعی نیاز به انجام کارهای پس زمینه طولانی مدت دارند. برای برنامه ریزی یک کار پس زمینه به روشی بهینه و کارآمد، از WorkManager استفاده کنید.
  • The main classes in the WorkManager library are Worker , WorkRequest , and WorkManager .
  • طبقه Worker نشان دهنده یک واحد کار است. برای پیاده سازی کار پس زمینه، کلاس Worker را گسترش دهید و متد doWork() لغو کنید.
  • کلاس WorkRequest یک درخواست برای انجام یک واحد کار را نشان می دهد. WorkRequest کلاس پایه برای تعیین پارامترهای کاری است که در WorkManager برنامه ریزی می کنید.
  • دو پیاده سازی مشخص از کلاس WorkRequest وجود دارد: OneTimeWorkRequest برای وظایف یکباره، و PeriodicWorkRequest برای درخواست های کاری دوره ای.
  • هنگام تعریف WorkRequest ، می‌توانید Constraints مشخص کنید که نشان می‌دهد Worker چه زمانی باید اجرا شود. محدودیت ها شامل مواردی مانند وصل بودن دستگاه، بیکار بودن دستگاه یا وصل بودن Wi-Fi می شود.
  • برای افزودن محدودیت‌ها به WorkRequest ، از روش‌های مجموعه فهرست شده در اسناد Constraints.Builder استفاده کنید. به عنوان مثال، برای نشان دادن اینکه WorkRequest نباید در صورت کم بودن باتری دستگاه اجرا شود، از متد setRequiresBatteryNotLow() استفاده کنید.
  • پس از تعریف WorkRequest ، کار را به سیستم اندروید بسپارید. برای انجام این کار، کار را با استفاده از یکی از متدهای enqueue WorkManager زمان بندی کنید.
  • زمان دقیق اجرای 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()

شروع به درس بعدی: 10.1 سبک ها و تم ها

برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبه‌های کد پایه Android Kotlin Fundamentals مراجعه کنید.