# 2026'da Android WorkManager: Arka Plan Görevleri, Kısıtlamalar ve Mülakat Soruları > Kotlin'de WorkManager 2.11 için kapsamlı rehber - temel kurulumdan kısıtlamalar ve iş zincirlerine, testlere ve mülakat sorularına kadar her şey. - Published: 2026-08-22 - Updated: 2026-08-22 - Author: Anthony Fillion-Maillet - Tags: android, workmanager, kotlin, background-tasks, jetpack - Reading time: 12 min --- Android WorkManager, uygulama yeniden başlatmaları ve cihaz yeniden başlatmaları boyunca kalıcı olan ertelenebilir, garantili arka plan işlerini yönetir. Android Jetpack'in bir parçası olarak yayınlanan WorkManager 2.11.2 (kararlı sürüm, Mart 2026), API 23+ üzerinde çalışan ve cihazın API seviyesine göre en iyi uygulamayı (JobScheduler, AlarmManager veya Firebase JobDispatcher) otomatik olarak seçen birleşik bir API sağlar. > **WorkManager ne zaman kullanılmalı** > > WorkManager, garantili yürütme gerektiren görevler için kullanılmalıdır: log gönderme, veri senkronizasyonu, görüntü işleme. Süreç ölümünden sonra devam etmesi gerekmeyen anlık işler için Kotlin Coroutines tercih edilmelidir. ## Kotlin Projesinde WorkManager 2.11 Kurulumu Herhangi bir worker yazmadan önce bağımlılık tanımlanmalıdır. WorkManager 2.11+ minSdk 23 ve compileSdk 33 gerektirir. ```gradle // build.gradle.kts (app module) dependencies { val workVersion = "2.11.2" implementation("androidx.work:work-runtime-ktx:$workVersion") // Optional: for testing androidTestImplementation("androidx.work:work-testing:$workVersion") } ``` `work-runtime-ktx` artifact'ı, `CoroutineWorker` aracılığıyla Kotlin uzantıları ve Coroutine desteği içerir. Temel kullanım için ek yapılandırma gerekmez: WorkManager kendini bir ContentProvider aracılığıyla otomatik olarak başlatır. ## doWork() ile Basit Bir Worker Oluşturma Bir `Worker` sınıfı `doWork()` metodunu override eder ve bir `Result` döndürür. Sistem bu metodu arka plan iş parçacığında çalıştırır. ```kotlin // SyncWorker.kt 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() } } } ``` Üç olası sonuç vardır: `Result.success()` tamamlanmayı işaret eder, `Result.failure()` yeniden denemeleri durdurur ve `Result.retry()` backoff politikasına göre yeniden planlar. ## Suspend Fonksiyonlar için CoroutineWorker Kullanımı İş suspend fonksiyonları (Retrofit çağrıları, Room sorguları) içerdiğinde, `CoroutineWorker` callback iç içe geçmesini ortadan kaldırır. ```kotlin // UploadWorker.kt 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()` varsayılan olarak `Dispatchers.Default` üzerinde çalışır. Dispatcher değiştirmek için fonksiyon içinde `withContext()` kullanılmalıdır. ## Koşullu Yürütme için Kısıtlamaları Tanımlama Kısıtlamalar, koşullar karşılanana kadar işin çalışmasını engeller. Bu pil tasarrufu sağlar ve başarısız denemeleri önler. ```kotlin // ScheduleUpload.kt fun scheduleUpload(context: Context, imageUri: String) { val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) // WiFi only .setRequiresBatteryNotLow(true) .setRequiresStorageNotLow(true) .build() val uploadRequest = OneTimeWorkRequestBuilder() .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 ) } ``` Mevcut kısıtlamalar arasında ağ türü (CONNECTED, UNMETERED, METERED, NOT_ROAMING), pil seviyesi, şarj durumu, depolama alanı ve cihaz boşta durumu bulunur. WorkManager 2.10+ ayrıca hassas ağ kontrolü için ham `NetworkRequest` kabul eder. > **Mülakat ipucu** > > Yaygın bir mülakat sorusu, `enqueueUniqueWork`'te `KEEP` ve `REPLACE` arasındaki farkı sorar. `KEEP`, aynı ada sahip iş varsa yeni istekleri yok sayar; `REPLACE`, mevcut işi iptal eder ve yeniden başlar. Yüklemelerde duplikasyonların bant genişliği israfına yol açtığı durumlarda `KEEP`, yalnızca en son verilerin önemli olduğu senkronizasyonlarda `REPLACE` kullanılır. ## then() ve combine() ile İş İsteklerini Zincirleme Karmaşık iş akışları sıralı ve paralel yürütme gerektirir. WorkManager, `beginWith()` ve `then()` kullanarak iş isteklerini zincirler. ```kotlin // WorkChain.kt fun processAndUploadImages(context: Context, imageUris: List) { val workManager = WorkManager.getInstance(context) // Parallel compression workers val compressRequests = imageUris.map { uri -> OneTimeWorkRequestBuilder() .setInputData(workDataOf("uri" to uri)) .build() } // Single upload worker runs after all compressions complete val uploadRequest = OneTimeWorkRequestBuilder() .setConstraints( Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() ) .build() // Cleanup runs after upload, regardless of success val cleanupRequest = OneTimeWorkRequestBuilder() .build() workManager .beginWith(compressRequests) // Parallel .then(uploadRequest) // Sequential .then(cleanupRequest) // Sequential .enqueue() } ``` Paralel worker'lardan gelen çıktı varsayılan olarak `ArrayCreatingInputMerger` ile birleştirilir. Sonraki worker tüm anahtar-değer çiftlerini alır ve yinelenen anahtarlar için diziler oluşturulur. ## PeriodicWorkRequest ile Periyodik İş Planlama PeriodicWorkRequest, minimum 15 dakikalık aralıklarla (Android bu limiti zorlar) tekrar tekrar yürütülür. ```kotlin // PeriodicSync.kt fun scheduleDailySync(context: Context) { val syncRequest = PeriodicWorkRequestBuilder( 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 ) } ``` Esneklik penceresi, WorkManager'ın işi diğer görevlerle gruplandırmasına olanak tanır ve pil verimliliğini artırır. 30 dakikalık esneklik penceresi ile 6 saatlik aralık, yürütmenin önceki çalışmadan 5:30 ile 6:00 arasında bir zamanda gerçekleşeceği anlamına gelir. ## LiveData ve Flow ile İş Durumunu Gözlemleme WorkManager, iş durumunu `WorkInfo` aracılığıyla sunar. LiveData veya Kotlin Flow kullanılarak gözlemlenebilir. ```kotlin // WorkObserver.kt class UploadViewModel(application: Application) : AndroidViewModel(application) { private val workManager = WorkManager.getInstance(application) // Flow-based observation fun observeUpload(workId: UUID): Flow { return workManager.getWorkInfoByIdFlow(workId) } // Check if any upload is running val activeUploads: Flow> = 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 -> {} } } ``` İş durumları bir yaşam döngüsü izler: ENQUEUED, RUNNING, SUCCEEDED/FAILED/CANCELLED, BLOCKED (bağımlılıklar bekleniyor). ## WorkManager 2.12 Work Metrics API WorkManager 2.12.0-rc01 (Ağustos 2026), yürütme geçmişini izlemek için `WorkMetricsInfo` sunar. ```kotlin // MetricsExample.kt class MetricsRepository(private val context: Context) { private val workManager = WorkManager.getInstance(context) suspend fun getWorkerMetrics(workerName: String): List { val query = WorkMetricsQuery.Builder() .setWorkerClassName(workerName) .setLimit(100) .build() return workManager.getWorkMetrics(query) } fun analyzeFailures(metrics: List): Map { // Count stop reasons return metrics .flatMap { it.stopReasonCounts.entries } .groupBy { it.key } .mapValues { entry -> entry.value.sumOf { it.value } } } } ``` Metrikler yürütme süresini, yeniden deneme sayaçlarını, durdurma nedenlerini ve zaman damgalarını içerir. API, özel loglama altyapısı olmadan üretimdeki aralıklı hataların debug edilmesini sağlar. > **Metrik saklama süresi** > > WorkMetricsInfo verileri varsayılan olarak 7 gün sonra temizlenir. Saklama süresi `Configuration.Builder().setWorkMetricsRetentionDuration()` ile yapılandırılabilir. ## WorkManagerTestInitHelper ile Worker'ları Test Etme Worker'ların birim testi `work-testing` artifact'ını gerektirir. `TestListenableWorkerBuilder`, worker'ları kuyruğa almadan oluşturur. ```kotlin // SyncWorkerTest.kt @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(context) .setInputData(inputData) .build() val result = worker.doWork() assertThat(result).isEqualTo(ListenableWorker.Result.success()) } @Test fun syncWorker_withoutUserId_fails() = runTest { val worker = TestListenableWorkerBuilder(context) .build() val result = worker.doWork() assertThat(result).isEqualTo(ListenableWorker.Result.failure()) } } ``` Kısıtlamaları ve zincirlemeyi doğrulayan entegrasyon testleri için `TestDriver`, kısıtlama karşılama ve zaman geçişi simülasyonu yapar. ## WorkManager Hakkında Yaygın Mülakat Soruları Teknik mülakatlar sıklıkla WorkManager'ın garantilerini ve ödünleşimlerini test eder. Bu sorular orta ve üst düzey Android mülakatlarında görülür. **S: Uygulama sonlandırıldığında WorkRequest'e ne olur?** WorkManager iş isteklerini bir Room veritabanında saklar. Uygulama yeniden başladığında veya sistem kısıtlama karşılandığını bildirdiğinde, bekleyen iş devam eder. Bu garanti, WorkManager'ı süreçle birlikte ölen `CoroutineScope` işinden ayırır. **S: WorkManager AlarmManager'dan nasıl farklıdır?** AlarmManager kesin zamanlı alarmlar planlar ve belirli saat zamanlarında kod çalıştırır. WorkManager, kısıtlamalar karşılandığında çalışan ertelenebilir iş planlar, kesin zamanlama garantisi yoktur. Kullanıcıya görünür alarmlar için AlarmManager, arka plan veri işleme için WorkManager kullanılır. **S: WorkManager işi hemen çalıştırabilir mi?** Evet, `setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)` ile. Hızlandırılmış iş istekleri API 31+ üzerinde ön plan hizmet slotunu veya daha eski API'lerde `JobScheduler.setImportantWhileForeground()` kullanır. Kota limitleri geçerlidir, bu nedenle `OutOfQuotaPolicy` geri dönüş davranışını tanımlar. **S: Tüm bekleyen yüklemeler nasıl iptal edilir?** ```kotlin WorkManager.getInstance(context).cancelAllWorkByTag("upload") ``` Etiketler toplu işlemleri etkinleştirir. Alternatif olarak, `cancelUniqueWork("name")` belirli bir zinciri iptal eder. ## Backoff Politikaları ile Sistem Kaynaklı Durmaları Yönetme Sistem bir worker'ı durdurduğunda (pil optimizasyonu, bellek baskısı), backoff politikası yeniden deneme zamanlamasını belirler. ```kotlin // BackoffConfig.kt val request = OneTimeWorkRequestBuilder() .setBackoffCriteria( BackoffPolicy.EXPONENTIAL, Duration.ofSeconds(30) // Initial delay, minimum 10 seconds ) .setBackoffOnSystemInterruption(true) // New in 2.11 .build() ``` Üstel backoff her yeniden denemede gecikmeyi ikiye katlar: 30s, 60s, 120s, maksimum 5 saate kadar. Doğrusal backoff her seferinde başlangıç gecikmesini ekler: 30s, 60s, 90s. WorkManager 2.11'deki yeni `setBackoffOnSystemInterruption()` bayrağı, durmaya sistem (worker değil) neden olduğunda bile backoff uygular. ## Üretim WorkManager Kullanımı için Temel Çıkarımlar - Suspend fonksiyonları çağırırken `Worker` yerine `CoroutineWorker` tercih edilmelidir. İş parçacıklarını bloke etmekten kaçınır ve mevcut coroutine koduyla entegre olur. - Yinelenen işi önlemek için `enqueueUniqueWork()` kullanılmalıdır. Idempotent işlemler için `KEEP`, yalnızca en son isteğin önemli olduğu durumlar için `REPLACE` seçilmelidir. - Her isteğe anlamlı etiketler eklenmelidir. Etiketler, iş zincirleri boyunca gözlem, iptal ve debug işlemlerini etkinleştirir. - Worker'ları `TestListenableWorkerBuilder` ile izole olarak test edin, ardından zincirleri `TestDriver` kısıtlama simülasyonu ile test edin. - WorkManager 2.12'nin `WorkMetricsInfo` API'si yürütme geçmişi sağlar. Üretimdeki yeniden deneme kalıplarını ve durdurma nedenlerini debug etmek için kullanılmalıdır. - Kısıtlamalar pil tasarrufu sağlar. Ağ eksikliği nedeniyle başarısız olan bir worker, yeniden deneme girişimlerinde CPU döngüleri harcar ve enerji tüketir. - Periyodik iş için 15 dakikalık minimum Android tarafından zorlanır, WorkManager tarafından değil. Periyodik görevler bu aralığa toleranslı olacak şekilde tasarlanmalıdır. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/android/android-workmanager-background-tasks-2026