Menentukan permintaan pekerjaan

Panduan memulai mencakup cara membuat WorkRequest sederhana dan mengantrekannya.

Dalam panduan ini, Anda akan mempelajari cara menentukan dan menyesuaikan objek WorkRequest untuk menangani kasus penggunaan umum, seperti cara:

  • Menjadwalkan pekerjaan satu kali dan berulang
  • Menyetel batasan kerja, seperti perlu menggunakan Wi-Fi atau mengisi daya untuk melakukan pekerjaan
  • Menjamin penundaan minimum dalam eksekusi pekerjaan
  • Menetapkan strategi percobaan ulang dan back-off
  • Meneruskan input data ke pekerjaan
  • Mengelompokkan pekerjaan yang saling berkaitan menggunakan tag

Ringkasan

Pekerjaan ditentukan di WorkManager melalui WorkRequest. Untuk menjadwalkan pekerjaan apa pun dengan WorkManager, terlebih dahulu Anda harus membuat objek WorkRequest, lalu mengantrekannya.

Kotlin

val myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest)

Java

WorkRequest myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest);

Objek WorkRequest berisi semua informasi yang diperlukan oleh WorkManager untuk menjadwalkan dan menjalankan pekerjaan Anda. Ini mencakup batasan yang harus dipenuhi agar tugas dapat dijalankan, penjadwalan informasi seperti penundaan atau interval berulang, konfigurasi percobaan ulang, dan mungkin termasuk menginput data jika tugas membutuhkannya.

WorkRequest adalah class dasar abstrak. Ada dua implementasi turunan dari class ini yang dapat Anda gunakan untuk membuat permintaan, OneTimeWorkRequest dan PeriodicWorkRequest. Sesuai dengan namanya, OneTimeWorkRequest berguna untuk menjadwalkan tugas yang tidak berulang, sementara PeriodicWorkRequest lebih cocok untuk menjadwalkan tugas yang berulang pada beberapa interval.

Menjadwalkan pekerjaan satu kali

Untuk tugas sederhana, yang tidak memerlukan konfigurasi tambahan, gunakan metode statis from:

Kotlin

val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)

Java

WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);

Untuk tugas yang lebih kompleks, Anda dapat menggunakan builder:

Kotlin

val uploadWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       // Additional configuration
       .build()

Java

WorkRequest uploadWorkRequest =
   new OneTimeWorkRequest.Builder(MyWork.class)
       // Additional configuration
       .build();

Menjadwalkan pekerjaan yang diprioritaskan

WorkManager 2.7.0 memperkenalkan konsep pekerjaan yang diprioritaskan. Hal ini memungkinkan WorkManager mengeksekusi pekerjaan penting sekaligus memberi sistem kontrol yang lebih baik untuk akses ke resource.

Pekerjaan yang diprioritaskan menjadi penting karena karakteristik berikut:

  • Tingkat kepentingan: Tugas yang diprioritaskan cocok dengan tugas yang penting bagi pengguna atau yang dimulai oleh pengguna.
  • Kecepatan: Pekerjaan yang diprioritaskan paling sesuai dengan tugas singkat yang dimulai segera dan selesai dalam beberapa menit.
  • Kuota: Kuota tingkat sistem yang membatasi waktu eksekusi latar depan menentukan apakah tugas yang diprioritaskan dapat dimulai.
  • Pengelolaan Daya: Pembatasan pengelolaan daya, seperti fitur Penghemat Baterai dan Istirahatkan, cenderung tidak memengaruhi tugas yang diprioritaskan.
  • Latensi: Sistem langsung mengeksekusi tugas yang diprioritaskan, asalkan beban kerja sistem saat ini memungkinkannya. Ini berarti sistem peka terhadap latensi dan tidak dapat dijadwalkan untuk eksekusi berikutnya.

Kasus penggunaan potensial untuk pekerjaan yang diprioritaskan mungkin berada dalam aplikasi chat saat pengguna ingin mengirim pesan atau gambar terlampir. Demikian pula, aplikasi yang menangani alur pembayaran atau langganan mungkin juga ingin menggunakan tugas yang diprioritaskan. Hal ini karena tugas tersebut penting bagi pengguna, dieksekusi dengan cepat di latar belakang, harus segera dimulai, dan harus terus dieksekusi meskipun pengguna menutup aplikasi

Kuota

Sistem harus mengalokasikan waktu eksekusi untuk tugas yang diprioritaskan sebelum dapat berjalan. Waktu eksekusi bukannya tidak terbatas. Sebaliknya, setiap aplikasi menerima kuota waktu eksekusi. Setelah aplikasi menggunakan waktu eksekusinya dan mencapai kuota yang dialokasikan, Anda tidak dapat lagi mengeksekusi pekerjaan yang diprioritaskan hingga kuota diperbarui. Hal ini memungkinkan Android menyeimbangkan resource di antara aplikasi secara lebih efektif.

Jumlah waktu eksekusi yang tersedia untuk aplikasi didasarkan pada bucket standby dan tingkat kepentingan proses.

Anda dapat menentukan apa yang akan terjadi jika kuota eksekusi tidak memungkinkan pekerjaan yang diprioritaskan segera dijalankan. Lihat cuplikan di bawah untuk mengetahui detailnya.

Mengeksekusi pekerjaan yang diprioritaskan

Mulai WorkManager 2.7, aplikasi dapat memanggil setExpedited() untuk mendeklarasikan bahwa WorkRequest harus berjalan secepat mungkin menggunakan tugas yang diprioritaskan. Cuplikan kode berikut memberikan contoh cara menggunakan setExpedited():

Kotlin

val request = OneTimeWorkRequestBuilder<SyncWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

WorkManager.getInstance(context)
    .enqueue(request)

Java

OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>()
    .setInputData(inputData)
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build();

Dalam contoh ini, kita melakukan inisialisasi instance OneTimeWorkRequest dan memanggil setExpedited(). Permintaan ini kemudian menjadi pekerjaan yang diprioritaskan. Jika kuota memungkinkan, tugas akan mulai berjalan segera di latar belakang. Jika kuota telah digunakan, parameter OutOfQuotaPolicy menunjukkan bahwa permintaan harus dijalankan sebagai pekerjaan normal, bukan pekerjaan yang dipercepat.

Kompatibilitas mundur dan layanan latar depan

Untuk mempertahankan kompatibilitas mundur bagi tugas yang diprioritaskan, WorkManager mungkin menjalankan layanan latar depan pada versi platform yang lebih lama dari Android 12. Layanan latar depan dapat menampilkan notifikasi kepada pengguna.

Metode getForegroundInfoAsync() dan getForegroundInfo() di dalam Pekerja memungkinkan WorkManager menampilkan notifikasi saat Anda memanggil setExpedited() sebelum Android 12.

Setiap ListenableWorker harus mengimplementasikan metode getForegroundInfo jika Anda ingin meminta agar tugas berjalan sebagai tugas yang diprioritaskan.

Saat menargetkan Android 12 atau yang lebih tinggi, layanan latar depan akan tetap tersedia melalui metode setForeground yang sesuai.

Pekerja

Pekerja tidak mengetahui pekerjaan yang mereka lakukan diprioritaskan atau tidak. Namun, pekerja dapat menampilkan notifikasi di beberapa versi Android saat WorkRequest telah diprioritaskan.

Untuk mengaktifkannya, WorkManager menyediakan metode getForegroundInfoAsync(), yang harus Anda implementasikan agar WorkManager dapat menampilkan notifikasi untuk memulai ForegroundService jika diperlukan.

CoroutineWorker

Jika menggunakan CoroutineWorker, Anda harus mengimplementasikan getForegroundInfo(). Anda kemudian meneruskannya ke setForeground() dalam doWork(). Jika Anda melakukannya, notifikasi di versi Android akan dibuat sebelum versi 12.

Perhatikan contoh berikut:

  class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
   CoroutineWorker(appContext, workerParams) {

   override suspend fun getForegroundInfo(): ForegroundInfo {
       return ForegroundInfo(
           NOTIFICATION_ID, createNotification()
       )
   }

   override suspend fun doWork(): Result {
       TODO()
   }

    private fun createNotification() : Notification {
       TODO()
    }

}

Kebijakan kuota

Anda dapat mengontrol apa yang terjadi pada pekerjaan yang diprioritaskan saat aplikasi mencapai kuota eksekusinya. Untuk melanjutkan, Anda dapat meneruskan setExpedited():

  • OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST, yang menyebabkan pekerjaan dijalankan sebagai permintaan pekerjaan biasa. Cuplikan di atas menunjukkan hal tersebut.
  • OutOfQuotaPolicy.DROP_WORK_REQUEST, yang menyebabkan permintaan dibatalkan jika tidak ada cukup kuota.

Pekerjaan yang diprioritaskan yang ditunda

Sistem akan mencoba mengeksekusi suatu tugas yang diprioritaskan sesegera mungkin setelah tugas tersebut dipanggil. Namun, seperti halnya dengan jenis tugas lain, sistem dapat menunda permulaan pekerjaan baru yang diprioritaskan, seperti dalam kasus berikut:

  • Beban: Beban sistem terlalu tinggi, yang dapat terjadi jika terlalu banyak tugas yang sudah berjalan, atau saat sistem tidak memiliki cukup memori.
  • Kuota: Batas kuota tugas yang diprioritaskan telah terlampaui. Pekerjaan yang diprioritaskan menggunakan sistem kuota yang didasarkan pada Bucket Aplikasi Standby dan membatasi waktu eksekusi maksimum dalam jendela waktu yang bergulir. Kuota yang digunakan untuk pekerjaan yang diprioritaskan lebih ketat dibandingkan dengan kuota yang digunakan untuk jenis tugas latar belakang lainnya.

Menjadwalkan pekerjaan berkala

Terkadang, aplikasi Anda mungkin memerlukan pekerjaan tertentu untuk dijalankan secara berkala. Misalnya, Anda mungkin perlu mencadangkan data, mendownload konten baru di aplikasi, atau mengupload log ke server secara berkala.

Berikut adalah cara menggunakan PeriodicWorkRequest untuk membuat objek WorkRequest yang dieksekusi secara berkala:

Kotlin

val saveRequest =
       PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
    // Additional configuration
           .build()

Java

PeriodicWorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS)
           // Constraints
           .build();

Dalam contoh ini, pekerjaan dijadwalkan dengan interval satu jam.

Periode interval didefinisikan sebagai waktu minimum di antara pengulangan. Waktu pasti eksekusi pekerja bergantung pada batasan yang Anda gunakan dalam objek WorkRequest dan pada pengoptimalan yang dilakukan oleh sistem.

Interval proses fleksibel

Jika sifat pekerjaan Anda sangat bergantung pada waktu eksekusi, Anda dapat mengonfigurasikan PeriodicWorkRequest untuk berjalan pada periode fleksibel dalam setiap periode interval, seperti yang ditunjukkan pada Gambar 1.

Anda dapat menyetel interval fleksibel untuk tugas berkala. Anda menentukan interval pengulangan,
dan interval fleksibel yang menentukan jumlah waktu tertentu di akhir
interval pengulangan. WorkManager mencoba menjalankan pekerjaan Anda pada waktu tertentu selama
interval fleksibel pada setiap siklus.

Gambar 1. Diagram menunjukkan interval pengulangan dengan periode fleksibel yang dapat digunakan untuk menjalankan pekerjaan.

Untuk menentukan pekerjaan berkala dengan periode flex, Anda perlu meneruskan flexInterval dengan repeatInterval saat membuat PeriodicWorkRequest. Periode flex dimulai pada repeatInterval - flexInterval, dan berlanjut ke akhir interval.

Berikut adalah contoh pekerjaan berkala yang dapat dijalankan selama 15 menit terakhir dari setiap periode satu jam.

Kotlin

val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(
       1, TimeUnit.HOURS, // repeatInterval (the period cycle)
       15, TimeUnit.MINUTES) // flexInterval
    .build()

Java

WorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class,
               1, TimeUnit.HOURS,
               15, TimeUnit.MINUTES)
           .build();

Interval berulang harus lebih besar dari atau sama dengan PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS dan interval fleksibel harus lebih besar dari atau sama dengan PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS.

Pengaruh Batasan pada Pekerjaan Berkala

Anda dapat menerapkan batasan untuk tugas berkala. Misalnya, Anda dapat menambahkan batasan ke permintaan tugas sehingga tugas hanya akan berjalan saat perangkat pengguna mengisi daya. Dalam kasus ini, meskipun interval pengulangan yang ditentukan berlalu, PeriodicWorkRequest tidak akan berjalan sampai kondisi ini terpenuhi. Hal ini dapat menyebabkan proses tertentu dari pekerjaan Anda menjadi tertunda, atau bahkan dilewati jika kondisi tidak terpenuhi dalam interval eksekusi.

Batasan pekerjaan

Batasan memastikan bahwa pekerjaan ditunda hingga kondisi optimal terpenuhi. Batasan berikut tersedia untuk WorkManager.

NetworkType Batasi jenis jaringan yang diperlukan agar pekerjaan Anda dapat berjalan. Misalnya, Wi-Fi (UNMETERED).
BatteryNotLow Bila disetel ke benar (true), pekerjaan Anda tidak akan berjalan jika perangkat dalam mode baterai lemah.
RequiresCharging Jika disetel ke benar (true), pekerjaan Anda hanya akan berjalan saat perangkat sedang diisi dayanya.
DeviceIdle Jika disetel ke benar (true), tindakan ini mengharuskan perangkat pengguna tidak beraktivitas sebelum pekerjaan berjalan. Tindakan ini berguna untuk menjalankan operasi batch yang mungkin berdampak negatif pada performa aplikasi lain yang berjalan secara aktif pada perangkat pengguna.
StorageNotLow Jika disetel ke benar (true), pekerjaan Anda tidak akan berjalan jika ruang penyimpanan pengguna di perangkat terlalu rendah.

Untuk membuat kumpulan batasan dan mengaitkannya ke beberapa tugas, buat instance Constraints menggunakan Contraints.Builder() dan tetapkan ke WorkRequest.Builder().

Misalnya, kode berikut membuat permintaan kerja yang hanya berjalan saat perangkat pengguna mengisi daya dan menggunakan Wi-Fi:

Kotlin

val constraints = Constraints.Builder()
   .setRequiredNetworkType(NetworkType.UNMETERED)
   .setRequiresCharging(true)
   .build()

val myWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       .setConstraints(constraints)
       .build()

Java

Constraints constraints = new Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresCharging(true)
       .build();

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setConstraints(constraints)
               .build();

Saat beberapa batasan ditentukan, pekerjaan hanya akan berjalan jika semua batasan terpenuhi.

Jika batasan menjadi tidak stabil saat pekerjaan berjalan, WorkManager akan menghentikan pekerja. Pekerjaan tersebut kemudian akan dicoba lagi setelah semua batasan terpenuhi.

Pekerjaan Tertunda

Jika pekerjaan Anda tidak memiliki batasan atau semua batasan terpenuhi saat pekerjaan diantrekan, sistem dapat memilih untuk langsung menjalankan pekerjaan ini. Jika tidak ingin tugas dijalankan langsung, Anda dapat menentukan tugas agar dimulai setelah penundaan awal minimum.

Berikut adalah contoh cara menetapkan pekerjaan agar berjalan minimal 10 menit setelah diantrekan.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .setInitialDelay(10, TimeUnit.MINUTES)
   .build()

Java

WorkRequest myWorkRequest =
      new OneTimeWorkRequest.Builder(MyWork.class)
               .setInitialDelay(10, TimeUnit.MINUTES)
               .build();

Meskipun contoh menggambarkan cara menetapkan penundaan awal untuk OneTimeWorkRequest, Anda juga dapat menetapkan penundaan awal untuk PeriodicWorkRequest. Dalam hal ini, hanya operasi pertama dari pekerjaan berkala Anda yang akan ditunda.

Kebijakan percobaan ulang dan backoff

Jika Anda mengharuskan WorkManager untuk mencoba kembali tugas, Anda dapat mengembalikan Result.retry() dari pekerja. Pekerjaan Anda akan dijadwalkan ulang sesuai dengan penundaan backoff dan kebijakan backoff.

  • Penundaan backoff menentukan jumlah waktu minimum untuk menunggu sebelum mencoba kembali pekerjaan Anda setelah upaya pertama. Nilai ini tidak boleh kurang dari 10 detik (atau MIN_BACKOFF_MILLIS).

  • Kebijakan backoff menentukan bagaimana keterlambatan backoff akan meningkat dari waktu ke waktu untuk upaya percobaan ulang berikutnya. WorkManager mendukung 2 kebijakan backoff, LINEAR dan EXPONENTIAL.

Setiap permintaan pekerjaan memiliki kebijakan backoff dan penundaan backoff. Kebijakan defaultnya adalah EXPONENTIAL dengan penundaan selama 30 detik, tetapi Anda dapat menggantinya di konfigurasi permintaan kerja.

Berikut adalah contoh penyesuaian kebijakan dan penundaan backoff.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .setBackoffCriteria(
       BackoffPolicy.LINEAR,
       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
       TimeUnit.MILLISECONDS)
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setBackoffCriteria(
                       BackoffPolicy.LINEAR,
                       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                       TimeUnit.MILLISECONDS)
               .build();

Dalam contoh ini, penundaan backoff minimum ditetapkan ke nilai minimum yang diizinkan, 10 detik. Karena kebijakannya adalah LINEAR, interval percobaan ulang akan meningkat sekitar 10 detik dengan setiap upaya baru. Misalnya, penyelesaian pertama dengan Result.retry() akan dicoba lagi setelah 10 detik, diikuti dengan 20, 30, 40, dan seterusnya, jika pekerjaan terus mengembalikan Result.retry() setelah upaya berikutnya. Jika kebijakan backoff ditetapkan ke EXPONENTIAL, urutan durasi percobaan ulang akan menjadi lebih dekat ke 20, 40, 80, dan seterusnya.

Memberi tag pekerjaan

Setiap permintaan pekerjaan memiliki pengenal unik, yang dapat digunakan untuk mengidentifikasi pekerjaan tersebut nanti untuk membatalkan pekerjaan atau mengamati progresnya.

Jika memiliki grup tugas yang terkait secara logis, Anda juga dapat membantu untuk memberi tag item tugas tersebut. Pemberian tag memungkinkan Anda untuk beroperasi dengan sekelompok permintaan tugas bersama-sama.

Misalnya, WorkManager.cancelAllWorkByTag(String) membatalkan semua permintaan pekerjaan dengan tag tertentu, dan WorkManager.getWorkInfosByTag(String) menampilkan daftar objek WorkInfo yang dapat digunakan untuk menentukan status pekerjaan saat ini.

Kode berikut menunjukkan cara menambahkan tag "pembersihan" ke pekerjaan:

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .addTag("cleanup")
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
       .addTag("cleanup")
       .build();

Terakhir, beberapa tag dapat ditambahkan ke satu permintaan pekerjaan. Secara internal, tag ini disimpan sebagai kumpulan string. Untuk mendapatkan kumpulan tag yang dikaitkan dengan WorkRequest, Anda dapat menggunakan WorkInfo.getTags().

Dari class Worker, Anda dapat mengambil kumpulan tag-nya melalui ListenableWorker.getTags().

Menetapkan data input

Tugas Anda mungkin memerlukan data input agar dapat melakukan pekerjaannya. Misalnya, tugas yang menangani upload gambar mungkin memerlukan URI gambar untuk diupload sebagai input.

Nilai input disimpan sebagai key-value pair dalam objek Data dan dapat ditetapkan pada permintaan pekerjaan. WorkManager akan mengirimkan input Data ke tugas Anda saat menjalankan tugas. Class Worker dapat mengakses argumen input dengan memanggil Worker.getInputData(). Kode di bawah ini menunjukkan cara membuat instance Worker yang memerlukan data input dan cara mengirimkannya dalam permintaan tugas Anda.

Kotlin

// Define the Worker requiring input
class UploadWork(appContext: Context, workerParams: WorkerParameters)
   : Worker(appContext, workerParams) {

   override fun doWork(): Result {
       val imageUriInput =
           inputData.getString("IMAGE_URI") ?: return Result.failure()

       uploadFile(imageUriInput)
       return Result.success()
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
val myUploadWork = OneTimeWorkRequestBuilder<UploadWork>()
   .setInputData(workDataOf(
       "IMAGE_URI" to "http://..."
   ))
   .build()

Java

// Define the Worker requiring input
public class UploadWork extends Worker {

   public UploadWork(Context appContext, WorkerParameters workerParams) {
       super(appContext, workerParams);
   }

   @NonNull
   @Override
   public Result doWork() {
       String imageUriInput = getInputData().getString("IMAGE_URI");
       if(imageUriInput == null) {
           return Result.failure();
       }

       uploadFile(imageUriInput);
       return Result.success();
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
WorkRequest myUploadWork =
      new OneTimeWorkRequest.Builder(UploadWork.class)
           .setInputData(
               new Data.Builder()
                   .putString("IMAGE_URI", "http://...")
                   .build()
           )
           .build();

Demikian pula, class Data dapat digunakan untuk menampilkan nilai hasil. Data input dan output dibahas secara lebih mendetail di bagian parameter input dan nilai yang ditampilkan.

Langkah Berikutnya

Di halaman Status dan pengamatan, Anda akan mempelajari lebih lanjut status pekerjaan dan cara memantau progres pekerjaan.