Mengelola pekerjaan

Setelah Anda menentukan Worker dan WorkRequest, maka langkah terakhir adalah mengantrekan pekerjaan. Cara termudah untuk mengantrekan pekerjaan adalah dengan memanggil metode WorkManager enqueue(), yakni dengan meneruskan WorkRequest yang ingin dijalankan.

Kotlin


val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)

Java


WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);

Berhati-hatilah saat mengantrekan pekerjaan untuk menghindari duplikasi. Misalnya, sebuah aplikasi mungkin akan mencoba mengupload log ke layanan backend setiap 24 jam. Jika tidak berhati-hati, Anda mungkin akan mengantrekan tugas yang sama berkali-kali, meskipun pekerjaan hanya perlu dijalankan sekali. Untuk mencapai tujuan ini, Anda dapat menjadwalkannya sebagai pekerjaan unik.

Pekerjaan Unik

Pekerjaan unik merupakan konsep ampuh yang akan menjamin bahwa Anda hanya memiliki satu instance pekerjaan dengan nama tertentu pada satu waktu. Tidak seperti ID, nama unik dapat dibaca oleh manusia dan ditentukan oleh developer, bukan dibuat secara otomatis oleh WorkManager. Tidak seperti tag, nama unik hanya dikaitkan dengan satu instance pekerjaan.

Pekerjaan unik dapat diterapkan baik untuk pekerjaan satu kali maupun pekerjaan berkala. Anda dapat membuat urutan kerja yang unik dengan memanggil salah satu metode ini, bergantung pada apakah Anda menjadwalkan pekerjaan berulang atau pekerjaan satu kali.

Kedua metode ini menerima 3 argumen:

  • uniqueWorkName - Sebuah String yang digunakan untuk mengidentifikasi permintaan kerja secara unik.
  • existingWorkPolicy - Sebuah enum yang akan memberi tahu WorkManager tindakan yang harus dilakukan jika sudah ada rantai pekerjaan dengan nama unik tersebut yang belum selesai. Lihat kebijakan resolusi konflik untuk informasi selengkapnya.
  • work - Ini adalah WorkRequest yang akan dijadwalkan.

Dengan menggunakan pekerjaan unik, kita bisa memperbaiki masalah penjadwalan duplikat yang telah diketahui sebelumnya.

Kotlin


val sendLogsWorkRequest =
       PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS)
           .setConstraints(Constraints.Builder()
               .setRequiresCharging(true)
               .build()
            )
           .build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
           "sendLogs",
           ExistingPeriodicWorkPolicy.KEEP,
           sendLogsWorkRequest
)

Java


PeriodicWorkRequest sendLogsWorkRequest = new
      PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS)
              .setConstraints(new Constraints.Builder()
              .setRequiresCharging(true)
          .build()
      )
     .build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
     "sendLogs",
     ExistingPeriodicWorkPolicy.KEEP,
     sendLogsWorkRequest);

Kini, jika kode berjalan saat pekerjaan sendLogs sudah berada dalam antrean, pekerjaan yang ada akan disimpan dan tidak ada pekerjaan baru yang ditambahkan.

Urutan pekerjaan unik juga dapat digunakan jika Anda perlu membuat rantai tugas yang panjang secara bertahap. Misalnya, aplikasi pengeditan foto dapat memungkinkan pengguna untuk mengurungkan rantai tindakan yang panjang. Setiap operasi urungkan mungkin perlu waktu beberapa saat, tetapi harus dilakukan dengan urutan yang benar. Dalam hal ini, aplikasi dapat membuat rantai "urungkan" dan menambahkan setiap operasi urungkan ke rantai tersebut sesuai kebutuhan. Lihat Perantaian pekerjaan untuk detail selengkapnya.

Kebijakan resolusi konflik

Saat menjadwalkan pekerjaan unik, Anda harus memberi tahu WorkManager tindakan yang harus diambil saat terjadi konflik. Tindakan ini dapat dilakukan dengan meneruskan enum saat mengantrekan pekerjaan.

Untuk pekerjaan satu kali, Anda perlu menyediakan ExistingWorkPolicy, yang mendukung 4 opsi untuk menangani konflik.

  • REPLACE pekerjaan yang sudah ada dengan pekerjaan baru. Opsi ini membatalkan pekerjaan yang ada.
  • KEEP pekerjaan yang ada dan mengabaikan pekerjaan baru.
  • APPEND pekerjaan baru hingga akhir pekerjaan yang ada. Kebijakan ini akan menyebabkan pekerjaan baru Anda dirantai ke pekerjaan yang ada, dan dijalankan setelah pekerjaan tersebut selesai.

Pekerjaan yang ada akan menjadi prasyarat untuk pekerjaan baru. Jika pekerjaan yang ada menjadi CANCELLED atau FAILED, pekerjaan baru juga akan menjadi CANCELLED atau FAILED. Jika Anda ingin menjalankan pekerjaan baru, terlepas dari status pekerjaan yang sudah ada, gunakan APPEND_OR_REPLACE.

  • APPEND_OR_REPLACE berfungsi serupa dengan APPEND, tetapi itu tidak bergantung pada status kerja prasyarat. Jika pekerjaan yang ada memiliki status CANCELLED atau FAILED, pekerjaan baru akan tetap berjalan.

Untuk pekerjaan berkala, Anda perlu menyediakan ExistingPeriodicWorkPolicy, yang mendukung 2 opsi, yaitu REPLACE dan KEEP. Opsi ini memiliki fungsi yang sama dengan pasangan ExistingWorkPolicy.

Mengamati pekerjaan

Kapan pun setelah mengantrekan pekerjaan, Anda dapat memeriksa statusnya dengan mengajukan kueri WorkManager berdasarkan name, id, atau dengan tag yang terkait dengannya.

Kotlin


// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>

// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>

// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>

Java


// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo>

// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>>

// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>


Kueri tersebut menampilkan ListenableFuture dari sebuah objek WorkInfo, yang mencakup id pekerjaan, tag-nya, State-nya saat ini, dan semua data output yang disetel melalui Result.success(outputData).

Varian LiveData untuk setiap metode memungkinkan Anda mengamati perubahan WorkInfo dengan mendaftarkan pemroses. Misalnya, jika ingin menampilkan pesan kepada pengguna saat beberapa pekerjaan berhasil diselesaikan, Anda dapat mengaturnya sebagai berikut:

Kotlin


workManager.getWorkInfoByIdLiveData(syncWorker.id)
               .observe(viewLifecycleOwner) { workInfo ->
   if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
       Snackbar.make(requireView(), 
      R.string.work_completed, Snackbar.LENGTH_SHORT)
           .show()
   }
}


Java


workManager.getWorkInfoByIdLiveData(syncWorker.id)
        .observe(getViewLifecycleOwner(), workInfo -> {
    if (workInfo.getState() != null &&
            workInfo.getState() == WorkInfo.State.SUCCEEDED) {
        Snackbar.make(requireView(),
                    R.string.work_completed, Snackbar.LENGTH_SHORT)
                .show();
   }
});

Kueri pekerjaan yang kompleks

WorkManager 2.4.0 dan yang lebih tinggi mendukung kueri yang kompleks untuk pekerjaan yang diantrekan menggunakan objek WorkQuery. WorkQuery mendukung proses pembuatan kueri untuk pekerjaan dari kombinasi tag, status, dan nama pekerjaan unik.

Contoh berikut ini menunjukkan cara untuk menemukan semua pekerjaan yang berisi tag, “syncTag”, yang memiliki status FAILED maupun CANCELLED dan memiliki nama kerja yang unik untuk "preProcess” atau “sync”.

Kotlin


val workQuery = WorkQuery.Builder
       .fromTags(listOf("syncTag"))
       .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(listOf("preProcess", "sync")
    )
   .build()

val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)

Java


WorkQuery workQuery = WorkQuery.Builder
       .fromTags(Arrays.asList("syncTag"))
       .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(Arrays.asList("preProcess", "sync")
     )
    .build();

ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);

Setiap komponen (tag, status, atau nama) pada WorkQuery akan diberi AND seperti komponen lainnya. Setiap nilai dalam komponen akan diberi OR. Misalnya: (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...).

WorkQuery juga berfungsi dengan LiveData yang setara, getWorkInfosLiveData().

Membatalkan dan menghentikan pekerjaan

Jika sudah tidak perlu pekerjaan yang sebelumnya diantrekan, Anda dapat meminta untuk membatalkan pekerjaan tersebut. Pekerjaan dapat dibatalkan oleh name, id, atau tag yang terkait dengannya.

Kotlin


// by id
workManager.cancelWorkById(syncWorker.id)

// by name
workManager.cancelUniqueWork("sync")

// by tag
workManager.cancelAllWorkByTag("syncTag")


Java


// by id
workManager.cancelWorkById(syncWorker.id);

// by name
workManager.cancelUniqueWork("sync");

// by tag
workManager.cancelAllWorkByTag("syncTag");

Di balik layar, WorkManager memeriksa State pekerjaan. Jika pekerjaan sudah selesai, tidak ada yang terjadi. Jika tidak, status pekerjaan diubah menjadi CANCELLED dan pekerjaan tidak akan dijalankan lagi di masa mendatang. Semua pekerjaan WorkRequest yang bergantung pada pekerjaan ini juga akan menjadi CANCELLED.

Saat ini pekerjaan RUNNING menerima panggilan ke ListenableWorker.onStopped(). Ganti metode ini untuk menangani segala potensi pembersihan. Lihat menghentikan pekerja yang berjalan untuk informasi selengkapnya.

Menghentikan Worker yang sedang berjalan

Ada beberapa alasan mengapa Worker yang sedang berjalan mungkin dihentikan oleh WorkManager:

  • Anda secara eksplisit memintanya untuk dibatalkan (misalnya dengan memanggil WorkManager.cancelWorkById(UUID)).
  • Untuk pekerjaan unik, Anda secara eksplisit mengantrekan WorkRequest baru dengan ExistingWorkPolicy dari REPLACE. WorkRequest lama langsung dianggap dibatalkan.
  • Batasan pekerjaan Anda tidak lagi terpenuhi.
  • Sistem menginstruksikan aplikasi agar menghentikan pekerjaan karena suatu alasan. Hal ini dapat terjadi jika Anda melebihi batas waktu eksekusi selama 10 menit. Pekerjaan akan dijadwalkan untuk dicoba lagi nanti.

Worker akan dihentikan dalam kondisi seperti ini.

Jika demikian, Anda harus mau membatalkan pekerjaan apa pun yang sedang dilakukan dan melepaskan semua resource berisi Worker. Sebagai contoh, dalam situasi ini, Anda harus menutup proses penanganan database dan file yang masih terbuka. Anda dapat menggunakan dua mekanisme untuk mengetahui kapan Worker akan berhenti bekerja.

Callback onStopped()

WorkManager memanggil ListenableWorker.onStopped() segera setelah Worker dihentikan. Ganti metode ini untuk menutup resource yang mungkin Anda miliki.

Properti isStopped()

Anda dapat memanggil metode ListenableWorker.isStopped() untuk memeriksa apakah pekerja sudah dihentikan. Jika Anda menjalankan operasi dalam waktu lama atau berulang di dalam Worker, Anda harus sering memeriksa properti ini dan menggunakannya sebagai sinyal untuk menghentikan pekerjaan sesegera mungkin.

Catatan: WorkManager mengabaikan Result yang ditetapkan oleh Worker yang telah menerima sinyal onStop, karena Worker sudah dianggap berhenti.