WorkManager Lanjutan

1. Pengantar

Codelab ini menjelaskan konsep WorkManager lanjutan. Fitur ini dibuat berdasarkan material dasar yang tercakup dalam codelab Pekerjaan Latar Belakang dengan WorkManager.

Resource lain yang tersedia untuk membiasakan diri Anda mengenal WorkManager adalah:

Yang akan Anda buat

Dalam codelab ini, Anda akan menjalankan Blur-O-Matic, sebuah aplikasi untuk memburamkan foto dan gambar serta menyimpan hasilnya ke file. Jika Anda telah menyelesaikan codelab Pekerjaan Latar Belakang dengan WorkManager, ini adalah aplikasi contoh serupa (satu perbedaannya adalah aplikasi contoh ini memungkinkan Anda memilih gambar Anda sendiri dari galeri foto untuk diburamkan). Di sini, Anda akan menambahkan beberapa fitur ke kode:

  1. Konfigurasi kustom
  2. Gunakan Progress API untuk mengupdate UI saat pekerjaan Anda dijalankan
  3. Uji Pekerja Anda

Yang akan Anda butuhkan

Untuk melakukan codelab ini, Anda memerlukan versi stabil Android Studio terbaru.

Anda juga harus memahami LiveData, ViewModel, dan View Binding. Jika Anda masih baru di class ini, lihat Codelab komponen berbasis Siklus Proses Android (khusus untuk ViewModel dan LiveData) atau Room dengan Tampilan Codelab (pengantar Komponen Arsitektur).

Jika Anda mengalami masalah pada tahap tertentu

Jika Anda mengalami masalah dengan codelab di tahap tertentu, atau jika Anda ingin melihat status akhir kode, Anda dapat

Atau jika mau, Anda dapat meng-clone codelab WorkManager yang telah selesai dari GitHub:

$ git clone -b advanced https://github.com/googlecodelabs/android-workmanager

2. Mempersiapkan

Langkah 1 - Download Kode

Untuk mengikuti codelab ini, klik link berikut untuk mendownload versi kode:

Atau jika mau, Anda dapat meng-clone codelab dari GitHub:

$ git clone -b advanced_start https://github.com/googlecodelabs/android-workmanager

Langkah 2 - Jalankan aplikasi

Jalankan aplikasi. Anda akan melihat layar berikut. Pastikan Anda telah mengizinkan aplikasi agar dapat mengakses foto Anda saat diminta.

Layar awal aplikasi yang meminta pengguna untuk memilih gambar dari galeri foto.

Layar ditampilkan kepada pengguna setelah gambar dipilih dari galeri, dengan tombol pilihan untuk tingkat keburaman yang diinginkan dan tombol Go untuk memulai proses pemburaman.

Anda dapat memilih gambar dan membuka layar berikutnya yang memiliki tombol pilihan. Di layar tersebut, Anda dapat menentukan tingkat keburaman gambar. Menekan tombol Go akan memburamkan dan menyimpan gambar. Selama pemburaman, aplikasi akan menampilkan tombol Cancel agar Anda dapat mengakhiri pekerjaan.

Permintaan WorkManager sedang berlangsung dengan notifikasi yang muncul di bagian atas dan indikator lingkaran berputar pemuatan di bagian bawah.

Kode awal berisi:

  • WorkerUtils: Class ini berisi kode untuk pemburaman yang sebenarnya, dan beberapa metode praktis yang nantinya akan digunakan untuk menampilkan Notifications dan memperlambat aplikasi.
  • BlurApplication: Class aplikasi dengan metode onCreate() sederhana untuk menginisialisasi sistem logging Timber untuk build debug.
  • BlurActivity: Aktivitas yang menampilkan gambar dan menyertakan tombol pilihan untuk memilih tingkat keburaman.
  • BlurViewModel: Model tampilan ini menyimpan semua data yang diperlukan untuk menampilkan BlurActivity. Model ini juga akan menjadi class tempat Anda memulai pekerjaan latar belakang menggunakan WorkManager.
  • Workers/CleanupWorker: Pekerja ini selalu menghapus file sementara, jika ada.
  • Workers/BlurWorker: Pekerja ini memburamkan gambar yang diteruskan sebagai data input dengan URI, dan menampilkan URI file sementara.
  • Workers/SaveImageToFileWorker: Pekerja ini mengambil URI gambar sementara sebagai input dan menampilkan URI file akhir.
  • Constants: Class statis dengan beberapa konstanta yang akan Anda gunakan selama codelab.
  • SelectImageActivity: Aktivitas pertama yang memungkinkan Anda untuk memilih gambar.
  • res/activity_blur.xml dan res/activity_select.xml: File tata letak untuk setiap aktivitas.

Anda akan membuat perubahan kode di class berikut: BlurApplication, BlurActivity, BlurViewModel, dan BlurWorker.

3. Menambahkan WorkManager ke aplikasi Anda

WorkManager memerlukan dependensi gradle di bawah ini. Dependensi ini sudah disertakan dalam file:

app/build.gradle

dependencies {
    implementation "androidx.work:work-runtime-ktx:$versions.work"
}

Anda harus mendapatkan versi work-runtime terbaru dari halaman rilis WorkManager dan menempatkan versi rilis stabil terbaru, atau menggunakan versi di bawah ini:

build.gradle

versions.work = "2.7.1"

Pastikan Anda mengklik Sync Now untuk menyinkronkan project dengan file Gradle yang telah diubah.

4. Menambahkan konfigurasi kustom WorkManager

Dalam langkah ini, Anda akan menambahkan konfigurasi kustom ke aplikasi untuk mengubah level logging WorkManager untuk build debug.

Langkah 1 - Nonaktifkan inisialisasi default

Seperti yang telah dijelaskan dalam dokumentasi Konfigurasi dan Inisialisasi WorkManager Kustom, Anda harus menonaktifkan inisialisasi default di file AndroidManifest.xml dengan menghapus node yang otomatis digabungkan dari library WorkManager secara default.

Untuk menghapus node ini, Anda dapat menambahkan node penyedia baru ke AndroidManifest.xml, seperti yang ditampilkan di bawah ini:

AndroidManifest.xml

<application

...

    <provider
        android:name="androidx.work.impl.WorkManagerInitializer"
        android:authorities="${applicationId}.workmanager-init"
        tools:node="remove" />
</application>

Anda juga perlu menambahkan namespace alat ke manifes. File lengkap dengan perubahan ini akan menjadi:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->

<manifest package="com.example.background"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:name=".BlurApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".SelectImageActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".BlurActivity" />

        <!-- ADD THE FOLLOWING NODE -->
        <provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="${applicationId}.workmanager-init"
            tools:node="remove" />
    </application>
</manifest>

Langkah 2 - Tambahkan Configuration.Provider ke class Aplikasi

Anda dapat menggunakan inisialisasi on demand dengan menerapkan antarmuka Configuration.Provider WorkManager di class Application. Saat pertama kali aplikasi mendapatkan instance WorkManager yang menggunakan getInstance(context), WorkManager menginisialisasi dirinya sendiri menggunakan konfigurasi yang ditampilkan oleh getWorkManagerConfiguration().

BlurApplication.kt

class BlurApplication : Application(), Configuration.Provider {

    override fun getWorkManagerConfiguration(): Configuration =

        Configuration.Builder()
                     .setMinimumLoggingLevel(android.util.Log.DEBUG)
                     .build()
...
}

Dengan perubahan ini, WorkManager berjalan dengan logging yang telah disetel ke DEBUG.

Opsi yang lebih baik mungkin menyiapkan WorkManager dengan cara ini hanya untuk build debug aplikasi Anda, menggunakan sesuatu seperti:

BlurApplication.kt

class BlurApplication() : Application(), Configuration.Provider {

    override fun getWorkManagerConfiguration(): Configuration {
        return if (BuildConfig.DEBUG) {
            Configuration.Builder()
                    .setMinimumLoggingLevel(android.util.Log.DEBUG)
                    .build()
        } else {
            Configuration.Builder()
                    .setMinimumLoggingLevel(android.util.Log.ERROR)
                    .build()
        }
    }

...
}

BlurApplication.kt yang lengkap kemudian menjadi:

BlurApplication.kt

/* Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 */

package com.example.background

import android.app.Application
import androidx.work.Configuration
import timber.log.Timber
import timber.log.Timber.DebugTree

class BlurApplication() : Application(), Configuration.Provider {

    override fun getWorkManagerConfiguration(): Configuration {
        return if (BuildConfig.DEBUG) {
            Configuration.Builder()
                    .setMinimumLoggingLevel(android.util.Log.DEBUG)
                    .build()
        } else {
            Configuration.Builder()
                    .setMinimumLoggingLevel(android.util.Log.ERROR)
                    .build()
        }
    }

    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) {
            Timber.plant(DebugTree())
        }
    }
}

Langkah 3 - Jalankan aplikasi dalam mode debug

WorkManager kini sudah dikonfigurasikan sehingga build debug Anda membuat log semua pesan yang berasal dari library.

Saat menjalankan aplikasi, Anda dapat melihat log di tab logcat Android Studio:

5f3522812d1bfb18.png

Langkah 4 - Apa yang dapat Anda konfigurasi?

Daftar lengkap parameter ada dalam panduan referensi WorkManager untuk Configuration.Builder. Perhatikan dua parameter tambahan:

  • WorkerFactory
  • Rentang JobId

Mengubah WorkerFactory memungkinkan penambahan parameter lain ke konstruktor Worker Anda. Anda dapat menemukan informasi cara menerapkan WorkerFactory khusus lebih lanjut dalam artikel Menyesuaikan WorkManager ini. Jika Anda menggunakan WorkManager serta JobScheduler API di aplikasi, sebaiknya sesuaikan rentang JobId untuk menghindari rentang JobId yang sama digunakan oleh kedua API tersebut.

Berbagi Progres WorkManager

WorkManager v2.3 menambahkan fungsi untuk membagikan informasi progres dari Pekerja ke aplikasi Anda menggunakan setProgressAsync() (atau setProgress() saat digunakan dari CoroutineWorker). Informasi ini dapat dilihat melalui WorkInfo, dan dimaksudkan untuk digunakan agar dapat memberikan masukan di dalam UI kepada pengguna. Data progres kemudian dibatalkan jika pekerja telah mencapai status akhir (BERHASIL, GAGAL, atau DIBATALKAN). Untuk mengetahui cara memublikasikan dan mendeteksi progres lebih lanjut, baca Mengamati progres Pekerja tingkat menengah.

Selanjutnya, Anda akan menambahkan status progres di UI sehingga jika aplikasi berada di latar depan, pengguna dapat melihat proses pemburaman. Hasil akhirnya akan terlihat seperti ini:

Permintaan WorkManager sedang berlangsung, seperti yang ditunjukkan oleh status progres yang ditampilkan di bagian bawah layar.

Langkah 1 - Ubah ProgressBar

Untuk mengubah ProgressBar di tata letak, Anda perlu menghapus parameter android:indeterminate="true", menambahkan gaya style="@android:style/Widget.ProgressBar.Horizontal",, dan menetapkan nilai awal dengan android:progress="0". Anda juga perlu menyetel orientasi LinearLayout ke "vertical":

app/src/main/res/layout/activity_blur.xml

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <ProgressBar
        android:id="@+id/progress_bar"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:progress="0"
        android:visibility="gone"
        android:layout_gravity="center_horizontal"
        />

    <Button
        android:id="@+id/cancel_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/cancel_work"
        android:visibility="gone"
        />
</LinearLayout>

Perubahan lain yang diperlukan adalah memastikan bahwa ProgressBar memulai ulang di posisi awal. Anda dapat melakukannya dengan mengupdate fungsi showWorkFinished() dalam file BlurActivity.kt:

app/src/main/java/com/example/background/BlurActivity.kt

/**
 * Shows and hides views for when the Activity is done processing an image
 */
private fun showWorkFinished() {
    with(binding) {
        progressBar.visibility = View.GONE
        cancelButton.visibility = View.GONE
        goButton.visibility = View.VISIBLE
        progressBar.progress = 0 // <-- ADD THIS LINE
    }
}

Langkah 2 - Amati informasi progres di ViewModel

Terdapat observer dalam file BlurViewModel yang akan memeriksa saat rantai Anda selesai. Tambahkan observer baru yang mengamati progres yang diposting oleh BlurWorker.

Pertama, tambahkan beberapa konstanta untuk melacak progres di akhir file Constants.kt:

app/src/main/java/com/example/background/Constants.kt

// Progress Data Key
const val PROGRESS = "PROGRESS"
const val TAG_PROGRESS = "TAG_PROGRESS"

Langkah selanjutnya adalah menambahkan tag ini ke WorkRequest BlurWorker dalam file BlurViewModel.kt sehingga Anda dapat mengambil WorkInfo-nya. Dari WorkInfo tersebut, Anda dapat mengambil informasi progres pekerja:

app/src/main/java/com/example/background/BlurViewModel.kt

// Add WorkRequests to blur the image the number of times requested
for (i in 0 until blurLevel) {
    val blurBuilder = OneTimeWorkRequestBuilder<BlurWorker>()

    // Input the Uri if this is the first blur operation
    // After the first blur operation the input will be the output of previous
    // blur operations.
    if (i == 0) {
        blurBuilder.setInputData(createInputDataForUri())
    }

    blurBuilder.addTag(TAG_PROGRESS) // <-- ADD THIS
    continuation = continuation.then(blurBuilder.build())
}

Tambahkan LiveData baru ke file BlurViewModel.kt yang akan melacak WorkRequest ini, dan melakukan inisialisasi LiveData di blok init:

app/src/main/java/com/example/background/BlurViewModel.kt

class BlurViewModel(application: Application) : AndroidViewModel(application) {

    internal var imageUri: Uri? = null
    internal var outputUri: Uri? = null
    internal val outputWorkInfoItems: LiveData<List<WorkInfo>>
    internal val progressWorkInfoItems: LiveData<List<WorkInfo>> // <-- ADD THIS
    private val workManager: WorkManager = WorkManager.getInstance(application)

    init {
        // This transformation makes sure that whenever the current work Id changes the WorkStatus
        // the UI is listening to changes
        outputWorkInfoItems = workManager.getWorkInfosByTagLiveData(TAG_OUTPUT)
        progressWorkInfoItems = workManager.getWorkInfosByTagLiveData(TAG_PROGRESS) // <-- ADD THIS
    }

...
}

Langkah 3 - Amati LiveData di Aktivitas

Anda sekarang dapat menggunakan LiveData ini di BlurActivity untuk mengamati semua progres yang telah dipublikasikan. Pertama, daftarkan observer LiveData baru di akhir metode onCreate():

app/src/main/java/com/example/background/BlurActivity.kt

// Show work status
viewModel.outputWorkInfoItems.observe(this, outputObserver())

// ADD THE FOLLOWING LINES
// Show work progress
viewModel.progressWorkInfoItems.observe(this, progressObserver())

Sekarang Anda dapat memeriksa WorkInfo yang diterima oleh observer untuk mengetahui adanya informasi progres dan mengupdate ProgressBar sesuai informasi tersebut:

app/src/main/java/com/example/background/BlurActivity.kt

private fun progressObserver(): Observer<List<WorkInfo>> {
    return Observer { listOfWorkInfo ->
        if (listOfWorkInfo.isNullOrEmpty()) {
            return@Observer
        }

        listOfWorkInfo.forEach { workInfo ->
            if (WorkInfo.State.RUNNING == workInfo.state) {
                val progress = workInfo.progress.getInt(PROGRESS, 0)
                binding.progressBar.progress = progress
            }
        }

    }
}

Langkah 4 - Publikasikan Progres dari BlurWorker

Kini tersedia semua bagian yang diperlukan untuk menampilkan informasi progres. Saatnya menambahkan publikasi informasi progres yang sebenarnya ke BlurWorker.

Contoh ini hanya menyimulasikan beberapa proses panjang dalam fungsi doWork() kami sehingga dapat memublikasikan informasi progres selama jangka waktu yang ditentukan.

Perubahan di sini adalah untuk menukar satu penundaan dengan 10 penundaan yang lebih kecil, menetapkan progres baru pada setiap iterasi:

app/src/main/java/com/example/background/workers/BlurWorker.kt

override fun doWork(): Result {
    val appContext = applicationContext

    val resourceUri = inputData.getString(KEY_IMAGE_URI)

    makeStatusNotification("Blurring image", appContext)
    // sleep()
    (0..100 step 10).forEach {
        setProgressAsync(workDataOf(PROGRESS to it))
        sleep()
    }

...
}

Karena keterlambatan aktual yang dapat ditoleransi adalah 3 detik, sebaiknya kurangi keterlambatan itu 10 kali hingga menjadi 0,3 detik:

app/src/main/java/com/example/background/Constants.kt

// const val DELAY_TIME_MILLIS: Long = 3000
const val DELAY_TIME_MILLIS: Long = 300

Langkah 5 - Jalankan

Pada tahap ini, menjalankan aplikasi seharusnya menampilkan ProgressBar yang diisi dengan pesan yang berasal dari BlurWorker.

5. Menguji WorkManager

Pengujian adalah komponen penting dari setiap aplikasi. Ketika memperkenalkan library seperti WorkManager, penting untuk menyediakan alat agar mudah menguji kode.

Dengan WorkManager, beberapa bantuan juga disediakan untuk memudahkan pengujian Pekerja. Untuk mengetahui cara membuat pengujian untuk Pekerja lebih lanjut, Anda dapat membaca dokumentasi WorkManager tentang pengujian.

Di bagian codelab ini, kami akan memperkenalkan beberapa pengujian untuk class Pekerja yang menampilkan beberapa kasus penggunaan umum.

Pertama, kami ingin memberikan cara mudah untuk menyiapkan pengujian. Untuk melakukannya, Anda dapat membuat TestRule yang menyiapkan WorkManager:

  • Tambahkan Dependensi
  • Buat WorkManagerTestRule dan TestUtils
  • Buat Pengujian untuk CleanupWorker
  • Buat Pengujian untuk BlurWorker

Dengan asumsi bahwa Anda telah membuat folder AndroidTest di project, Anda perlu menambahkan beberapa dependensi agar dapat digunakan dalam pengujian kami:

app/build.gradle

androidTestImplementation "androidx.arch.core:core-testing:2.1.0"
androidTestImplementation "androidx.test.ext:junit:1.1.3"
androidTestImplementation "androidx.test:rules:1.4.0"
androidTestImplementation "androidx.test:runner:1.4.0"
androidTestImplementation "androidx.work:work-testing:$versions.work"

Sekarang Anda bisa mulai menyusun bagian dengan TestRule yang dapat digunakan dalam pengujian:

app/src/androidTest/java/com/example/background/workers/WorkManagerTestRule.kt

/* Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 */

package com.example.background.workers

import android.content.Context
import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import androidx.work.Configuration
import androidx.work.WorkManager
import androidx.work.testing.SynchronousExecutor
import androidx.work.testing.WorkManagerTestInitHelper
import org.junit.rules.TestWatcher
import org.junit.runner.Description

class WorkManagerTestRule : TestWatcher() {
    lateinit var targetContext: Context
    lateinit var testContext: Context
    lateinit var configuration: Configuration
    lateinit var workManager: WorkManager

    override fun starting(description: Description?) {
        targetContext = InstrumentationRegistry.getInstrumentation().targetContext
        testContext = InstrumentationRegistry.getInstrumentation().context
        configuration = Configuration.Builder()
                // Set log level to Log.DEBUG to make it easier to debug
                .setMinimumLoggingLevel(Log.DEBUG)
                // Use a SynchronousExecutor here to make it easier to write tests
                .setExecutor(SynchronousExecutor())
                .build()

        // Initialize WorkManager for instrumentation tests.
        WorkManagerTestInitHelper.initializeTestWorkManager(targetContext, configuration)
        workManager = WorkManager.getInstance(targetContext)
    }
}

Karena Anda memerlukan gambar pengujian ini dalam perangkat (tempat pengujian akan dijalankan), Anda dapat membuat beberapa fungsi bantuan untuk digunakan dalam pengujian:

app/src/androidTest/java/com/example/background/workers/TestUtils.kt

/* Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 */

package com.example.background.workers

import android.content.Context
import android.graphics.BitmapFactory
import android.net.Uri
import com.example.background.OUTPUT_PATH
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.util.UUID

/**
 * Copy a file from the asset folder in the testContext to the OUTPUT_PATH in the target context.
 * @param testCtx android test context
 * @param targetCtx target context
 * @param filename source asset file
 * @return Uri for temp file
 */
@Throws(Exception::class)
fun copyFileFromTestToTargetCtx(testCtx: Context, targetCtx: Context, filename: String): Uri {
    // Create test image
    val destinationFilename = String.format("blur-test-%s.png", UUID.randomUUID().toString())
    val outputDir = File(targetCtx.filesDir, OUTPUT_PATH)
    if (!outputDir.exists()) {
        outputDir.mkdirs()
    }
    val outputFile = File(outputDir, destinationFilename)

    val bis = BufferedInputStream(testCtx.assets.open(filename))
    val bos = BufferedOutputStream(FileOutputStream(outputFile))
    val buf = ByteArray(1024)
    bis.read(buf)
    do {
        bos.write(buf)
    } while (bis.read(buf) != -1)
    bis.close()
    bos.close()

    return Uri.fromFile(outputFile)
}

/**
 * Check if a file exists in the given context.
 * @param testCtx android test context
 * @param uri for the file
 * @return true if file exist, false if the file does not exist of the Uri is not valid
 */
fun uriFileExists(targetCtx: Context, uri: String?): Boolean {
    if (uri.isNullOrEmpty()) {
        return false
    }

    val resolver = targetCtx.contentResolver

    // Create a bitmap
    try {
        BitmapFactory.decodeStream(
                resolver.openInputStream(Uri.parse(uri)))
    } catch (e: FileNotFoundException) {
        return false
    }
    return true
}

Setelah menyelesaikan tugas ini, Anda dapat mulai menulis pengujian.

Pertama, kita uji CleanupWorker untuk memeriksa bahwa file tersebut telah benar-benar dihapus. Untuk melakukannya, salin gambar pengujian di perangkat yang akan diuji, lalu periksa apakah gambar masih ada di sana setelah CleanupWorker dijalankan:

app/src/androidTest/java/com/example/background/workers/CleanupWorkerTest.kt

/* Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 */

package com.example.background.workers

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkInfo
import org.hamcrest.CoreMatchers.`is`
import org.junit.Assert.assertThat
import org.junit.Rule
import org.junit.Test

class CleanupWorkerTest {

    @get:Rule
    var instantTaskExecutorRule = InstantTaskExecutorRule()
    @get:Rule
    var wmRule = WorkManagerTestRule()

    @Test
    fun testCleanupWork() {
        val testUri = copyFileFromTestToTargetCtx(
                wmRule.testContext, wmRule.targetContext, "test_image.png")
        assertThat(uriFileExists(wmRule.targetContext, testUri.toString()), `is`(true))

        // Create request
        val request = OneTimeWorkRequestBuilder<CleanupWorker>().build()

        // Enqueue and wait for result. This also runs the Worker synchronously
        // because we are using a SynchronousExecutor.
        wmRule.workManager.enqueue(request).result.get()
        // Get WorkInfo
        val workInfo = wmRule.workManager.getWorkInfoById(request.id).get()

        // Assert
        assertThat(uriFileExists(wmRule.targetContext, testUri.toString()), `is`(false))
        assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED))
    }
}

Anda sekarang dapat menjalankan pengujian ini dari Android Studio melalui menu Run, atau menggunakan kotak hijau di sisi kiri class pengujian:

be955a84b5b00400.png

Anda juga dapat menjalankan pengujian dari command line menggunakan perintah ./gradlew cAT dari folder root project.

Anda akan melihat bahwa pengujian Anda dijalankan dengan benar.

Selanjutnya kita dapat menguji BlurWorker. Pekerja mengandalkan data input dengan URI gambar untuk diproses sehingga Anda dapat membuat beberapa pengujian: pengujian yang memeriksa apakah pekerja gagal jika tidak ada URI input, dan pengujian yang benar-benar memproses gambar input.

app/src/androidTest/java/com/example/background/workers/BlurWorkerTest.kt

/* Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 */

package com.example.background.workers

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.workDataOf
import org.hamcrest.CoreMatchers.`is`
import org.junit.Assert.assertThat
import org.junit.Rule
import com.example.background.KEY_IMAGE_URI
import org.junit.Test

class BlurWorkerTest {

    @get:Rule
    var instantTaskExecutorRule = InstantTaskExecutorRule()
    @get:Rule
    var wmRule = WorkManagerTestRule()

    @Test
    fun testFailsIfNoInput() {
        // Define input data

        // Create request
        val request = OneTimeWorkRequestBuilder<BlurWorker>().build()

        // Enqueue and wait for result. This also runs the Worker synchronously
        // because we are using a SynchronousExecutor.
        wmRule.workManager.enqueue(request).result.get()
        // Get WorkInfo
        val workInfo = wmRule.workManager.getWorkInfoById(request.id).get()

        // Assert
        assertThat(workInfo.state, `is`(WorkInfo.State.FAILED))
    }

    @Test
    @Throws(Exception::class)
    fun testAppliesBlur() {
        // Define input data
        val inputDataUri = copyFileFromTestToTargetCtx(
                wmRule.testContext,
                wmRule.targetContext,
                "test_image.png")
        val inputData = workDataOf(KEY_IMAGE_URI to inputDataUri.toString())

        // Create request
        val request = OneTimeWorkRequestBuilder<BlurWorker>()
                .setInputData(inputData)
                .build()

        // Enqueue and wait for result. This also runs the Worker synchronously
        // because we are using a SynchronousExecutor.
        wmRule.workManager.enqueue(request).result.get()
        // Get WorkInfo
        val workInfo = wmRule.workManager.getWorkInfoById(request.id).get()
        val outputUri = workInfo.outputData.getString(KEY_IMAGE_URI)

        // Assert
        assertThat(uriFileExists(wmRule.targetContext, outputUri), `is`(true))
        assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED))
    }
}

Jika Anda menjalankan pengujian ini, keduanya akan berhasil.

6. Selamat

Selamat! Anda telah menyelesaikan aplikasi Blur-O-Matic, dan dalam proses ini Anda telah mempelajari cara:

  • Membuat konfigurasi kustom
  • Memublikasikan progres dari Pekerja Anda
  • Menampilkan progres tugas di UI
  • Menulis pengujian untuk Pekerja Anda

Kerja bagus! Untuk melihat status akhir kode dan semua perubahan, lihat:

Atau jika mau, Anda bisa menggabungkan codelab WorkManager dari GitHub:

$ git clone -b advanced https://github.com/googlecodelabs/android-workmanager

WorkManager mendukung banyak hal, lebih dari yang dapat kita bahas dalam codelab ini. Untuk mempelajari lebih lanjut, buka dokumentasi WorkManager.