Android WorkManager in 2026: Achtergrondtaken, Constraints en Sollicitatievragen
Complete handleiding voor Android WorkManager 2.11/2.12 met Kotlin-codevoorbeelden, constraints-configuratie, het koppelen van werkverzoeken en veelgestelde technische sollicitatievragen.

Android WorkManager beheert uitstelbare, gegarandeerde achtergrondtaken die app-herstarts en apparaatopstarts overleven. Als onderdeel van Android Jetpack biedt WorkManager 2.11.2 (stabiel, maart 2026) een uniforme API voor API 23+ die automatisch de beste onderliggende implementatie kiest (JobScheduler, AlarmManager of Firebase JobDispatcher) op basis van het API-niveau van het apparaat.
WorkManager is geschikt voor taken die gegarandeerde uitvoering vereisen: uploaden van logs, synchroniseren van data, verwerken van afbeeldingen. Voor onmiddellijk werk dat proceseinde niet overleeft, worden Kotlin Coroutines gebruikt.
WorkManager 2.11 opzetten in een Kotlin-project
Voordat een worker wordt geschreven, moet de dependency worden gedeclareerd. WorkManager 2.11+ vereist minSdk 23 en compileSdk 33.
dependencies {
val workVersion = "2.11.2"
implementation("androidx.work:work-runtime-ktx:$workVersion")
// Optional: for testing
androidTestImplementation("androidx.work:work-testing:$workVersion")
}Het work-runtime-ktx-artefact bevat Kotlin-extensies en Coroutine-ondersteuning via CoroutineWorker. Voor basisgebruik is geen extra configuratie nodig: WorkManager initialiseert zichzelf via een ContentProvider.
Een eenvoudige Worker maken met doWork()
Een Worker-klasse overschrijft doWork() en retourneert een Result. Het systeem voert deze methode uit op een achtergrondthread.
class SyncWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
override fun doWork(): Result {
// Read input data
val userId = inputData.getString("user_id") ?: return Result.failure()
return try {
// Perform sync operation
val syncService = SyncService.getInstance(applicationContext)
syncService.syncUserData(userId)
Result.success()
} catch (e: IOException) {
// Retry on network errors
Result.retry()
} catch (e: Exception) {
// Permanent failure
Result.failure()
}
}
}Drie mogelijke uitkomsten bestaan: Result.success() markeert voltooiing, Result.failure() stopt nieuwe pogingen, en Result.retry() plant opnieuw in volgens het backoff-beleid.
CoroutineWorker gebruiken voor Suspend-functies
Wanneer het werk suspend-functies omvat (Retrofit-aanroepen, Room-queries), elimineert CoroutineWorker geneste callbacks.
class UploadWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val imageUri = inputData.getString("image_uri")
?: return Result.failure()
// Progress reporting (visible in WorkInfo observers)
setProgress(workDataOf("status" to "compressing"))
val compressed = ImageCompressor.compress(imageUri)
setProgress(workDataOf("status" to "uploading"))
return try {
val response = ApiClient.imageService.upload(compressed)
val outputData = workDataOf("url" to response.imageUrl)
Result.success(outputData)
} catch (e: HttpException) {
if (e.code() in 500..599) Result.retry()
else Result.failure()
}
}
}CoroutineWorker.doWork() draait op Dispatchers.Default. Om van dispatcher te wisselen, wordt withContext() binnen de functie gebruikt.
Constraints definiëren voor voorwaardelijke uitvoering
Constraints voorkomen dat werk wordt uitgevoerd totdat aan voorwaarden is voldaan. Dit bespaart batterij en vermijdt mislukte pogingen.
fun scheduleUpload(context: Context, imageUri: String) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED) // WiFi only
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.build()
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(constraints)
.setInputData(workDataOf("image_uri" to imageUri))
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
Duration.ofMinutes(1)
)
.addTag("upload")
.build()
WorkManager.getInstance(context)
.enqueueUniqueWork(
"upload_$imageUri",
ExistingWorkPolicy.KEEP,
uploadRequest
)
}Beschikbare constraints omvatten netwerktype (CONNECTED, UNMETERED, METERED, NOT_ROAMING), batterijniveau, oplaadstatus, opslagruimte en apparaat-idle-status. WorkManager 2.10+ accepteert ook een raw NetworkRequest voor fijnmazige netwerkcontrole.
Een veelgestelde sollicitatievraag betreft wanneer KEEP vs REPLACE te gebruiken in enqueueUniqueWork. KEEP negeert nieuwe verzoeken als werk met dezelfde naam bestaat, REPLACE annuleert bestaand werk en start opnieuw. KEEP wordt gebruikt voor uploads waar duplicaten bandbreedte verspillen, REPLACE voor synchronisaties waar alleen de nieuwste data telt.
Werkverzoeken koppelen met then() en combine()
Complexe workflows vereisen sequentiële en parallelle uitvoering. WorkManager koppelt werkverzoeken met beginWith() en then().
fun processAndUploadImages(context: Context, imageUris: List<String>) {
val workManager = WorkManager.getInstance(context)
// Parallel compression workers
val compressRequests = imageUris.map { uri ->
OneTimeWorkRequestBuilder<CompressWorker>()
.setInputData(workDataOf("uri" to uri))
.build()
}
// Single upload worker runs after all compressions complete
val uploadRequest = OneTimeWorkRequestBuilder<BatchUploadWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
// Cleanup runs after upload, regardless of success
val cleanupRequest = OneTimeWorkRequestBuilder<CleanupWorker>()
.build()
workManager
.beginWith(compressRequests) // Parallel
.then(uploadRequest) // Sequential
.then(cleanupRequest) // Sequential
.enqueue()
}Output van parallelle workers wordt standaard samengevoegd in een ArrayCreatingInputMerger. De volgende worker ontvangt alle key-value-paren, waarbij arrays worden gemaakt voor dubbele sleutels.
Klaar om je Android gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Periodiek werk plannen met PeriodicWorkRequest
PeriodicWorkRequest voert herhaaldelijk uit met een minimuminterval van 15 minuten (Android handhaaft deze limiet).
fun scheduleDailySync(context: Context) {
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
repeatInterval = 6,
repeatIntervalTimeUnit = TimeUnit.HOURS,
flexTimeWindow = 30,
flexTimeUnit = TimeUnit.MINUTES
)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.addTag("periodic_sync")
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
"daily_sync",
ExistingPeriodicWorkPolicy.UPDATE,
syncRequest
)
}Het flex-venster stelt WorkManager in staat werk te bundelen met andere jobs, wat de batterij-efficiëntie verbetert. Een interval van 6 uur met 30 minuten flex betekent dat uitvoering ergens tussen 5:30 en 6:00 na de vorige run plaatsvindt.
Werkstatus observeren met LiveData en Flow
WorkManager stelt werkstatus beschikbaar via WorkInfo. Observatie gebeurt met LiveData of Kotlin Flow.
class UploadViewModel(application: Application) : AndroidViewModel(application) {
private val workManager = WorkManager.getInstance(application)
// Flow-based observation
fun observeUpload(workId: UUID): Flow<WorkInfo?> {
return workManager.getWorkInfoByIdFlow(workId)
}
// Check if any upload is running
val activeUploads: Flow<List<WorkInfo>> =
workManager.getWorkInfosByTagFlow("upload")
.map { workInfos ->
workInfos.filter { it.state == WorkInfo.State.RUNNING }
}
}
// In Compose UI
@Composable
fun UploadProgress(workId: UUID, viewModel: UploadViewModel) {
val workInfo by viewModel.observeUpload(workId)
.collectAsState(initial = null)
when (workInfo?.state) {
WorkInfo.State.RUNNING -> {
val status = workInfo?.progress?.getString("status") ?: "working"
CircularProgressIndicator()
Text(status)
}
WorkInfo.State.SUCCEEDED -> {
val url = workInfo?.outputData?.getString("url")
Text("Uploaded: $url")
}
WorkInfo.State.FAILED -> Text("Upload failed")
else -> {}
}
}Werkstatussen volgen een levenscyclus: ENQUEUED, RUNNING, SUCCEEDED/FAILED/CANCELLED, BLOCKED (wachtend op dependencies).
WorkManager 2.12 Work Metrics API
WorkManager 2.12.0-rc01 (augustus 2026) introduceert WorkMetricsInfo voor het bijhouden van uitvoeringsgeschiedenis.
class MetricsRepository(private val context: Context) {
private val workManager = WorkManager.getInstance(context)
suspend fun getWorkerMetrics(workerName: String): List<WorkMetricsInfo> {
val query = WorkMetricsQuery.Builder()
.setWorkerClassName(workerName)
.setLimit(100)
.build()
return workManager.getWorkMetrics(query)
}
fun analyzeFailures(metrics: List<WorkMetricsInfo>): Map<Int, Int> {
// Count stop reasons
return metrics
.flatMap { it.stopReasonCounts.entries }
.groupBy { it.key }
.mapValues { entry -> entry.value.sumOf { it.value } }
}
}Metrics omvatten uitvoeringsduur, retry-tellingen, stopreden en timestamps. De API maakt het mogelijk intermitterende fouten in productie te debuggen zonder aangepaste logging-infrastructuur.
WorkMetricsInfo-data wordt standaard na 7 dagen verwijderd. Retentie kan worden geconfigureerd met Configuration.Builder().setWorkMetricsRetentionDuration().
Workers testen met WorkManagerTestInitHelper
Unit-tests voor workers vereisen het work-testing-artefact. TestListenableWorkerBuilder maakt workers aan zonder ze in de wachtrij te plaatsen.
@RunWith(AndroidJUnit4::class)
class SyncWorkerTest {
private lateinit var context: Context
@Before
fun setup() {
context = ApplicationProvider.getApplicationContext()
val config = Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setExecutor(SynchronousExecutor())
.build()
WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
}
@Test
fun syncWorker_withValidUserId_succeeds() = runTest {
val inputData = workDataOf("user_id" to "123")
val worker = TestListenableWorkerBuilder<SyncWorker>(context)
.setInputData(inputData)
.build()
val result = worker.doWork()
assertThat(result).isEqualTo(ListenableWorker.Result.success())
}
@Test
fun syncWorker_withoutUserId_fails() = runTest {
val worker = TestListenableWorkerBuilder<SyncWorker>(context)
.build()
val result = worker.doWork()
assertThat(result).isEqualTo(ListenableWorker.Result.failure())
}
}Voor integratietests die constraints en koppeling verifiëren, wordt TestDriver gebruikt om constraint-vervulling en tijdsverloop te simuleren.
Veelgestelde sollicitatievragen over WorkManager
Technische sollicitatiegesprekken testen vaak het begrip van WorkManager's garanties en trade-offs. Deze vragen verschijnen in Android mid-level en senior interviews.
V: Wat gebeurt er met een WorkRequest als de app wordt afgesloten?
WorkManager slaat werkverzoeken persistent op in een Room-database. Wanneer de app herstart of het systeem constraint-vervulling signaleert, wordt lopend werk hervat. Deze garantie onderscheidt WorkManager van CoroutineScope-werk dat sterft met het proces.
V: Hoe verschilt WorkManager van AlarmManager?
AlarmManager plant exacte tijdalarmen en voert code uit op specifieke kloktijden. WorkManager plant uitstelbaar werk dat wordt uitgevoerd wanneer aan constraints is voldaan, zonder garantie voor exacte timing. AlarmManager wordt gebruikt voor gebruikersgerichte alarmen, WorkManager voor achtergrond-dataverwerking.
V: Kan WorkManager werk onmiddellijk uitvoeren?
Ja, met setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST). Versnelde werkverzoeken gebruiken de foreground service-slot op API 31+ of JobScheduler.setImportantWhileForeground() op oudere APIs. Quota-limieten gelden, dus de OutOfQuotaPolicy definieert fallback-gedrag.
V: Hoe zou men alle lopende uploads annuleren?
WorkManager.getInstance(context).cancelAllWorkByTag("upload")Tags maken bulk-operaties mogelijk. Alternatief annuleert cancelUniqueWork("name") een specifieke keten.
Systeem-geïnduceerde stops afhandelen met Backoff-beleid
Wanneer het systeem een worker stopt (batterij-optimalisatie, geheugendruk), bepaalt het backoff-beleid de timing voor nieuwe pogingen.
val request = OneTimeWorkRequestBuilder<UploadWorker>()
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
Duration.ofSeconds(30) // Initial delay, minimum 10 seconds
)
.setBackoffOnSystemInterruption(true) // New in 2.11
.build()Exponentiële backoff verdubbelt de vertraging bij elke retry: 30s, 60s, 120s, tot een maximum van 5 uur. Lineaire backoff voegt de initiële vertraging elke keer toe: 30s, 60s, 90s. De nieuwe setBackoffOnSystemInterruption()-vlag in WorkManager 2.11 past backoff ook toe wanneer het systeem (niet de worker) de stop veroorzaakte.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Belangrijke inzichten voor productie-WorkManager-gebruik
CoroutineWorkerprefereren bovenWorkerbij het aanroepen van suspend-functies. Het vermijdt thread-blokkering en integreert met bestaande coroutine-code.enqueueUniqueWork()gebruiken om dubbel werk te voorkomen.KEEPkiezen voor idempotente operaties,REPLACEwanneer alleen het laatste verzoek telt.- Betekenisvolle tags op elk verzoek instellen. Tags maken observatie, annulering en debugging over werkketens mogelijk.
- Workers geïsoleerd testen met
TestListenableWorkerBuilder, daarna ketens testen metTestDriverconstraint-simulatie. - WorkManager 2.12's
WorkMetricsInfo-API biedt uitvoeringsgeschiedenis. Deze wordt gebruikt om retry-patronen en stopredenen in productie te debuggen. - Constraints besparen batterij. Een worker die faalt door ontbrekend netwerk verspilt CPU-cycli en verbruikt stroom bij retry-pogingen.
- Het 15-minutenminimum voor periodiek werk wordt afgedwongen door Android, niet WorkManager. Periodieke taken moeten worden ontworpen om dit interval te tolereren.
Zie jij de bug in Android?
Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Geschreven door
Anthony Fillion-MailletOprichter van SharpSkill
Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.
Bijgewerkt op 22 augustus 2026
Tags
Delen
Gerelateerde artikelen

Jetpack Navigation Compose in 2026: Type-Safe Navigatie en Sollicitatievragen
Een uitgebreide handleiding voor type-safe navigatie met Jetpack Compose. Praktische codevoorbeelden, best practices en veelgestelde interviewvragen voor Android-ontwikkelaars.

Kotlin Flow vs StateFlow vs SharedFlow: Android-interviewvragen in 2026
De Kotlin Flow vs StateFlow vs SharedFlow-vragen die Android-interviewers in 2026 stellen, met heldere antwoorden, een vergelijkingstabel en productieklare code.

Android 16 in 2026: Nieuwe API's, Desktopmodus en Sollicitatievragen
Android 16 brengt ingrijpende veranderingen voor ontwikkelaars: verplicht edge-to-edge-rendering, desktopmodus, ProgressStyle-notificaties en predictive back-navigatie. Een technische deep-dive met codevoorbeelden en sollicitatievragen.