Skip to content

Can't invoke factories with parameters from different threads #2305

@marcusSengaro

Description

@marcusSengaro

Describe the bug

CoroutineScope(Dispatchers.Default).launch {
    val myClassA = get<MyClassA> { parametersOf("a") }
}
val myClassB = get<MyClassB> { parametersOf(1) }

When two classes are instantiated with runtime parameters on different threads at the same time from a koin factory an exception occurs:

15:38:57.063  D  |- 'app.MyClassB'...
15:38:57.063  D  |- 'app.MyClassA'...
15:38:57.063  D  | >> parameters DefinitionParameters[1]
15:38:57.063  D  | >> parameters DefinitionParameters[a]
15:38:57.063  D  |- ? t:'app.MyClassB' - q:'null' look in injected parameters
15:38:57.063  D  |- ? t:'app.MyClassA' - q:'null' look in injected parameters
15:38:57.063  D  | (+) '[Factory: 'app.MyClassB']'
15:38:57.063  D  | (+) '[Factory: 'app.MyClassA']'
15:38:57.063  D  |- 'java.lang.Integer'...
15:38:57.063  D  |- 'java.lang.String'...
15:38:57.063  D  |- ? t:'java.lang.String' - q:'null' look in stack parameters
15:38:57.063  D  |- 'java.lang.String' in 0.08 ms
15:38:57.063  I  MyClassA created with ID: a
15:38:57.063  D  | << parameters
15:38:57.064  E  * Instance creation error : could not create instance for '[Factory: 'app.MyClassB']': org.koin.core.error.NoDefinitionFoundException: No definition found for type 'java.lang.Integer'. Check your Modules configuration and add missing type and/or qualifier!
                 	org.koin.core.resolution.CoreResolver.resolveFromContext(CoreResolver.kt:178)
                 	org.koin.core.scope.Scope.resolveFromContext(Scope.kt:321)
                 	org.koin.core.scope.Scope.stackParametersCall(Scope.kt:284)
                 	org.koin.core.scope.Scope.resolveInstance(Scope.kt:270)
                 	org.koin.core.scope.Scope.resolve(Scope.kt:247)
                 	org.koin.core.scope.Scope.get(Scope.kt:225)
                 	app.di.DefaultServiceModuleKt$defaultServiceModule$lambda$137$$inlined$factoryOf$default$3.invoke(FactoryOf.kt:226)
                 	app.di.DefaultServiceModuleKt$defaultServiceModule$lambda$137$$inlined$factoryOf$default$3.invoke(FactoryOf.kt:50)
                 	org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:49)
                 	org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
                 	org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:132)
                 	org.koin.core.resolution.CoreResolver.resolveFromRegistry(CoreResolver.kt:87)
                 	org.koin.core.resolution.CoreResolver.resolveFromContextOrNull(CoreResolver.kt:74)
                 	org.koin.core.resolution.CoreResolver.resolveFromContextOrNull$default(CoreResolver.kt:72)
                 	org.koin.core.resolution.CoreResolver.resolveFromContext(CoreResolver.kt:69)
                 	org.koin.core.scope.Scope.resolveFromContext(Scope.kt:321)
                 	org.koin.core.scope.Scope.stackParametersCall(Scope.kt:292)
                 	org.koin.core.scope.Scope.resolveInstance(Scope.kt:270)
                 	org.koin.core.scope.Scope.resolve(Scope.kt:247)
                 	org.koin.core.scope.Scope.get(Scope.kt:225)
                 	app.MyApplication.onCreate(MyApplication.kt:354)
                 	android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1277)
                 	android.app.ActivityThread.handleBindApplication(ActivityThread.java:7667)
                 	android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
                 	android.app.ActivityThread$H.handleMessage(ActivityThread.java:2410)
                 	android.os.Handler.dispatchMessage(Handler.java:106)
                 	android.os.Looper.loopOnce(Looper.java:226)
                 	android.os.Looper.loop(Looper.java:313)
                 	android.app.ActivityThread.main(ActivityThread.java:8810)
                 	java.lang.reflect.Method.invoke(Native Method)
                 	com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
                 	com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
15:38:57.064  D  |- 'app.MyClassA' in 0.686 ms
15:38:57.064  D  | << parameters
15:38:57.064  D  Shutting down VM

Expected behavior
Koin factories with parameters can provide class instances on different threads without having to force every class instantiation on the same thread.

Koin module and version:
io.insert-koin:koin-android:4.1.1

Snippet or Sample project to help reproduce
Test classes:

class MyClassA(val id: String) {
    init {
        println("MyClassA created with ID: $id")
    }
}

class MyClassB(val id: Int) {
    init {
        println("MyClassB created with ID: $id")
    }
}

Koin module with factories for my classes:

module { 
    factoryOf(::MyClassA)
    factoryOf(::MyClassB)
}

Code snippet to get classes with parameters on background dispatcher:

CoroutineScope(Dispatchers.Default).launch {
    val myClassA = get<MyClassA> { parametersOf("a") }
}
val myClassB = get<MyClassB> { parametersOf(1) }

Metadata

Metadata

Assignees

No one assigned

    Labels

    coroutinesstatus:checkingcurrently in analysis - discussion or need more detailed specs

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions