WorkManager adalah library untuk menjadwalkan dan mengeksekusi pekerjaan latar belakang yang dapat ditangguhkan di Android. Library ini merupakan pengganti yang direkomendasikan untuk Firebase JobDispatcher. Panduan berikut akan menjelaskan proses memigrasikan penerapan Firebase JobDispatcher ke WorkManager.
Penyiapan Gradle
Untuk mengimpor library WorkManager ke project Android, tambahkan dependensi yang tercantum di Mulai Menggunakan WorkManager.
Dari JobService ke pekerja
FirebaseJobDispatcher
menggunakan subclass
JobService
sebagai titik masuk untuk mendefinisikan
pekerjaan yang perlu dilakukan. Anda mungkin langsung
menggunakan JobService
, atau
menggunakan SimpleJobService
.
JobService
akan terlihat seperti ini:
Kotlin
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?" } }
Java
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?" } }
Jika Anda menggunakan SimpleJobService
, Anda harus mengganti onRunJob()
,
yang menampilkan jenis @JobResult int
.
Perbedaan utama adalah saat Anda menggunakan JobService
secara langsung, onStartJob()
akan dipanggil pada thread utama, dan merupakan tanggung jawab aplikasi untuk mengalihkan
pekerjaan ke thread latar belakang. Di sisi lain, jika Anda menggunakan
SimpleJobService
, layanan tersebut bertanggung jawab untuk menjalankan pekerjaan
Anda di thread latar belakang.
WorkManager memiliki konsep yang serupa. Unit dasar pekerjaan dalam
WorkManager adalah ListenableWorker
. Ada
juga subjenis lainnya dari pekerja
seperti Worker
,
RxWorker
, dan CoroutineWorker
(jika
menggunakan coroutine Kotlin).
JobService dipetakan ke ListenableWorker
Jika Anda menggunakan JobService
secara langsung, maka pekerja yang
dipetakannya adalah ListenableWorker
. Jika Anda menggunakan SimpleJobService
, maka Anda harus menggunakan
Worker
sebagai gantinya.
Saatnya menggunakan contoh di atas (MyJobService
) dan lihat cara kami mengonversinya
menjadi ListenableWorker
.
Kotlin
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. } }
Java
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. } }
Unit dasar pekerjaan dalam WorkManager adalah ListenableWorker
. Sama
seperti JobService.onStartJob()
, startWork()
dipanggil di thread utama. Di
sini MyWorker
mengimplementasikan ListenableWorker
dan menampilkan instance
dari ListenableFuture
,
yang digunakan untuk menandakan penyelesaian pekerjaan secara asinkron. Anda harus memilih
strategi threading Anda sendiri di sini.
Di sini ListenableFuture
pada akhirnya menampilkan jenis
ListenableWorker.Result
yang dapat berupa salah satu Result.success()
, Result.success(Data outputData)
,
Result.retry()
, Result.failure()
, atau Result.failure(Data outputData)
. Untuk
informasi selengkapnya, lihat halaman referensi
untuk ListenableWorker.Result
.
onStopped()
dipanggil untuk menandai bahwa ListenableWorker
perlu berhenti,
baik karena batasan tidak lagi terpenuhi (misalnya, karena
jaringan tidak lagi tersedia), atau karena metode
WorkManager.cancel…()
dipanggil. onStopped()
juga dapat dipanggil jika OS memutuskan untuk menonaktifkan pekerjaan Anda
karena beberapa alasan.
SimpleJobService dipetakan ke Pekerja
Saat menggunakan SimpleJobService
, pekerja di atas akan terlihat seperti:
Kotlin
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") } }
Java
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. } }
Di sini doWork()
menampilkan instance dari ListenableWorker.Result
untuk menandakan
penyelesaian pekerjaan secara sinkron. Ini mirip dengan SimpleJobService
, yang menjadwalkan
tugas di thread latar belakang.
JobBuilder dipetakan ke WorkRequest
FirebaseJobBuilder menggunakan Job.Builder
untuk merepresentasikan metadata Job
. WorkManager
menggunakan WorkRequest
untuk mengisi peran ini.
WorkManager memiliki dua jenis WorkRequest
:
OneTimeWorkRequest
dan
PeriodicWorkRequest
.
Jika Anda sedang menggunakan Job.Builder.setRecurring(true)
, maka Anda harus
membuat PeriodicWorkRequest
baru. Jika tidak, Anda harus
menggunakan OneTimeWorkRequest
.
Mari kita lihat tampilan penjadwalan Job
dengan FirebaseJobDispatcher
yang
kompleks:
Kotlin
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)
Java
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);
Untuk mencapai hal yang sama dengan WorkManager, Anda harus:
- Membuat data input yang dapat digunakan sebagai input untuk
Worker
. - Membuat
WorkRequest
dengan data input dan batasan yang serupa dengan yang ditentukan di atas untukFirebaseJobDispatcher
. - Mengantrekan
WorkRequest
.
Menyiapkan input untuk Pekerja
FirebaseJobDispatcher
menggunakan Bundle
untuk mengirimkan data input ke JobService
.
WorkManager menggunakan Data
sebagai gantinya. Ini
akan menjadi:
Kotlin
import androidx.work.workDataOf val data = workDataOf("some_key" to "some_val")
Java
import androidx.work.Data; Data input = new Data.Builder() .putString("some_key", "some_value") .build();
Menyiapkan Batasan untuk Pekerja
FirebaseJobDispatcher
penggunaan
Job.Builder.setConstaints(...)
untuk mengatur batasan
pada pekerjaan. WorkManager menggunakan
Constraints
sebagai gantinya.
Kotlin
import androidx.work.* val constraints: Constraints = Constraints.Builder().apply { setRequiredNetworkType(NetworkType.CONNECTED) setRequiresCharging(true) }.build()
Java
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();
Membuat WorkRequest (OneTime atau Periodic)
Untuk membuat OneTimeWorkRequest
dan PeriodicWorkRequest
, Anda harus menggunakan
OneTimeWorkRequest.Builder
dan PeriodicWorkRequest.Builder
.
Untuk membuat OneTimeWorkRequest
yang serupa dengan Job
di atas, Anda harus
melakukan hal berikut:
Kotlin
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()
Java
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();
Perbedaan utamanya adalah bahwa tugas WorkManager akan otomatis dipertahankan saat reboot perangkat.
Jika Anda ingin membuat PeriodicWorkRequest
, maka Anda harus melakukan hal berikut:
Kotlin
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()
Java
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();
Menjadwalkan pekerjaan
Setelah menentukan Worker
dan WorkRequest
, Anda siap
untuk menjadwalkan pekerjaan.
Setiap Job
yang ditentukan dengan FirebaseJobDispatcher
memiliki tag
yang digunakan
untuk mengidentifikasi secara unik Job
. Ini juga menyediakan cara bagi aplikasi untuk memberi tahu
scheduler jika instance dari Job
mengganti salinan
Job
yang ada dengan memanggil setReplaceCurrent
.
Kotlin
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()
Java
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);
Saat menggunakan WorkManager, Anda dapat meraih hasil yang sama dengan menggunakan
API enqueueUniqueWork()
dan enqueueUniquePeriodicWork()
(jika menggunakan
OneTimeWorkRequest
dan PeriodicWorkRequest
). Untuk informasi
selengkapnya, lihat halaman referensi
untuk WorkManager.enqueueUniqueWork()
dan WorkManager.enqueueUniquePeriodicWork()
.
Ini akan terlihat seperti:
Kotlin
import androidx.work.* val request: OneTimeWorkRequest = TODO("A WorkRequest") WorkManager.getInstance(myContext) .enqueueUniqueWork("my-unique-name", ExistingWorkPolicy.KEEP, request)
Java
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);
Membatalkan pekerjaan
Dengan FirebaseJobDispatcher
Anda dapat membatalkan pekerjaan menggunakan:
Kotlin
dispatcher.cancel("my-unique-tag")
Java
dispatcher.cancel("my-unique-tag");
Saat menggunakan WorkManager, Anda dapat menggunakan:
Kotlin
import androidx.work.WorkManager WorkManager.getInstance(myContext).cancelUniqueWork("my-unique-name")
Java
import androidx.work.WorkManager; WorkManager.getInstance(myContext).cancelUniqueWork("my-unique-name");
Menginisialisasi WorkManager
WorkManager biasanya menginisialisasi sendiri dengan menggunakan ContentProvider
.
Jika Anda memerlukan kontrol lebih terhadap cara WorkManager mengatur dan menjadwalkan pekerjaan, Anda
dapat menyesuaikan konfigurasi dan inisialisasi WorkManager.