Skip to main content
Version: 4.2

WorkManager

Koin plugs a WorkerFactory into Android WorkManager, so your Workers get their dependencies through the constructor. This page covers the setup, how to declare a Worker and how to pass input data. It assumes Koin is started in your Application (see Starting Koin on Android).

Setup​

Add the WorkManager artifact next to koin-android:

// build.gradle.kts
dependencies {
implementation("io.insert-koin:koin-android")
implementation("io.insert-koin:koin-androidx-workmanager")
}

Versions come from the Koin BOM (see Gradle Setup).

Call workManagerFactory() in startKoin, after androidContext():

import org.koin.androidx.workmanager.koin.workManagerFactory

class MainApplication : Application() {

override fun onCreate() {
super.onCreate()

startKoin {
androidContext(this@MainApplication)
workManagerFactory()
modules(appModule)
}
}
}

workManagerFactory() initializes WorkManager with a configuration that uses the Koin WorkerFactory. It does nothing if WorkManager is already initialized, which is the case when the default AndroidX initializer runs first. Remove that initializer in AndroidManifest.xml:

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
warning

If you keep the default initializer, WorkManager starts without the Koin factory. Workers then fail at runtime because WorkManager can't create a class with extra constructor parameters.

Declaring a Worker​

A Worker takes Context and WorkerParameters from WorkManager, then any dependency from Koin:

class SyncWorker(
context: Context,
params: WorkerParameters,
private val repository: SyncRepository,
) : CoroutineWorker(context, params) {

override suspend fun doWork(): Result {
repository.sync()
return Result.success()
}
}

Declare it as a worker:

import org.koin.plugin.module.dsl.worker

val workModule = module {
single<SyncRepository>()
worker<SyncWorker>()
}

A worker definition is a factory named after the Worker class and bound to ListenableWorker. When WorkManager asks for a Worker class, the Koin factory looks up that name. If no definition matches, Koin returns null and WorkManager falls back to its default factory.

Enqueuing work​

Nothing changes on the WorkManager side:

val request = OneTimeWorkRequestBuilder<SyncWorker>().build()
WorkManager.getInstance(context).enqueue(request)

Input data​

Values that change per run go through WorkManager input data, not through Koin:

class UserSyncWorker(
context: Context,
params: WorkerParameters,
private val repository: UserRepository,
) : CoroutineWorker(context, params) {

override suspend fun doWork(): Result {
val userId = inputData.getString("USER_ID") ?: return Result.failure()
repository.syncUser(userId)
return Result.success()
}
}
val request = OneTimeWorkRequestBuilder<UserSyncWorker>()
.setInputData(workDataOf("USER_ID" to "123"))
.build()

WorkManager.getInstance(context).enqueue(request)

Input data is stored by WorkManager and survives process death, which Koin parameters do not.