1. はじめに
この Codelab は、高度な WorkManager のコンセプトについて説明しており、WorkManager を使用したバックグラウンド処理の Codelab で説明した基本事項に基づいています。
WorkManager について理解を深める際に有用な、以下に示すその他のリソースもご覧ください。
- WorkManager ガイド
- ブログシリーズ: WorkManager の紹介
- ADS 2019 WorkManager についての講演: WorkManager: 基本から応用へ
- WorkManager - MAD スキルシリーズ
作成するアプリの概要
この Codelab では、写真や画像にぼかしを入れて結果をファイルに保存するアプリ、Blur-O-Matic を作成します。バックグラウンド処理と WorkManager の Codelab をすでに完了している場合は、同様のサンプルアプリとなります(このサンプルアプリでは、ぼかしを入れるためにフォト ギャラリーから独自の画像を選択できる点が異なります)。ここでは、コードに以下の機能を追加します。
- カスタム構成
- Progress API を使用して、作業の実行中に UI を更新する
- ワーカーをテストする
必要なもの
この Codelab を実行するには、最新の Android Studio 安定版が必要です。
LiveData
、ViewModel
、View Binding
に習熟していることも必要です。これらのクラスを初めて使用する場合は、Android ライフサイクル対応コンポーネント Codelab(特に ViewModel および LiveData 向け)または Room と View Codelab(アーキテクチャ コンポーネントの概要)をご確認ください。
問題が発生した場合
いずれかの時点でこの Codelab に問題が生じた場合、またはコードの最終状態を確認することが必要な場合は、できます。
または、GitHub から完成した WorkManager Codelab のクローンを作成することもできます。
$ git clone -b advanced https://github.com/googlecodelabs/android-workmanager
2. 設定方法
ステップ 1 - コードをダウンロードする
次のリンクをクリックして、この Codelab の手順に沿って進めるために必要なバージョンのコードをダウンロードします。
または、GitHub から Codelab のクローンを作成することもできます。
$ git clone -b advanced_start https://github.com/googlecodelabs/android-workmanager
ステップ 2 - アプリを実行する
アプリを実行します。次の画面が表示されます。プロンプトが表示されたら、写真にアクセスするために必要な権限をアプリに付与します。
画像を選択して次の画面に進みます。この画面では、ラジオボタンで画像をどの程度ぼかすかを選択できます。[Go] ボタンを押すと、画像がぼかし加工されて保存されます。ぼかし加工の実行中に、作業を終了するための [キャンセル] ボタンがアプリに表示されます。
初期状態のコードには以下が含まれています。
WorkerUtils
: このクラスには、実際にぼかしを入れるコードと、後でNotifications
を表示したり、アプリを遅らせたりするのに使用するいくつかのメソッドが含まれています。BlurApplication
: デバッグビルド用に Timber ロギング システムを初期化するための、シンプルなonCreate()
メソッドを含むアプリケーション クラス。BlurActivity
: 画像を表示し、ぼかしの程度を選択するためのラジオボタンを含むアクティビティ。BlurViewModel
: このビューモデルには、BlurActivity
の表示に必要なすべてのデータが格納されています。WorkManager を使用してバックグラウンド処理を開始するクラスでもあります。Workers/CleanupWorker
: このワーカーは、一時ファイルが存在する場合に、常にそれを削除します。Workers/BlurWorker
: このワーカーは、URI によって入力データとして渡された画像をぼかし加工して、一時ファイルの URI を返します。Workers/SaveImageToFileWorker
: このワーカーは、一時的な画像の URI を入力として受け取り、最終的なファイルの URI を返します。Constants
: Codelab で使用する定数が含まれる静的クラス。SelectImageActivity
: 画像を選択するための最初のアクティビティ。res/activity_blur.xml
とres/activity_select.xml
: 各アクティビティのレイアウト ファイル。
BlurApplication
、BlurActivity
、BlurViewModel
、BlurWorker
の各クラスでコードを変更します。
3.アプリに WorkManager を追加する
WorkManager
には、下記の Gradle 依存関係が必要です。依存関係は、すでに次のファイルに含まれています。
app/build.gradle
dependencies {
implementation "androidx.work:work-runtime-ktx:$versions.work"
}
WorkManager リリースページから work-runtime
の最新バージョンを入手し、最新の安定版リリースのバージョンを挿入するか、以下を使用してください。
build.gradle
versions.work = "2.7.1"
[Sync Now] をクリックし、変更された Gradle ファイルとプロジェクトを同期するようにしてください。
4. WorkManager のカスタム構成を追加する
このステップでは、カスタム構成をアプリに追加して、デバッグビルド用に WorkManager のロギングレベルを変更します。
ステップ 1 - デフォルトの初期化を無効にする
WorkManager のカスタム構成と初期化のドキュメントで説明されているように、デフォルトで WorkManager ライブラリから自動的にマージされるノードを削除して、AndroidManifest.xml
ファイルでデフォルトの初期化を無効にする必要があります。
このノードを削除するには、以下に示すように新しいプロバイダ ノードを AndroidManifest.xml
に追加します。
AndroidManifest.xml
<application
...
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
</application>
マニフェストにツールの名前空間を追加する必要もあります。これらの変更を実行した完成形のファイルは次のとおりです。
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>
ステップ 2 - Application クラスに Configuration.Provider を追加する
Application
クラスに WorkManager の Configuration.Provider
インターフェースを実装すると、オンデマンド初期化を使用できます。アプリが初めて getInstance(context)
を使用して WorkManager のインスタンスを取得すると、WorkManager は getWorkManagerConfiguration()
から返された構成を使用して自身を初期化します。
BlurApplication.kt
class BlurApplication : Application(), Configuration.Provider {
override fun getWorkManagerConfiguration(): Configuration =
Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.DEBUG)
.build()
...
}
この変更により、ロギングが DEBUG
に設定された状態で WorkManager が実行されます。
より適切なオプションとしては、これと同じ方法で、次のようなコードを使用して、アプリのデバッグビルドのみを目的として WorkManager をセットアップすることが挙げられます。
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 は次のようになります。
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())
}
}
}
ステップ 3 - デバッグモードでアプリを実行する
デバッグビルドがライブラリから受信したすべてのメッセージをログに記録するように、WorkManager が構成されました。
アプリを実行すると、Android Studio の [logcat
] タブでログを確認できます。
ステップ 4 - 構成可能な要素
パラメータの全一覧については、Configuration.Builder
に関する WorkManager のリファレンス ガイドをご覧ください。次の 2 つの追加パラメータに注意してください。
WorkerFactory
JobId
の範囲
WorkerFactory
を変更すると、ワーカーのコンストラクタに他のパラメータを追加できます。カスタム WorkerFactory の実装方法について詳しくは、こちらの WorkManager のカスタマイズの記事をご覧ください。アプリで WorkManager と JobScheduler
API を併用する場合は、JobId
の範囲をカスタマイズして、2 つの API で同じ JobId
範囲が使用されないようにすることをおすすめします。
WorkManager の進行状況の共有
WorkManager v2.3 では、setProgressAsync()
(または、CoroutineWorker
から使用されている場合は setProgress()
)を使用してワーカーから取得した進行状況の情報をアプリと共有する機能が追加されています。この情報は WorkInfo で確認でき、UI でユーザーにフィードバックを提供することを目的として使用するためのものです。ワーカーが最終状態(SUCCEEDED、FAILED、または CANCELLED)に達すると、進行状況のデータはキャンセルされます。進行状況を公開してリッスンする方法の詳細については、ワーカーの中間進行状況の監視をご覧ください。
次に、進行状況を示すバーを UI に追加します。これにより、アプリがフォアグラウンドにある場合、ユーザーはぼかし処理の進行状況を確認できます。最終的な結果は次のようになります。
ステップ 1 - ProgressBar
を変更する
レイアウトで ProgressBar を変更するには、android:indeterminate="true"
パラメータを削除し、スタイル style="@android:style/Widget.ProgressBar.Horizontal",
を追加して、初期値を android:progress="0"
に設定する必要があります。さらに、LinearLayout
の向きを "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>
必要なもう一つの変更は、ProgressBar
が初期位置で再開するようにすることです。そのためには、BlurActivity.kt
ファイルの showWorkFinished()
関数を更新します。
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
}
}
ステップ 2 - ViewModel の進行状況に関する情報を監視する
BlurViewModel
ファイルには、チェーンの完了を確認するオブザーバーがすでに存在します。BlurWorker
によって送信された進行状況に関する情報を監視するための新しいオブザーバーを追加します。
まず、進行状況をトラッキングするための 2 つの定数を Constants.kt
ファイルの末尾に追加します。
app/src/main/java/com/example/background/Constants.kt
// Progress Data Key
const val PROGRESS = "PROGRESS"
const val TAG_PROGRESS = "TAG_PROGRESS"
次ステップでは、このタグを BlurViewModel.kt
ファイルの BlurWorker
の WorkRequest
に追加して、WorkInfo
を取得できるようにします。この WorkInfo
から、ワーカーの進行状況に関する情報を取得できます。
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())
}
この WorkRequest
をトラッキングする BlurViewModel.kt
ファイルに新しい LiveData
を追加し、init
ブロックで LiveData
を初期化します。
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
}
...
}
ステップ 3 - アクティビティの LiveData を監視する
BlurActivity
の LiveData
を使用して、公開されたすべての進行状況を監視できるようになりました。まず、onCreate()
メソッドの末尾に、新しい LiveData
オブザーバーを登録します。
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())
これでオブザーバーが受信した WorkInfo
を確認し、進行状況に関する情報があるかどうかを確認して、それに応じて ProgressBar
を更新できるようになりました。
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
}
}
}
}
ステップ 4 - BlurWorker の進行状況を公開する
進行状況に関する情報の表示に必要な要素がすべて揃いました。次に、進行状況に関する情報の実際の公開を BlurWorker
に追加します。
この例では、一定期間にわたる進行状況に関して情報を公開できるよう、doWork()
関数で長いプロセスをシンプルにシミュレートしています。
ここでの変更は、1 つの遅延を 10 件の小さな遅延に置き換え、イテレーションごとに新しい進行状況を設定することを目的としています。
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()
}
...
}
元の遅延が 3 秒であったため、係数 10 によって 0.3 秒に短縮するのもよいでしょう。
app/src/main/java/com/example/background/Constants.kt
// const val DELAY_TIME_MILLIS: Long = 3000
const val DELAY_TIME_MILLIS: Long = 300
ステップ 5 - 実行する
この時点でアプリケーションを実行すると、BlurWorker
から受信したメッセージが入力された ProgressBar が表示されます。
5. WorkManager をテストする
テストの実行はすべてのアプリにおいて重要なコンポーネントであり、WorkManager などのライブラリを導入する際は、コードを簡単にテストするためのツールを用意することが重要です。
また、WorkManager には、ワーカーを簡単にテストできるヘルパーも用意されています。ワーカーのテストを作成する方法の詳細については、テストに関する WorkManager のドキュメントをご覧ください。
Codelab のこのセクションでは、一般的なユースケースのいくつかを示すワーカークラスのテストを紹介します。
まず、テストを簡単にセットアップできるように、WorkManager をセットアップする TestRule を作成します。
- 依存関係を追加する
WorkManagerTestRule
とTestUtils
を作成するCleanupWorker
用のテストを作成するBlurWorker
用のテストを作成する
プロジェクトで AndroidTest フォルダをすでに作成していることを前提として、テストで使用する依存関係を追加する必要があります。
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"
これで、TestRule で各要素をまとめて、テストで使用できるようになりました。
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)
}
}
デバイス(テストを実行するデバイス)にこのテスト画像が必要になるため、テストで使用するヘルパー関数をいくつか作成します。
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
}
この作業が完了したら、テストの作成を開始できます。
まず、CleanupWorker
をテストして、実際にファイルが削除されることを確認します。これを行うには、テスト中のデバイスでテスト画像をコピーし、CleanupWorker
の実行後に同じ場所に存在するかどうかを確認します。
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))
}
}
このテストは、Android Studio の [Run] メニューから、またはテストクラスの左側にある緑色の長方形を使用することで実行できます。
プロジェクトのルートフォルダからコマンド ./gradlew cAT
を使用することで、コマンドラインからテストを実行することもできます。
テストが正しく実行されていることを確認します。
次に、BlurWorker をテストします。このワーカーは、画像の URI を含む入力データが処理されることを想定しています。そのため、2 つのテストをビルドします。1 つ目のテストでは、入力 URI がない場合にワーカーが失敗することを確認し、もう 2 つ目のテストでは入力画像が実際に処理されることを確認します。
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))
}
}
これらのテストを実行すると、両方とも成功します。
6. 完了
これで、Blur-O-Matic アプリが完成しました。このプロセスでは、以下の方法について学びました。
- カスタム構成を作成する
- ワーカーの進行状況を公開する
- UI に作業の進行状況を表示する
- ワーカーのテストを作成する
作業は適切に完了しました。最終状態のコードとすべての変更を確認するには、以下をご覧ください。
または、GitHub から WorkManager の Codelab のクローンを作成することもできます。
$ git clone -b advanced https://github.com/googlecodelabs/android-workmanager
WorkManager は、この Codelab で取り扱った機能以外にも多くの機能をサポートしています。詳細については、WorkManager のドキュメントをご覧ください。