Android WorkManager 2026年完全ガイド:バックグラウンドタスク、制約条件、面接対策
Android WorkManagerを使ったバックグラウンド処理の実装方法を詳しく解説。制約条件の設定、定期実行、チェーン処理、2026年の技術面接でよく問われる質問まで網羅的にカバー。

2026年現在、Android WorkManagerはバックグラウンドタスクを処理するための標準ソリューションとして確立されています。Android 15のバッテリー最適化強化により、アプリがバックグラウンドで確実にタスクを実行することがこれまで以上に重要になっています。WorkManagerは、アプリが終了した後やデバイスが再起動した後でも、遅延可能で信頼性の高い非同期タスクを実行するためのAndroid Jetpackライブラリです。本記事では、WorkManagerの基本概念から高度な使用方法、そして2026年の技術面接でよく問われる質問について詳しく解説します。
WorkManagerは、JobScheduler、AlarmManager、Firebase JobDispatcherの機能を統合し、APIレベル21以上で一貫した動作を保証します。タスクの制約条件(ネットワーク接続、充電状態など)を宣言的に指定でき、システムがタスクの最適な実行タイミングを自動的に決定します。Foreground Serviceが即時実行を必要とするタスク向けであるのに対し、WorkManagerは遅延可能だが確実に実行されるべきタスクに最適です。
WorkManagerの基本:OneTimeWorkRequestとWorkerクラス
WorkManagerの基本的な構成要素は、WorkerクラスとWorkRequestです。Workerクラスはバックグラウンドで実行するタスクのロジックを定義し、WorkRequestはそのタスクをどのように実行するかを指定します。
まず、WorkManagerの依存関係をプロジェクトに追加します。
dependencies {
implementation("androidx.work:work-runtime-ktx:2.10.0")
// For testing
androidTestImplementation("androidx.work:work-testing:2.10.0")
}次に、データを同期するシンプルなWorkerを実装します。
class SyncDataWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
override fun doWork(): Result {
return try {
// Get input data
val userId = inputData.getString(KEY_USER_ID)
?: return Result.failure()
// Perform sync operation
val syncResult = performDataSync(userId)
// Return output data on success
val outputData = workDataOf(
KEY_SYNC_COUNT to syncResult.recordCount,
KEY_LAST_SYNC to System.currentTimeMillis()
)
Result.success(outputData)
} catch (e: NetworkException) {
// Retry on network errors
Result.retry()
} catch (e: Exception) {
// Permanent failure
Result.failure()
}
}
private fun performDataSync(userId: String): SyncResult {
// Actual sync logic here
return SyncResult(recordCount = 42)
}
companion object {
const val KEY_USER_ID = "user_id"
const val KEY_SYNC_COUNT = "sync_count"
const val KEY_LAST_SYNC = "last_sync"
}
}このWorkerをスケジュールするには、OneTimeWorkRequestを作成してWorkManagerにエンキューします。
class DataSyncManager(private val context: Context) {
fun scheduleSyncWork(userId: String) {
val inputData = workDataOf(
SyncDataWorker.KEY_USER_ID to userId
)
val syncWorkRequest = OneTimeWorkRequestBuilder<SyncDataWorker>()
.setInputData(inputData)
.addTag("sync_work")
.build()
WorkManager.getInstance(context)
.enqueueUniqueWork(
"user_sync_$userId",
ExistingWorkPolicy.REPLACE,
syncWorkRequest
)
}
}enqueueUniqueWorkを使用することで、同じ識別子を持つタスクが重複してスケジュールされることを防止できます。ExistingWorkPolicy.REPLACEは既存のタスクをキャンセルして新しいタスクに置き換え、KEEPは既存のタスクを保持します。
制約条件の設定:実行条件の制御
WorkManagerの最も強力な機能の一つは、タスクの実行条件を制約として指定できることです。これにより、ネットワーク接続がある場合のみ、または充電中のみタスクを実行するといった制御が可能になります。
fun scheduleImageUploadWork(imageUri: String) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED) // WiFi only
.setRequiresBatteryNotLow(true) // Battery > 20%
.setRequiresCharging(false) // No charging required
.setRequiresStorageNotLow(true) // Sufficient storage
.build()
val uploadWorkRequest = OneTimeWorkRequestBuilder<ImageUploadWorker>()
.setConstraints(constraints)
.setInputData(workDataOf("image_uri" to imageUri))
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
Duration.ofMinutes(1)
)
.build()
WorkManager.getInstance(context)
.enqueue(uploadWorkRequest)
}NetworkTypeには以下のオプションがあります:
NOT_REQUIRED: ネットワーク不要CONNECTED: 任意のネットワーク接続UNMETERED: WiFiなどの従量制でないネットワークMETERED: モバイルデータなどの従量制ネットワークNOT_ROAMING: ローミング中でないネットワーク
setBackoffCriteriaは、タスクがResult.retry()を返した場合のリトライ間隔を設定します。EXPONENTIALポリシーでは、リトライごとに待機時間が2倍になります(1分、2分、4分...)。
定期実行タスク:PeriodicWorkRequest
バックグラウンドでの定期的なデータ同期やキャッシュクリーンアップなど、繰り返し実行するタスクにはPeriodicWorkRequestを使用します。
class PeriodicSyncScheduler(private val context: Context) {
fun schedulePeriodicSync() {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
val periodicSyncRequest = PeriodicWorkRequestBuilder<SyncDataWorker>(
repeatInterval = 6, TimeUnit.HOURS,
flexInterval = 30, TimeUnit.MINUTES
)
.setConstraints(constraints)
.setInputData(workDataOf("sync_type" to "periodic"))
.addTag("periodic_sync")
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
"periodic_data_sync",
ExistingPeriodicWorkPolicy.UPDATE,
periodicSyncRequest
)
}
fun cancelPeriodicSync() {
WorkManager.getInstance(context)
.cancelUniqueWork("periodic_data_sync")
}
}flexIntervalパラメータは、タスクが実行される時間枠を指定します。上記の例では、6時間ごとに実行され、実行タイミングは各間隔の最後の30分以内となります。これにより、システムは複数のアプリのタスクをバッチ処理してバッテリーを節約できます。
注意点として、定期タスクの最小間隔は15分です。これより短い間隔を指定しても、システムは15分に強制します。
タスクチェーン:順次実行と並列実行
WorkManagerでは、複数のタスクを順次または並列に実行するチェーンを構築できます。これは、画像のダウンロード、処理、アップロードといった一連の操作に最適です。
class ImageProcessingPipeline(private val context: Context) {
fun processAndUploadImages(imageIds: List<String>) {
val workManager = WorkManager.getInstance(context)
// Step 1: Download images in parallel
val downloadRequests = imageIds.map { imageId ->
OneTimeWorkRequestBuilder<DownloadImageWorker>()
.setInputData(workDataOf("image_id" to imageId))
.addTag("download")
.build()
}
// Step 2: Apply filters (runs after ALL downloads complete)
val filterRequest = OneTimeWorkRequestBuilder<ApplyFilterWorker>()
.addTag("filter")
.build()
// Step 3: Compress images
val compressRequest = OneTimeWorkRequestBuilder<CompressImageWorker>()
.addTag("compress")
.build()
// Step 4: Upload to server
val uploadRequest = OneTimeWorkRequestBuilder<UploadImageWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.addTag("upload")
.build()
// Build the chain
workManager
.beginWith(downloadRequests) // Parallel execution
.then(filterRequest) // Sequential after downloads
.then(compressRequest) // Sequential
.then(uploadRequest) // Sequential
.enqueue()
}
}beginWithに複数のWorkRequestを渡すと、それらは並列に実行されます。thenでチェーンされたタスクは、前のすべてのタスクが成功した後に実行されます。
タスクの監視とキャンセル
実行中のタスクの状態を監視し、必要に応じてキャンセルすることは、優れたユーザーエクスペリエンスのために不可欠です。
class WorkStatusObserver(private val context: Context) {
fun observeWorkStatus(workId: UUID): Flow<WorkInfo.State> {
return WorkManager.getInstance(context)
.getWorkInfoByIdFlow(workId)
.map { it?.state ?: WorkInfo.State.CANCELLED }
}
fun observeWorkByTag(tag: String): Flow<List<WorkInfo>> {
return WorkManager.getInstance(context)
.getWorkInfosByTagFlow(tag)
}
// Usage in ViewModel
fun monitorSyncProgress() {
viewModelScope.launch {
observeWorkByTag("sync_work").collect { workInfoList ->
workInfoList.forEach { workInfo ->
when (workInfo.state) {
WorkInfo.State.RUNNING -> {
val progress = workInfo.progress.getInt("progress", 0)
_uiState.update { it.copy(syncProgress = progress) }
}
WorkInfo.State.SUCCEEDED -> {
val syncCount = workInfo.outputData.getInt("sync_count", 0)
_uiState.update { it.copy(syncComplete = true, recordCount = syncCount) }
}
WorkInfo.State.FAILED -> {
_uiState.update { it.copy(syncError = "Sync failed") }
}
else -> { /* Handle other states */ }
}
}
}
}
}
}タスクをキャンセルするには、タグ、ユニーク名、またはIDを使用します:
val workManager = WorkManager.getInstance(context)
// Cancel by unique name
workManager.cancelUniqueWork("user_sync_123")
// Cancel by tag
workManager.cancelAllWorkByTag("sync_work")
// Cancel by ID
workManager.cancelWorkById(workId)
// Cancel all work (use with caution)
workManager.cancelAllWork()CoroutineWorkerによる非同期処理
Kotlinコルーチンを使用する場合、CoroutineWorkerがより自然な選択です。doWorkがサスペンド関数となり、非同期操作を簡潔に記述できます。
class CoroutineSyncWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
@Inject
lateinit var repository: DataRepository
override suspend fun doWork(): Result {
return try {
setForeground(createForegroundInfo())
val totalRecords = 100
var processedRecords = 0
repository.getRecordsToSync().collect { record ->
repository.syncRecord(record)
processedRecords++
// Report progress
setProgress(workDataOf(
"progress" to (processedRecords * 100 / totalRecords)
))
}
Result.success(workDataOf(
"synced_count" to processedRecords
))
} catch (e: CancellationException) {
throw e // Don't catch cancellation
} catch (e: Exception) {
if (runAttemptCount < 3) {
Result.retry()
} else {
Result.failure(workDataOf("error" to e.message))
}
}
}
private fun createForegroundInfo(): ForegroundInfo {
val notification = NotificationCompat.Builder(applicationContext, "sync_channel")
.setContentTitle("Syncing Data")
.setSmallIcon(R.drawable.ic_sync)
.setOngoing(true)
.build()
return ForegroundInfo(
NOTIFICATION_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
}
companion object {
private const val NOTIFICATION_ID = 1001
}
}setForegroundを呼び出すことで、長時間実行されるタスクをForeground Serviceとして実行し、システムによるキャンセルを防止できます。Android 14以降では、foregroundServiceTypeを明示的に指定する必要があります。
Androidの面接対策はできていますか?
インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。
2026年技術面接でよく問われる質問
Androidの技術面接では、WorkManagerに関する深い理解が求められることが多くあります。以下は、よく問われる質問とその回答のポイントです。
Q1: WorkManagerとForeground Serviceの使い分けは?
WorkManagerは遅延可能だが確実に実行されるべきタスクに使用します(例:ログのアップロード、定期的な同期)。Foreground Serviceは即時かつ継続的な実行が必要なタスクに使用します(例:音楽再生、位置追跡)。WorkManagerのタスクはシステムの判断で遅延される可能性がありますが、Foreground Serviceは即座に開始されます。
Q2: Dozeモードとの関係は?
Dozeモード中、WorkManagerのタスクはメンテナンスウィンドウまで遅延されます。ただし、setExpedited()を使用すると、より早いタイミングでの実行を要求できます。Android 12以降では、setExpeditedはForeground Serviceを自動的に使用してタスクを実行します。
Q3: Worker内での依存性注入は?
Hilt 2.50以降では、@HiltWorkerアノテーションを使用して簡単に依存性を注入できます:
@HiltWorker
class HiltSyncWorker @AssistedInject constructor(
@Assisted context: Context,
@Assisted params: WorkerParameters,
private val repository: DataRepository // Injected
) : CoroutineWorker(context, params) {
// ...
}Q4: テストはどのように行うか?
work-testingライブラリを使用して、同期的にWorkerをテストできます:
@Test
fun testSyncWorker() {
val worker = TestListenableWorkerBuilder<SyncDataWorker>(context)
.setInputData(workDataOf("user_id" to "123"))
.build()
val result = worker.doWork()
assertThat(result).isEqualTo(ListenableWorker.Result.success())
}まとめ
Android WorkManagerは、2026年のAndroid開発においてバックグラウンドタスク処理の標準ツールとして確立されています。制約条件の宣言的な指定、タスクチェーンの構築、そしてCoroutineWorkerによる非同期処理のサポートにより、信頼性の高いバックグラウンド処理を簡潔に実装できます。
技術面接では、WorkManagerの基本概念だけでなく、Dozeモードとの関係、適切な使い分け、テスト手法についても説明できることが求められます。本記事で紹介したパターンを実際のプロジェクトで活用し、深い理解を身につけることが重要です。
Android のバグを見つけられますか
実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

執筆
Anthony Fillion-MailletSharpSkill 創業者
10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。
2026年8月22日 更新
タグ
共有
関連記事

2026年のAndroidモジュール化:マルチモジュールアーキテクチャと面接対策
Androidアプリのマルチモジュール設計について詳しく解説。Gradleバージョンカタログ、コンベンションプラグイン、モジュール間通信パターン、そして技術面接でよく出題される質問と回答を紹介します。

Jetpack Navigation Compose 2026年版:型安全ナビゲーションと面接対策
Navigation Compose 2.10の型安全APIを詳細解説。Kotlin Serializationによるルート定義、ネストグラフ、ディープリンク、面接頻出質問まで網羅。

Kotlin Flow vs StateFlow vs SharedFlow:2026年のAndroid面接質問
2026年にAndroidの面接官が問う Kotlin Flow・StateFlow・SharedFlow の質問を、明快な回答・比較表・本番投入できるコードとともに解説します。