WorkManager کتابخانه ای برای زمان بندی و اجرای کارهای پس زمینه قابل تعویق در اندروید است. این جایگزین پیشنهادی برای Firebase JobDispatcher است. راهنمای زیر شما را در فرآیند انتقال پیادهسازی Firebase JobDispatcher به WorkManager راهنمایی میکند.
راه اندازی Gradle
برای وارد کردن کتابخانه WorkManager به پروژه Android خود، وابستگیهای فهرست شده در شروع با WorkManager را اضافه کنید.
از JobService تا کارگران
FirebaseJobDispatcher
از یک زیر کلاس JobService
به عنوان نقطه ورودی برای تعریف کاری که باید انجام شود استفاده می کند. ممکن است به طور مستقیم JobService
یا از SimpleJobService
استفاده کنید.
JobService
چیزی شبیه به این خواهد بود:
کاتلین
import com.firebase.jobdispatcher.JobParameters import com.firebase.jobdispatcher.JobService class MyJobService : JobService() { override fun onStartJob(job: JobParameters): Boolean { // Do some work here return false // Answers the question: "Is there still work going on?" } override fun onStopJob(job: JobParameters): Boolean { return false // Answers the question: "Should this job be retried?" } }
جاوا
import com.firebase.jobdispatcher.JobParameters; import com.firebase.jobdispatcher.JobService; public class MyJobService extends JobService { @Override public boolean onStartJob(JobParameters job) { // Do some work here return false; // Answers the question: "Is there still work going on?" } @Override public boolean onStopJob(JobParameters job) { return false; // Answers the question: "Should this job be retried?" } }
اگر از SimpleJobService
استفاده می کنید onRunJob()
باطل کرده اید که یک نوع @JobResult int
را برمی گرداند.
تفاوت اصلی این است که وقتی مستقیماً از JobService
استفاده می کنید، onStartJob()
در رشته اصلی فراخوانی می شود و این وظیفه برنامه است که کار را در یک رشته پس زمینه بارگذاری کند. از طرف دیگر، اگر از SimpleJobService
استفاده می کنید، آن سرویس وظیفه اجرای کار شما را بر روی یک رشته پس زمینه دارد.
WorkManager مفاهیم مشابهی دارد. واحد اساسی کار در WorkManager یک ListenableWorker
است. همچنین زیرشاخههای مفید دیگری از کارگران مانند Worker
، RxWorker
، و CoroutineWorker
(هنگام استفاده از کوروتینهای Kotlin) وجود دارد.
JobService به یک ListenableWorker نگاشت می شود
اگر مستقیماً از JobService
استفاده میکنید، کارگری که به آن نقشهبرداری میکند ListenableWorker
است. اگر از SimpleJobService
استفاده می کنید، به جای آن باید از Worker
استفاده کنید.
بیایید از مثال بالا ( MyJobService
) استفاده کنیم و ببینیم چگونه می توانیم آن را به ListenableWorker
تبدیل کنیم.
کاتلین
import android.content.Context import androidx.work.ListenableWorker import androidx.work.ListenableWorker.Result import androidx.work.WorkerParameters import com.google.common.util.concurrent.ListenableFuture class MyWorker(appContext: Context, params: WorkerParameters) : ListenableWorker(appContext, params) { override fun startWork(): ListenableFuture<ListenableWorker.Result> { // Do your work here. TODO("Return a ListenableFuture<Result>") } override fun onStopped() { // Cleanup because you are being stopped. } }
جاوا
import android.content.Context; import androidx.work.ListenableWorker; import androidx.work.ListenableWorker.Result; import androidx.work.WorkerParameters; import com.google.common.util.concurrent.ListenableFuture; class MyWorker extends ListenableWorker { public MyWorker(@NonNull Context appContext, @NonNull WorkerParameters params) { super(appContext, params); } @Override public ListenableFuture<ListenableWorker.Result> startWork() { // Do your work here. Data input = getInputData(); // Return a ListenableFuture<> } @Override public void onStopped() { // Cleanup because you are being stopped. } }
واحد اصلی کار در WorkManager یک ListenableWorker
است. درست مانند JobService.onStartJob()
، startWork()
در رشته اصلی فراخوانی می شود. در اینجا MyWorker
ListenableWorker
را پیادهسازی میکند و نمونهای از ListenableFuture
را برمیگرداند، که برای سیگنال دادن به اتمام کار به صورت ناهمزمان استفاده میشود. شما باید استراتژی threading خود را در اینجا انتخاب کنید.
ListenableFuture
در اینجا در نهایت یک نوع ListenableWorker.Result
را برمی گرداند که می تواند یکی از Result.success()
, Result.success(Data outputData)
Result.retry()
, Result.failure()
یا Result.failure(Data outputData)
باشد. برای اطلاعات بیشتر، صفحه مرجع ListenableWorker.Result
را ببینید.
onStopped()
فراخوانی می شود تا سیگنالی باشد که ListenableWorker
باید متوقف شود، یا به این دلیل که محدودیت ها دیگر برآورده نمی شوند (مثلاً به دلیل اینکه شبکه دیگر در دسترس نیست)، یا به این دلیل که متد WorkManager.cancel…()
فراخوانی شده است. اگر سیستم عامل به دلایلی تصمیم بگیرد کار شما را خاموش کند onStopped()
نیز ممکن است فراخوانی شود.
SimpleJobService به یک Worker نقشه میدهد
هنگام استفاده از SimpleJobService
، کارگر فوق به شکل زیر خواهد بود:
کاتلین
import android.content.Context; import androidx.work.Data; import androidx.work.ListenableWorker.Result; import androidx.work.Worker; import androidx.work.WorkerParameters; class MyWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { TODO("Return a Result") } override fun onStopped() { super.onStopped() TODO("Cleanup, because you are being stopped") } }
جاوا
import android.content.Context; import androidx.work.Data; import androidx.work.ListenableWorker.Result; import androidx.work.Worker; import androidx.work.WorkerParameters; class MyWorker extends Worker { public MyWorker(@NonNull Context appContext, @NonNull WorkerParameters params) { super(appContext, params); } @Override public Result doWork() { // Do your work here. Data input = getInputData(); // Return a ListenableWorker.Result Data outputData = new Data.Builder() .putString(“Key”, “value”) .build(); return Result.success(outputData); } @Override public void onStopped() { // Cleanup because you are being stopped. } }
در اینجا doWork()
نمونهای از ListenableWorker.Result
را به سیگنال تکمیل کار همزمان برمیگرداند. این شبیه به SimpleJobService
است که کارها را در یک رشته پسزمینه زمانبندی میکند.
نقشه های JobBuilder به WorkRequest
FirebaseJobBuilder از Job.Builder
برای نمایش فراداده Job
استفاده می کند. WorkManager از WorkRequest
برای پر کردن این نقش استفاده می کند.
WorkManager دو نوع WorkRequest
دارد: OneTimeWorkRequest
و PeriodicWorkRequest
.
اگر در حال حاضر از Job.Builder.setRecurring(true)
استفاده می کنید، باید یک PeriodicWorkRequest
جدید ایجاد کنید. در غیر این صورت، باید از OneTimeWorkRequest
استفاده کنید.
بیایید ببینیم برنامه ریزی یک Job
پیچیده با FirebaseJobDispatcher
چگونه ممکن است به نظر برسد:
کاتلین
val input: Bundle = Bundle().apply { putString("some_key", "some_value") } val job = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyService::class.java) // uniquely identifies the job .setTag("my-unique-tag") // one-off job .setRecurring(false) // don't persist past a device reboot .setLifetime(Lifetime.UNTIL_NEXT_BOOT) // start between 0 and 60 seconds from now .setTrigger(Trigger.executionWindow(0, 60)) // don't overwrite an existing job with the same tag .setReplaceCurrent(false) // retry with exponential backoff .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) .setConstraints( // only run on an unmetered network Constraint.ON_UNMETERED_NETWORK, // // only run when the device is charging Constraint.DEVICE_CHARGING ) .setExtras(input) .build() dispatcher.mustSchedule(job)
جاوا
Bundle input = new Bundle(); input.putString("some_key", "some_value"); Job myJob = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyJobService.class) // uniquely identifies the job .setTag("my-unique-tag") // one-off job .setRecurring(false) // don't persist past a device reboot .setLifetime(Lifetime.UNTIL_NEXT_BOOT) // start between 0 and 60 seconds from now .setTrigger(Trigger.executionWindow(0, 60)) // don't overwrite an existing job with the same tag .setReplaceCurrent(false) // retry with exponential backoff .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) // constraints that need to be satisfied for the job to run .setConstraints( // only run on an unmetered network Constraint.ON_UNMETERED_NETWORK, // only run when the device is charging Constraint.DEVICE_CHARGING ) .setExtras(input) .build(); dispatcher.mustSchedule(myJob);
برای رسیدن به همان کار با WorkManager باید:
- ایجاد داده های ورودی که می تواند به عنوان ورودی برای
Worker
استفاده شود. - یک
WorkRequest
با داده های ورودی و محدودیت هایی مشابه مواردی که در بالا برایFirebaseJobDispatcher
تعریف شده است بسازید. -
WorkRequest
در نوبت قرار دهید.
تنظیم ورودی ها برای Worker
FirebaseJobDispatcher
از یک Bundle
برای ارسال داده های ورودی به JobService
استفاده می کند. WorkManager به جای آن Data
استفاده می کند. بنابراین تبدیل می شود:
کاتلین
import androidx.work.workDataOf val data = workDataOf("some_key" to "some_val")
جاوا
import androidx.work.Data; Data input = new Data.Builder() .putString("some_key", "some_value") .build();
تنظیم محدودیت ها برای کارگر
FirebaseJobDispatcher
از Job.Builder.setConstaints(...)
برای تنظیم محدودیتها در کارها استفاده میکند. WorkManager به جای آن از Constraints
استفاده می کند.
کاتلین
import androidx.work.* val constraints: Constraints = Constraints.Builder().apply { setRequiredNetworkType(NetworkType.CONNECTED) setRequiresCharging(true) }.build()
جاوا
import androidx.work.Constraints; import androidx.work.Constraints.Builder; import androidx.work.NetworkType; Constraints constraints = new Constraints.Builder() // The Worker needs Network connectivity .setRequiredNetworkType(NetworkType.CONNECTED) // Needs the device to be charging .setRequiresCharging(true) .build();
ایجاد WorkRequest (یک بار یا دوره ای)
برای ایجاد OneTimeWorkRequest
و PeriodicWorkRequest
باید از OneTimeWorkRequest.Builder
و PeriodicWorkRequest.Builder
استفاده کنید.
برای ایجاد OneTimeWorkRequest
که مشابه Job
فوق است، باید موارد زیر را انجام دهید:
کاتلین
import androidx.work.* import java.util.concurrent.TimeUnit val constraints: Constraints = TODO("Define constraints as above") val request: OneTimeWorkRequest = // Tell which work to execute OneTimeWorkRequestBuilder<MyWorker>() // Sets the input data for the ListenableWorker .setInputData(input) // If you want to delay the start of work by 60 seconds .setInitialDelay(60, TimeUnit.SECONDS) // Set a backoff criteria to be used when retry-ing .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30000, TimeUnit.MILLISECONDS) // Set additional constraints .setConstraints(constraints) .build()
جاوا
import androidx.work.BackoffCriteria; import androidx.work.Constraints; import androidx.work.Constraints.Builder; import androidx.work.NetworkType; import androidx.work.OneTimeWorkRequest; import androidx.work.OneTimeWorkRequest.Builder; import androidx.work.Data; // Define constraints (as above) Constraints constraints = ... OneTimeWorkRequest request = // Tell which work to execute new OneTimeWorkRequest.Builder(MyWorker.class) // Sets the input data for the ListenableWorker .setInputData(inputData) // If you want to delay the start of work by 60 seconds .setInitialDelay(60, TimeUnit.SECONDS) // Set a backoff criteria to be used when retry-ing .setBackoffCriteria(BackoffCriteria.EXPONENTIAL, 30000, TimeUnit.MILLISECONDS) // Set additional constraints .setConstraints(constraints) .build();
تفاوت اصلی در اینجا این است که کارهای WorkManager همیشه در سراسر راهاندازی مجدد دستگاه به طور خودکار ادامه دارند.
اگر میخواهید یک PeriodicWorkRequest
ایجاد کنید، باید کاری مانند:
کاتلین
val constraints: Constraints = TODO("Define constraints as above") val request: PeriodicWorkRequest = PeriodicWorkRequestBuilder<MyWorker>(15, TimeUnit.MINUTES) // Sets the input data for the ListenableWorker .setInputData(input) // Other setters .build()
جاوا
import androidx.work.BackoffCriteria; import androidx.work.Constraints; import androidx.work.Constraints.Builder; import androidx.work.NetworkType; import androidx.work.PeriodicWorkRequest; import androidx.work.PeriodicWorkRequest.Builder; import androidx.work.Data; // Define constraints (as above) Constraints constraints = ... PeriodicWorkRequest request = // Executes MyWorker every 15 minutes new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES) // Sets the input data for the ListenableWorker .setInputData(input) . // other setters (as above) .build();
برنامه ریزی کار
اکنون که Worker
و WorkRequest
را تعریف کرده اید، آماده زمان بندی کار هستید.
هر Job
که با FirebaseJobDispatcher
تعریف میشود دارای یک tag
بود که برای شناسایی منحصر به فرد یک Job
استفاده میشد. همچنین راهی را برای برنامه ارائه میکند تا به زمانبند بگوید که آیا این نمونه از Job
قرار است با فراخوانی setReplaceCurrent
جایگزین یک کپی موجود از Job
شود.
کاتلین
val job = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyService::class.java) // uniquely identifies the job .setTag("my-unique-tag") // don't overwrite an existing job with the same tag .setRecurring(false) // Other setters... .build()
جاوا
Job myJob = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyJobService.class) // uniquely identifies the job .setTag("my-unique-tag") // don't overwrite an existing job with the same tag .setReplaceCurrent(false) // other setters // ... dispatcher.mustSchedule(myJob);
هنگام استفاده از WorkManager، میتوانید با استفاده از APIهای enqueueUniqueWork()
و enqueueUniquePeriodicWork()
(به ترتیب هنگام استفاده از OneTimeWorkRequest
و PeriodicWorkRequest
به همان نتیجه برسید). برای اطلاعات بیشتر، به صفحات مرجع WorkManager.enqueueUniqueWork()
و WorkManager.enqueueUniquePeriodicWork()
مراجعه کنید.
این چیزی شبیه به این خواهد بود:
کاتلین
import androidx.work.* val request: OneTimeWorkRequest = TODO("A WorkRequest") WorkManager.getInstance(myContext) .enqueueUniqueWork("my-unique-name", ExistingWorkPolicy.KEEP, request)
جاوا
import androidx.work.ExistingWorkPolicy; import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; OneTimeWorkRequest workRequest = // a WorkRequest; WorkManager.getInstance(myContext) // Use ExistingWorkPolicy.REPLACE to cancel and delete any existing pending // (uncompleted) work with the same unique name. Then, insert the newly-specified // work. .enqueueUniqueWork("my-unique-name", ExistingWorkPolicy.KEEP, workRequest);
لغو کار
با FirebaseJobDispatcher
می توانید کار را با استفاده از:
کاتلین
dispatcher.cancel("my-unique-tag")
جاوا
dispatcher.cancel("my-unique-tag");
هنگام استفاده از WorkManager می توانید از موارد زیر استفاده کنید:
کاتلین
import androidx.work.WorkManager WorkManager.getInstance(myContext).cancelUniqueWork("my-unique-name")
جاوا
import androidx.work.WorkManager; WorkManager.getInstance(myContext).cancelUniqueWork("my-unique-name");
راه اندازی WorkManager
WorkManager معمولاً خود را با استفاده از ContentProvider
مقداردهی اولیه می کند. اگر به کنترل بیشتری بر نحوه سازماندهی و زمان بندی کار WorkManager نیاز دارید، می توانید پیکربندی WorkManager و مقداردهی اولیه را سفارشی کنید .