Topik WorkManager lanjutan

WorkManager memudahkan penyiapan dan penjadwalan permintaan tugas yang rumit. Anda dapat menggunakan API untuk skenario seperti ini:

  • Urutan berantai dari tugas yang berjalan dalam urutan yang telah ditentukan
  • Urutan bernama unik, dengan aturan untuk apa yang akan terjadi jika aplikasi meluncurkan dua urutan dengan nama yang sama
  • Tugas yang meneruskan dan menampilkan nilai, termasuk tugas berantai yang mana setiap tugas meneruskan argumen ke tugas berikutnya dalam rantai tersebut

Tugas berantai

Aplikasi Anda mungkin perlu menjalankan beberapa tugas dalam urutan tertentu. WorkManager memungkinkan Anda membuat dan mengantrekan urutan pekerjaan yang menentukan beberapa tugas, serta menetapkan urutan berjalannya tugas tersebut.

Misalnya, aplikasi Anda memiliki tiga objek OneTimeWorkRequest: workA, workB, dan workC. Tugas harus dijalankan dalam urutan tersebut. Untuk mengantrekannya, buat urutan dengan metode WorkManager.beginWith(OneTimeWorkRequest), yang meneruskan objek OneTimeWorkRequest pertama; metode tersebut menampilkan objek WorkContinuation, yang menentukan urutan tugas. Kemudian, tambahkan objek OneTimeWorkRequest lainnya, sesuai urutan, dengan WorkContinuation.then(OneTimeWorkRequest), dan terakhir, antrekan semua urutan tersebut dengan WorkContinuation.enqueue():

Kotlin

WorkManager.getInstance(myContext)
    .beginWith(workA)
        // Note: WorkManager.beginWith() returns a
        // WorkContinuation object; the following calls are
        // to WorkContinuation methods
    .then(workB)    // FYI, then() returns a new WorkContinuation instance
    .then(workC)
    .enqueue()

Java

WorkManager.getInstance(myContext)
    .beginWith(workA)
        // Note: WorkManager.beginWith() returns a
        // WorkContinuation object; the following calls are
        // to WorkContinuation methods
    .then(workB)    // FYI, then() returns a new WorkContinuation instance
    .then(workC)
    .enqueue();

WorkManager menjalankan tugas dalam urutan yang diminta, sesuai dengan batasan setiap tugas yang telah ditentukan. Jika tugas apa pun menampilkan Result.failure(), seluruh urutan akan berakhir.

Anda juga dapat meneruskan beberapa objek OneTimeWorkRequest ke salah satu panggilan beginWith(List<OneTimeWorkRequest>) dan then(List<OneTimeWorkRequest>). Jika Anda meneruskan beberapa objek OneTimeWorkRequest ke satu panggilan metode, WorkManager menjalankan semua tugas tersebut (secara paralel) sebelum menjalankan sisa urutannya. Contoh:

Kotlin

WorkManager.getInstance(myContext)
    // First, run all the A tasks (in parallel):
    .beginWith(Arrays.asList(workA1, workA2, workA3))
    // ...when all A tasks are finished, run the single B task:
    .then(workB)
    // ...then run the C tasks (in parallel):
    .then(Arrays.asList(workC1, workC2))
    .enqueue()

Java

WorkManager.getInstance(myContext)
    // First, run all the A tasks (in parallel):
    .beginWith(Arrays.asList(workA1, workA2, workA3))
    // ...when all A tasks are finished, run the single B task:
    .then(workB)
    // ...then run the C tasks (in parallel):
    .then(Arrays.asList(workC1, workC2))
    .enqueue();

Anda dapat membuat urutan yang lebih kompleks dengan menggabungkan beberapa rantai menggunakan metode WorkContinuation.combine(List<OneTimeWorkRequest>). Misalnya, Anda ingin menjalankan urutan seperti ini:

Gambar 1. Anda dapat menggunakan WorkContinuation untuk menyiapkan tugas berantai yang kompleks.

Untuk menyiapkan urutan ini, buat dua rantai yang berbeda, lalu gabungkan rantai tersebut menjadi rantai ketiga:

Kotlin

val chain1 = WorkManager.getInstance(myContext)
    .beginWith(workA)
    .then(workB)
val chain2 = WorkManager.getInstance(myContext)
    .beginWith(workC)
    .then(workD)
val chain3 = WorkContinuation
    .combine(Arrays.asList(chain1, chain2))
    .then(workE)
chain3.enqueue()

Java

WorkContinuation chain1 = WorkManager.getInstance(myContext)
    .beginWith(workA)
    .then(workB);
WorkContinuation chain2 = WorkManager.getInstance(myContext)
    .beginWith(workC)
    .then(workD);
WorkContinuation chain3 = WorkContinuation
    .combine(Arrays.asList(chain1, chain2))
    .then(workE);
chain3.enqueue();

Dalam hal ini, WorkManager menjalankan workA sebelum workB. WorkManager juga menjalankan workC sebelum workD. Setelah workB dan workD selesai, WorkManager menjalankan workE.

Ada sejumlah varian dari metode WorkContinuation yang memberikan cara pintas untuk situasi tertentu. Untuk mengetahui detailnya, lihat referensi WorkContinuation.

Urutan pekerjaan unik

Anda dapat membuat urutan pekerjaan unik, dengan memulai setiap urutan dengan panggilan ke beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest), bukan beginWith(OneTimeWorkRequest). Setiap urutan pekerjaan unik memiliki nama; WorkManager hanya mengizinkan satu urutan pekerjaan dengan suatu nama dalam satu waktu. Saat membuat urutan pekerjaan unik yang baru, Anda menentukan apa yang harus dilakukan WorkManager jika sudah ada urutan yang belum selesai dengan nama yang sama:

  • Membatalkan urutan yang ada dan MENGGANTI urutan tersebut dengan yang baru
  • KEEP (MENYIMPAN) urutan yang ada dan mengabaikan permintaan yang baru
  • MENAMBAHKAN urutan yang baru ke urutan yang sudah ada, menjalankan tugas pertama dari urutan yang baru setelah tugas terakhir urutan yang sudah ada telah selesai

Urutan pekerjaan unik dapat berguna saat Anda memiliki tugas yang tidak boleh diantrekan beberapa kali. Misalnya, jika aplikasi perlu menyinkronkan datanya ke jaringan, Anda dapat mengantrekan urutan bernama "sinkronisasi", dan menentukan bahwa tugas baru harus diabaikan jika sudah ada urutan dengan nama tersebut. Urutan pekerjaan unik juga berguna jika Anda perlu membuat rantai tugas panjang secara bertahap. Misalnya, aplikasi pengeditan foto dapat memungkinkan pengguna 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.

Parameter input dan nilai yang ditampilkan

Untuk fleksibilitas yang lebih besar, Anda dapat meneruskan argumen ke tugas dan meminta tugas menampilkan hasilnya. Nilai yang diteruskan dan ditampilkan merupakan key-value pair. Untuk meneruskan argumen ke tugas, panggil metode WorkRequest.Builder.setInputData(Data) sebelum Anda membuat objek WorkRequest. Metode tersebut mengambil objek Data, yang Anda buat dengan Data.Builder. Class Worker dapat mengakses argumen tersebut dengan memanggil Worker.getInputData(). Untuk memperoleh output nilai yang ditampilkan, tugas harus menyertakannya di Result (misalnya, menampilkan) Result.success(Data). Anda dapat memperoleh output dengan mengamati WorkInfo tugas.

Misalnya, Anda memiliki class Worker yang melakukan penghitungan yang memerlukan waktu lama. Kode berikut menunjukkan seperti apa tampilan class Worker:

Kotlin

// Define the parameter keys:
const val KEY_X_ARG = "X"
const val KEY_Y_ARG = "Y"
const val KEY_Z_ARG = "Z"

// ...and the result key:
const val KEY_RESULT = "result"

// Define the Worker class:
class MathWorker(context : Context, params : WorkerParameters)
    : Worker(context, params)  {

    override fun doWork(): Result {
        val x = inputData.getInt(KEY_X_ARG, 0)
        val y = inputData.getInt(KEY_Y_ARG, 0)
        val z = inputData.getInt(KEY_Z_ARG, 0)

        // ...do the math...
        val result = myLongCalculation(x, y, z);

        //...set the output, and we're done!
        val output: Data = workDataOf(KEY_RESULT to result)

        return Result.success(output)
    }
}

Java

// Define the Worker class:
public class MathWorker extends Worker {

    // Define the parameter keys:
    public static final String KEY_X_ARG = "X";
    public static final String KEY_Y_ARG = "Y";
    public static final String KEY_Z_ARG = "Z";
    // ...and the result key:
    public static final String KEY_RESULT = "result";

    public MathWorker(
        @NonNull Context context,
        @NonNull WorkerParameters params) {
        super(context, params);
    }

    @Override
    public Result doWork() {
        // Fetch the arguments (and specify default values):
        int x = getInputData().getInt(KEY_X_ARG, 0);
        int y = getInputData().getInt(KEY_Y_ARG, 0);
        int z = getInputData().getInt(KEY_Z_ARG, 0);

        // ...do the math...
        int result = myLongCalculation(x, y, z);

        //...set the output, and we're done!
        Data output = new Data.Builder()
            .putInt(KEY_RESULT, result)
            .build();
        return Result.success(output);
    }
}

Untuk membuat tugas dan meneruskan argumen, Anda harus menggunakan kode seperti ini:

Kotlin

val myData: Data = workDataOf("KEY_X_ARG" to 42,
                       "KEY_Y_ARG" to 421,
                       "KEY_Z_ARG" to 8675309)

// ...then create and enqueue a OneTimeWorkRequest that uses those arguments
val mathWork = OneTimeWorkRequestBuilder<MathWorker>()
        .setInputData(myData)
        .build()
WorkManager.getInstance(myContext).enqueue(mathWork)

Java

// Create the Data object:
Data myData = new Data.Builder()
    // We need to pass three integers: X, Y, and Z
    .putInt(KEY_X_ARG, 42)
    .putInt(KEY_Y_ARG, 421)
    .putInt(KEY_Z_ARG, 8675309)
    // ... and build the actual Data object:
    .build();

// ...then create and enqueue a OneTimeWorkRequest that uses those arguments
OneTimeWorkRequest mathWork = new OneTimeWorkRequest.Builder(MathWorker.class)
        .setInputData(myData)
        .build();
WorkManager.getInstance(myContext).enqueue(mathWork);

Nilai yang ditampilkan akan tersedia di WorkInfo tugas:

Kotlin

WorkManager.getInstance(myContext).getWorkInfoByIdLiveData(mathWork.id)
        .observe(this, Observer { info ->
            if (info != null && info.state.isFinished) {
                val myResult = info.outputData.getInt(KEY_RESULT,
                      myDefaultValue)
                // ... do something with the result ...
            }
        })

Java

WorkManager.getInstance(myContext).getWorkInfoByIdLiveData(mathWork.getId())
    .observe(lifecycleOwner, info -> {
         if (info != null && info.getState().isFinished()) {
           int myResult = info.getOutputData().getInt(KEY_RESULT,
                  myDefaultValue));
           // ... do something with the result ...
         }
    });

Jika Anda merantai tugas, output dari satu tugas akan tersedia sebagai input untuk tugas berikutnya pada rantai tersebut. Jika berupa rantai sederhana, dengan satu OneTimeWorkRequest yang diikuti dengan satu OneTimeWorkRequestlain, tugas pertama menampilkan hasilnya dengan memanggil Result.success(Data), dan tugas berikutnya mengambil hasil tersebut dengan memanggil getInputData(). Jika rantainya lebih rumit—misalnya, karena beberapa tugas semuanya mengirim output ke satu tugas berikutnya—Anda dapat menentukan InputMerger di OneTimeWorkRequest.Builder untuk menetapkan apa yang akan terjadi jika tugas yang berbeda menampilkan output dengan kunci sama.

Referensi lainnya

Untuk mempelajari WorkManager lebih lanjut, lihat referensi tambahan berikut.

Contoh