Hector
Hector

Reputation: 5664

Is Dynamic Dependency Injection with Koin possible

I am investigating Koin dependency injection library in my current Android application.

I have a CoroutineWorker that completes all my background work.

What I would like to do is Dynamically inject a lambda for each type of background work I have.

I have the following code that works, however it is not Dynamic

Koin Module:

const val BackgroundLambdaName: String = "back-ground-lambda"

val lambdaModule = module {

    single(qualifier = named(BackgroundLambdaName)) {
        background
    }
}

private val background: suspend CoroutineScope.(Service) -> Unit = { service: Service ->
    val limit: Int = 200
    var offset: Int = 0

    loop@ while (true) {

        val networkResponse = service.move(options = mutableMapOf("limit" to limit, "offset" to offset))

        if (networkResponse.next == null) {
            break@loop
        }
        offset += limit
    }
}

And my CoroutineWorker:

class BackgroundWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params), KoinComponent {

    private val service: Service by inject()
    private val x_background: suspend CoroutineScope.(Service) -> Unit by inject(qualifier = named(BackgroundLambdaName))

    override suspend fun doWork(): Result = coroutineScope {

        withContext(Dispatchers.IO) {
            downloadSynchronously(this)
            Result.success()
        }
    }

    private suspend fun downloadSynchronously(coroutineScope: CoroutineScope) {
        x_background(coroutineScope, service)
    }
}

Is there any approach I can take that will allow me to specify different lambdas at runtime to inject into my CoroutineWorker?

For example if my lambda Koin module had 10 lambdas defined

BackgroundLambdaName_0 - BackgroundLambdaName_9

Then when starting my unique background work as follows:

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .setRequiresBatteryNotLow(true)
    .setRequiresCharging(true)
    .build()

val backgroundWorkRequest = OneTimeWorkRequestBuilder<BackgroundWorker>()
    .setConstraints(constraints)
    .setBackoffCriteria(
        BackoffPolicy.EXPONENTIAL,
        OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
        TimeUnit.MILLISECONDS
    ).build()

// DYNAMICALLY set qualifier = named(BackgroundLambdaName) to one of 
// BackgroundLambdaName_0 - BackgroundLambdaName_9

WorkManager.getInstance(application).enqueueUniqueWork(UNIQUE_WORK_NAME, ExistingWorkPolicy.KEEP, backgroundWorkRequest)

Upvotes: 6

Views: 6185

Answers (1)

PedroAGSantos
PedroAGSantos

Reputation: 2346

Yes it is possible with Koin 2 at least is totally possible.

First create module that would be needed I guess for you is 'lambdaModule'

val coffeeAppModule = module {
    single { CoffeeMaker(get(), get()) }
    single<Pump> { Thermosiphon(get()) }
    single<Heater> { ElectricHeater() }
}

Then dynamically load the module and unload when you don't need anymore.

    // after start
loadKoinModules(coffeeAppModule)

// resolve CoffeeMaker
get()<CoffeeMaker>

// drop module's definitions & instances when you don't need it anymore
unloadKoinModules(coffeeAppModule)

please refer to maintainer of the library here you can find more https://medium.com/koin-developers/ready-for-koin-2-0-2722ab59cac3

Upvotes: 11

Related Questions