# WorkManager 2.10 Coroutines: Background Task Modern Yaklaşım
WorkManager 2.10 (2024 Q4 stable), Android background task'ların altın standardı. JobScheduler, AlarmManager ve Firebase JobDispatcher için tek replacement API. Coroutines-first yaklaşım, expedited work desteği, Flow<WorkInfo> observation — hepsi mature. Bu yazı WorkManager 2.10'un modern pattern'lerini, Android 15 foreground service restriction'larıyla uyumu, testing stratejisini ve migration best practice'lerini anlatır.
💡 Pro Tip: WorkManager her background task için değil. Network sync, upload, periodic refresh için ideal. Real-time event için değil — Firebase Messaging push + WorkManager kombinasyonu.
İçindekiler
- WorkManager Nedir, Ne Zaman
- CoroutineWorker: Modern Worker
- Expedited Work (Android 12+)
- Constraints Sistemi
- Work Chaining
- Unique Work Policies
- Flow<WorkInfo> Observer
- Android 15 Compatibility
- Testing
WorkManager Nedir, Ne Zaman
Kullan:
- Network sync (deferrable, periodic)
- Image/video upload
- Database cleanup (haftalık)
- Analytics batch send
- Offline queue processing
- ML model download
Kullanma:
- Real-time messaging (FCM)
- Active user interaction (UI thread'de async)
- Ultra-time-sensitive operations (<30s)
- Background audio playback (MediaSession)
CoroutineWorker: Modern Worker
kotlin
1import androidx.work.CoroutineWorker2import androidx.work.WorkerParameters3import kotlinx.coroutines.Dispatchers4import kotlinx.coroutines.withContext5 6class SyncDataWorker(7 context: Context,8 params: WorkerParameters9) : CoroutineWorker(context, params) {10 11 override suspend fun doWork(): Result = withContext(Dispatchers.IO) {12 try {13 val data = inputData.getString("user_id")14 ?: return@withContext Result.failure()15 16 // Network call with coroutine17 val users = userRepository.syncUsers(data)18 19 // Persist20 userDao.insertAll(users)21 22 // Return success data23 val output = workDataOf("synced_count" to users.size)24 Result.success(output)25 } catch (e: IOException) {26 Result.retry() // Exponential backoff27 } catch (e: Exception) {28 Result.failure()29 }30 }31}Enqueue
kotlin
1val syncRequest = OneTimeWorkRequestBuilder() 2 .setInputData(workDataOf("user_id" to userId))3 .setConstraints(4 Constraints.Builder()5 .setRequiredNetworkType(NetworkType.CONNECTED)6 .setRequiresBatteryNotLow(true)7 .build()8 )9 .setBackoffCriteria(10 BackoffPolicy.EXPONENTIAL,11 WorkRequest.MIN_BACKOFF_MILLIS,12 TimeUnit.MILLISECONDS13 )14 .build()15 16WorkManager.getInstance(context).enqueue(syncRequest)Expedited Work (Android 12+)
Kritik user-perceivable task'lar için:
kotlin
1val urgentSync = OneTimeWorkRequestBuilder() 2 .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)3 .build()4 5WorkManager.getInstance(context).enqueue(urgentSync)Expedited work:
- Battery optimization bypass
- Doze mode'da çalışabilir (Android 12+)
- Quota-limited (günlük kotalar)
- Quota bittiğinde policy'ye göre fallback
Foreground Service Notification
kotlin
1class UploadWorker(ctx: Context, params: WorkerParameters) :2 CoroutineWorker(ctx, params) {3 4 override suspend fun getForegroundInfo(): ForegroundInfo {5 val notification = NotificationCompat.Builder(applicationContext, "upload_channel")6 .setContentTitle("Dosya yükleniyor")7 .setSmallIcon(R.drawable.ic_upload)8 .setOngoing(true)9 .build()10 11 return ForegroundInfo(12 NOTIFICATION_ID,13 notification,14 ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC15 )16 }17 18 override suspend fun doWork(): Result {19 setForeground(getForegroundInfo()) // Foreground service başlat20 // Upload work21 return Result.success()22 }23}Constraints Sistemi
kotlin
1val constraints = Constraints.Builder()2 .setRequiredNetworkType(NetworkType.UNMETERED) // Wi-Fi only3 .setRequiresCharging(true) // Charging4 .setRequiresBatteryNotLow(true) // Pil > %155 .setRequiresDeviceIdle(true) // Doze mode6 .setRequiresStorageNotLow(true) // Storage yeterli7 .build()8 9val request = OneTimeWorkRequestBuilder() 10 .setConstraints(constraints)11 .build()Tüm constraint'ler MET olunca work çalışır. Değilse sessizce bekler.
Work Chaining
Sıralı task'lar:
kotlin
1WorkManager.getInstance(context)2 .beginWith(compressWork)3 .then(uploadWork)4 .then(notifyWork)5 .enqueue()6 7// Veya parallel + sequential karışık8WorkManager.getInstance(context)9 .beginWith(listOf(compressImageWork, compressVideoWork)) // parallel10 .then(uploadWork) // await both, then upload11 .enqueue()Data Passing
kotlin
1// Worker 1'in output'ı2override suspend fun doWork(): Result {3 val output = workDataOf("compressed_path" to "/tmp/img.jpg")4 return Result.success(output)5}6 7// Worker 2 input'u automatically worker 1'in output'u8override suspend fun doWork(): Result {9 val path = inputData.getString("compressed_path") ?: return Result.failure()10 // Upload path11}Unique Work Policies
Duplicate prevention:
kotlin
1WorkManager.getInstance(context).enqueueUniqueWork(2 "user_sync_job", // Unique name3 ExistingWorkPolicy.REPLACE, // KEEP, REPLACE, APPEND, APPEND_OR_REPLACE4 syncRequest5)- KEEP: Mevcut varsa yeni'yi ignore et
- REPLACE: Eski'yi cancel + yeni'yi çalıştır
- APPEND: Sıraya ekle (chain)
- APPEND_OR_REPLACE: Append, fail olanı replace
Periodic work:
kotlin
1val periodicRequest = PeriodicWorkRequestBuilder( 2 15, TimeUnit.MINUTES, // repeat interval3 5, TimeUnit.MINUTES // flex period4).build()5 6WorkManager.getInstance(context).enqueueUniquePeriodicWork(7 "periodic_sync",8 ExistingPeriodicWorkPolicy.UPDATE, // UPDATE, KEEP9 periodicRequest10)Min interval: 15 dakika.
Flow<WorkInfo> Observer
Modern reactive monitoring:
kotlin
1class SyncViewModel : ViewModel() {2 val syncState: Flow = WorkManager 3 .getInstance(context)4 .getWorkInfoByIdFlow(syncRequest.id)5 6 fun enqueueSync() = viewModelScope.launch {7 syncState.collect { workInfo ->8 when (workInfo.state) {9 WorkInfo.State.ENQUEUED -> showQueuedUi()10 WorkInfo.State.RUNNING -> showRunningUi()11 WorkInfo.State.SUCCEEDED -> {12 val count = workInfo.outputData.getInt("synced_count", 0)13 showSuccess(count)14 }15 WorkInfo.State.FAILED -> showError()16 WorkInfo.State.CANCELLED -> showCancelled()17 else -> {}18 }19 }20 }21}Compose UI:
kotlin
1@Composable2fun SyncScreen(vm: SyncViewModel = viewModel()) {3 val state by vm.syncState.collectAsState(initial = null)4 5 Column {6 when (state?.state) {7 WorkInfo.State.RUNNING -> CircularProgressIndicator()8 WorkInfo.State.SUCCEEDED -> Text("✓ Senkronize edildi")9 WorkInfo.State.FAILED -> Text("✗ Hata")10 else -> Button(onClick = { vm.enqueueSync() }) { Text("Sync") }11 }12 }13}Android 15 Compatibility
Android 15 foreground service strict mode:
setExpeditedkullan — Doze bypass içinforegroundServiceTypebelirt (dataSync, location, etc.)- Manifest'e permission ekle
setForegroundçağrısınıdoWorkiçinde yap
xml
12 3 4 5 6 android:name="androidx.work.impl.foreground.SystemForegroundService"7 android:foregroundServiceType="dataSync"8 tools:node="merge" />Testing
kotlin
1// Test harness2@RunWith(AndroidJUnit4::class)3class SyncWorkerTest {4 private lateinit var context: Context5 6 @Before7 fun setup() {8 context = ApplicationProvider.getApplicationContext()9 val config = Configuration.Builder()10 .setMinimumLoggingLevel(Log.DEBUG)11 .setExecutor(SynchronousExecutor())12 .build()13 WorkManagerTestInitHelper.initializeTestWorkManager(context, config)14 }15 16 @Test17 fun testSyncSuccess() = runTest {18 val worker = TestListenableWorkerBuilder(context) 19 .setInputData(workDataOf("user_id" to "123"))20 .build()21 22 val result = worker.doWork()23 assertEquals(Result.success(), result)24 }25}ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
kotlin
1// WorkManagerModule.kt (Hilt)2@Module3@InstallIn(SingletonComponent::class)4object WorkManagerModule {5 6 @Provides7 @Singleton8 fun provideWorkManager(9 @ApplicationContext context: Context10 ): WorkManager = WorkManager.getInstance(context)11 12 @Provides13 @IntoMap14 @WorkerKey(SyncDataWorker::class)15 fun provideSyncWorker(16 userRepository: UserRepository17 ): ChildWorkerFactory = object : ChildWorkerFactory {18 override fun create(context: Context, params: WorkerParameters): ListenableWorker {19 return SyncDataWorker(context, params, userRepository)20 }21 }22}23 24// HiltWorkerFactory setup for DIOkuyucu Ödülü
Hilt + WorkManager entegrasyonu ile dependency injection temiz. **External Resources:** - [WorkManager 2.10 docs](https://developer.android.com/topic/libraries/architecture/workmanager) - [Expedited work guide](https://developer.android.com/topic/libraries/architecture/workmanager/advanced/expedited-work) - [WorkManager + Hilt](https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager) - [Testing guide](https://developer.android.com/topic/libraries/architecture/workmanager/how-to/integration-testing) - [Migration from JobScheduler](https://developer.android.com/topic/libraries/architecture/workmanager/migration)
Sonuç
WorkManager 2.10 Android background task'ın olgun, production-ready API'si. Coroutines-first, Flow<WorkInfo> reactive, expedited work kritik ihtiyaçlar için. Android 15 strict mode uyumlu. Migration JobScheduler/AlarmManager'dan 1-2 hafta; ROI yüksek (daha az battery drain, daha güvenilir). Next-gen work scheduling için hala geçerli olan standard.
*İlgili yazılar: Compose 1.7, Kotlin 2.1, Android 15.*

