Using koin-android:1.0.2 and koin-java:1.0.2, I'm apparently unable to inject androidContext(). My module is defined in a static field on an object:
object AppModules {
@JvmField
val helpers = module {
single<IFileHelper> { FileHelper(androidContext()) }
}
}
My application class is written in Java. I'm calling startKoin from the onCreate method like this:
startKoin(Collections.singletonList(AppModules.helpers));
This is the signature for the FileHelper class:
class FileHelper(private val _context: Context) : IFileHelper {
I'm trying to get an instance of FileHelper from an activity, which is also written in Java:
IFileHelper fileHelper = get(IFileHelper.class);
It throws this exception:
org.koin.error.BeanInstanceCreationException: Can't create definition for 'Single [name='IFileHelper',class='com.my.app.helpers.IFileHelper']' due to error :
No compatible definition found. Check your module definition
org.koin.core.bean.BeanRegistry.checkedResult(BeanRegistry.kt:120)
org.koin.core.bean.BeanRegistry.retrieveDefinition(BeanRegistry.kt:87)
org.koin.core.instance.InstanceRegistry.findDefinition(InstanceRegistry.kt:125)
org.koin.core.instance.InstanceRegistry.access$findDefinition(InstanceRegistry.kt:39)
org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1$1.invoke(InstanceRegistry.kt:91)
org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1$1.invoke(InstanceRegistry.kt:39)
org.koin.core.time.DurationKt.logDuration(Duration.kt:11)
org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:90)
org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:39)
org.koin.core.time.DurationKt.measureDuration(Duration.kt:19)
org.koin.core.instance.InstanceRegistry.proceedResolution(InstanceRegistry.kt:87)
org.koin.core.instance.InstanceRegistry.resolve(InstanceRegistry.kt:61)
org.koin.android.ext.koin.ContextExtKt.androidContext(ContextExt.kt:42)
com.my.app.ioc.AppModules$helpers$1$1.invoke(AppModules.kt:25)
com.my.app.ioc.AppModules$helpers$1$1.invoke(AppModules.kt:21)
org.koin.core.instance.holder.InstanceHolder$DefaultImpls.create(InstanceHolder.kt:17)
org.koin.core.instance.holder.SingleInstanceHolder.create(SingleInstanceHolder.kt:10)
org.koin.core.instance.holder.SingleInstanceHolder.get(SingleInstanceHolder.kt:19)
org.koin.core.instance.InstanceFactory.retrieveInstance(InstanceFactory.kt:53)
org.koin.core.instance.InstanceRegistry$resolveInstance$1.invoke(InstanceRegistry.kt:138)
org.koin.core.instance.InstanceRegistry$resolveInstance$1.invoke(InstanceRegistry.kt:39)
org.koin.core.stack.ResolutionStack.resolve(ResolutionStack.kt:44)
org.koin.core.instance.InstanceRegistry.resolveInstance(InstanceRegistry.kt:137)
org.koin.core.instance.InstanceRegistry.access$resolveInstance(InstanceRegistry.kt:39)
org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1$2.invoke(InstanceRegistry.kt:98)
org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1$2.invoke(InstanceRegistry.kt:39)
org.koin.core.time.DurationKt.logDuration(Duration.kt:11)
org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:97)
org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:39)
org.koin.core.time.DurationKt.measureDuration(Duration.kt:19)
org.koin.core.instance.InstanceRegistry.proceedResolution(InstanceRegistry.kt:87)
org.koin.core.instance.InstanceRegistry.resolve(InstanceRegistry.kt:61)
org.koin.core.KoinContext.get(KoinContext.kt:79)
org.koin.java.standalone.KoinJavaComponent.get(KoinJavaComponent.kt:65)
org.koin.java.standalone.KoinJavaComponent.get$default(KoinJavaComponent.kt:63)
org.koin.java.standalone.KoinJavaComponent.get(Unknown Source:7)
com.my.app.activities.MainActivity.handleResumeUpload(MainActivity.java:1114)
com.my.app.activities.MainActivity.onActivityResult(MainActivity.java:770)
android.app.Activity.dispatchActivityResult(Activity.java:7454)
android.app.ActivityThread.deliverResults(ActivityThread.java:4353)
android.app.ActivityThread.handleSendResult(ActivityThread.java:4402)
android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
android.os.Handler.dispatchMessage(Handler.java:106)
android.os.Looper.loop(Looper.java:193)
android.app.ActivityThread.main(ActivityThread.java:6669)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I've read many similar bug reports and tried all of the following:
val helpers = module {
single<IFileHelper> { FileHelper(androidApplication()) }
}
val helpers = module {
val ctx by lazy { androidContext() }
single<IFileHelper> { FileHelper(ctx) }
}
val helpers = module {
val ctx by lazy { androidApplication() }
single<IFileHelper> { FileHelper(ctx) }
}
I also tried moving the module out of the object but had the same problem.
Any help would be greatly appreciated.
Same problem here
you have to startKoin from an Application instance: startKoin(this, listOf(modules))
this is your instance
@arnaudgiuliani how does that work with koin-java, then? I can't call startKoin(this, listOf(modules)) from a Java class, and there doesn't appear to be a Java method that accepts an argument of type application.
@arnaudgiuliani any ideas? Is there an equivalent method that I can call from Java code?
@dave-kennedy can you try with koin 2.0 beta-3? Use the Kotlin DSL to describe how to start Koin and after that use it in your Java classes.
https://beta.insert-koin.io/docs/2.0/quick-references/starting-koin/
@arnaudgiuliani I'd rather wait for 2.0 to be out of beta before pulling it into my production app. Is there no way to start Koin with the Android context from a Java class? To clarify, I'm calling org.koin.java.standalone.KoinJavaStarter.startKoin from my Application class because it's still written in Java. Converting my Application class to Kotlin is something I'd like to do soon.
Try this
// Place on any kotlin file
@file:JvmName("YourPreferredName") // So it won't be FileNameKt in Java (optional)
@JvmOverloads
fun start(application: Application) {
application.startKoin( // invokes the ComponentCallbacks extension
application,
listOf(
yourModules
)
)
}
Then on your java application
YourPreferredName.start(this);
so that it will resolve contexts immediately. There is a weird bug in StandAloneContext.startKoin() with application.
ComponentCallbacks.startKoin documentation says will be soon deprecated for starKoin() with <androidContext> but it doesn't work for some reason.
@vielasis that worked. Thanks!
Does it make a difference whether the first parameter to startKoin is application vs application.applicationContext?
Solution for 2.0.0-beta-4
`class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
val context = this
startKoin{
modules(appModule)
.androidContext(context)
}
}
}
androidContext()` will be available in appModule
@dave-kennedy not sure but you can check if it resolves to the same extension ComponentCallbacks.startKoin()
Most helpful comment
you have to startKoin from an Application instance:
startKoin(this, listOf(modules))this is your instance