Koin Android: org.koin.error.NoBeanDefFoundException - android

Got that message error
java.lang.RuntimeException: Unable to create application com.app.name.application.MainApplication: org.koin.error.BeanInstanceCreationException: Can't create bean Bean[class=com.app.name.general.preferences.Preferences] due to error :
org.koin.error.NoBeanDefFoundException: No definition found to resolve type 'android.app.Application'. Check your module definition
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5830)
at android.app.ActivityThread.-wrap1(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1673)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:172)
at android.app.ActivityThread.main(ActivityThread.java:6637)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: org.koin.error.BeanInstanceCreationException: Can't create bean Bean[class=com.app.name.general.preferences.Preferences] due to error :
org.koin.error.NoBeanDefFoundException: No definition found to resolve type 'android.app.Application'. Check your module definition
at org.koin.core.instance.InstanceFactory.createInstance(InstanceFactory.kt:63)
at org.koin.core.instance.InstanceFactory.retrieveInstance(InstanceFactory.kt:26)
at org.koin.KoinContext$resolveInstance$$inlined$synchronized$lambda$1.invoke(KoinContext.kt:85)
at org.koin.KoinContext$resolveInstance$$inlined$synchronized$lambda$1.invoke(KoinContext.kt:23)
at org.koin.ResolutionStack.resolve(ResolutionStack.kt:23)
at org.koin.KoinContext.resolveInstance(KoinContext.kt:80)
at com.app.name.constants.EnvironmentConstants$initEnvironmentVariables$$inlined$getKoinInstance$1$1.invoke(KoinComponent.kt:114)
at kotlin.SynchronizedLazyImpl.getValue(Lazy.kt:131)
at com.app.name.constants.EnvironmentConstants$initEnvironmentVariables$$inlined$getKoinInstance$1.getValue(Unknown Source:7)
at com.app.name.constants.EnvironmentConstants.initEnvironmentVariables(EnvironmentConstants.kt:180)
at com.app.name.application.MainApplication.onCreate(MainApplication.kt:59)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5827)
... 8 more
But all dependencies were correct.
Also I noticed that modules without androidApplication() argument works correctly.
Code looks like:
startKoin(listOf(
imageManagerModule,
databaseRepositoryModule
))
ImageManager works perfectly
val imageManagerModule: Module = applicationContext {
bean { ImageManagerImpl() as ImageManager }
}
But Preferences crashes
val preferencesModule: Module = applicationContext {
bean { PreferencesImpl(androidApplication()) as Preferences }
}

Solution is easy but not so obvious.
Somehow Android Studio imported standalone startKoin function instead of specific android function.
So I had to replace
import org.koin.standalone.StandAloneContext.startKoin
To
import org.koin.android.ext.android.startKoin
And that works!

In my case I needed to make like this:
import android.app.Application
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidFileProperties
import org.koin.android.ext.koin.androidLogger
import org.koin.android.viewmodel.dsl.viewModel
import org.koin.core.context.startKoin
import org.koin.core.module.Module
import org.koin.dsl.module
class MyApplication : Application() {
override fun onCreate(){
super.onCreate()
// start Koin!
startKoin {
// Android context
androidLogger()
androidContext(this#MyApplication)
// use the Android context given there
// load properties from assets/koin.properties file
androidFileProperties()
// modules
modules(myModule)
}
}
val myModule: Module = module { viewModel { MyViewModel() }}
}
and use older dependencies:
implementation("org.koin:koin-android:2.0.1")
implementation("org.koin:koin-android-viewmodel:2.0.1")

I had similar issue ,
Try to just add this dependency it will be resolved
// Room
implementation "android.arch.persistence.room:runtime:1.1.1"
kapt "android.arch.persistence.room:compiler:1.1.1" .

In my case for another situation it wrote this message:
"org.koin.core.error.NoBeanDefFoundException: No definition found for class:'...Actions'. Check your definitions!"
private val actions: Actions by inject()
var modules = module(override = true) {
single<Actions> { ActionsImpl(get()) }
}
#Test
fun test() {
actions.swipe()
}
In this case Actions is an interface.
Make sure you call a variable before unloadKoinModules(modules) has been called!

Related

Koin dependency Injection Isssue - Android

In my android application am using MVVM architecture and using koin library for DI.
Below is my Repository class:
class JaiminRepository constructor(
private var remoteDataSource : RemoteDataSource,
private var enrollApiInterface : EnrollApiInterface
) {
...
}
Created module for is as below:
val jaiminRepositoryModule = module {
single {
JaiminRepository(get(),get())
}
}
For this I am getting error as :
Instance creation error : could not create instance for
[Singleton:'com.jaimin.sdk.repository.JaiminRepository']:
org.koin.core.error.NoBeanDefFoundException: |- No definition found
for class:'com.jaimin.api.RemoteDataSource'. Check your definitions!
org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:287)
org.koin.core.scope.Scope.resolveValue(Scope.kt:257)
So I have added factory for RemoteDataSource.
factory {
RemoteDataSource()
}
and finally it look like as below:
val jaiminRepositoryModule = module {
factory {
RemoteDataSource()
}
single {
JaiminRepository(get(),get())
}
}
But still am getting error. What might be the issue? Do I need to do something with EnrollApiInterface also? Please guide. Thanks in Advance.
You have to define all dependencies in the module(or another module), otherwise your repository can't be created. Make sure you also provide the EnrollApiInterface:
val jaiminRepositoryModule = module {
factory<EnrollApiInterface> {
EnrollApiInterfaceImpl()
}
factory {
RemoteDataSource()
}
single {
JaiminRepository(get(),get())
}
}

NoClassDefFoundError kotlinx serialization

I have a kotlin multiplatform project and I need to serialize a class. I have included the following dependency in my commonMain and androidMain and iosMain respectively in my multiplatform gradle file:
//commonMain
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.20.0"
//androidMain
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
//iosMain
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.20.0"
This is the class I want to serialize:
#Serializable
class Test {
fun toJsonTestClass() = Json.stringify(Test.serializer(), this)
var value1:Double = 0.toDouble()
companion object {
fun buildClass(value1 : Double):Test {
val test = Test()
test.value1 = value1
return test
}
fun fromJsonTestClass(json:String) = Json.parse(Test.serializer(), json)
}
}
And in another class (TrialClass), this is how I am testing it:
val test = Test()
val testToJson = test.toJsonTestClass() //<- This is where the error is pointing to.
println(testToJson)
But when I run it, I get the following error:
Exception in thread "main" java.lang.NoClassDefFoundError: kotlinx/serialization/json/Json
at Test.toJsonTestClass(Test.kt:28)
at TrialClass.main(TrialClass.kt:4)
Caused by: java.lang.ClassNotFoundException: kotlinx.serialization.json.Json
I get no issues when having the imports in my class, but when running I get the above mentioned error.
Any help or advice will be highly appreciated.
For my case, I did everything right - code & configuration. And gradle clean didn't help, I ended up with the magic Invalidate Caches / Restart from IntelliJ IDEA.
Your class is probably being obfuscated. You have two options:
Add the #Keep annotation above the class:
#Serializable
#Keep
class Teste {
// ...
}...
or add it to your module's proguard:
-keep (path_to_the_class).test.** { *; }

Pass App context to Koin from Java Application class

I have a Java application class, I cannot change it to Kotlin. I init Koin like this:
KoinApplication koinApp = KoinApplication.create()
.printLogger()
.modules(
myModule
);
start(koinApp);
My module is created in another file:
#JvmField
val myModule = module {
single { DateUtil(androidContext()) }
factory<ListPresenterContract> { MyListPresenter() }
}
But then when I access this file DateUtil I'm getting this error regarding androidContext():
Caused by: org.koin.android.error.MissingAndroidContextException: Can't resolve Context instance. Please use androidContext() function in your KoinApplication configuration.
at org.koin.android.ext.koin.ModuleExtKt.androidContext(ModuleExt.kt:33)
at koin.MyKoinModulesKt$MyModule$1$1.invoke(MyKoinModules.kt:16)
at koin.MyKoinModulesKt$MyModule$1$1.invoke(Unknown Source:4)
at org.koin.core.instance.DefinitionInstance.create(DefinitionInstance.kt:54)
at org.koin.core.instance.SingleDefinitionInstance.get(SingleDefinitionInstance.kt:40)
at org.koin.core.definition.BeanDefinition.resolveInstance(BeanDefinition.kt:70)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:165)
at org.koin.core.scope.Scope.get(Scope.kt:128)
at view.MyViewerListAdapter$$special$$inlined$inject$1.invoke(Scope.kt:327)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at view.MyViewerListAdapter.getDateUtil(Unknown Source:7)
at view.MyViewerListAdapter.setModelView(MyListAdapter.kt:77)
at view.MyViewerListAdapter.onBindViewHolder(MyViewerListAdapter.kt:45)
at view.MyViewerListAdapter.onBindViewHolder(MyListAdapter.kt:27)
I suspect that it just so happens that my module is initialised before the application class, and gets null for the androidContext. And only when I actually access the file that supposed to have context, it doesn't lazily initialise and I still have the null context. I don't know how to get around that in a Java app class so I removed the context from the module in the meantime.
Based on the latest version 2.0.1 standard
in AppModult.kt
val appContext = module {
single(named("appContext")) { androidContext() }
}
in Application.kt
startKoin {
androidContext(this#App)
androidFileProperties()
modules(listOf(appContext))
}
Create Kotlin klass (JavaKoinApplication.kt)
fun start(myApplication: Application) {
startKoin(listOf(module)) with (myApplication)}
then Call this class in your Java Application Class
JavaKoinApplication.start(this);

App Crash once replace Fragment for scoped ViewModel

Bug
I was found an issue when I try to open fragment and then replace with the same fragment.
In our prod application, it's a popular case.
java.lang.IllegalStateException: Definition without any InstanceContext - [type:Scope,scope:'com.abc.view.fragment.BrowseTaskFragment', primary_type:'com.abc.viewModel.BrowseTaskVM']
at org.koin.core.definition.BeanDefinition.resolveInstance(BeanDefinition.kt:72)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:141)
at org.koin.core.scope.Scope.get(Scope.kt:131)
at com.abc.view.fragment.BrowseTaskFragment$$special$$inlined$inject$1.invoke(Scope.kt:274)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.abc.view.fragment.BrowseTaskFragment.getMViewModel(Unknown Source:25)
at com.abc.view.fragment.BrowseTaskFragment.getMViewModel(BrowseTaskFragment.kt:37)
at com.abc.base.BaseFragment.performViewModelBinding(BaseFragment.kt:55)
at com.abc.base.BaseFragment.onViewCreated(BaseFragment.kt:31)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1471)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:802)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
at androidx.fragment.app.FragmentManagerImpl$1.run(FragmentManager.java:733)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6810)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Steps to reproduce the behavior:
I have BottomNavigationView once I tap on existing fragment which is visible, getting above crash.
Koin version: 2.0.1
Module
val viewModelModule = module {
scope(named<BrowseTaskFragment>()) {
scoped { BrowseTaskVM() }
}
}
Application class
startKoin {
androidContext(this#AbcApplication)
modules(listOf(appModule, stateModule, apiModule, viewModelModule))
}
You can do this by create scope.
First in your module class create scope by named koin method
val viewModelModule = module {
scope(named<BrowseTaskFragment>()) {
scoped { BrowseTaskVM() }
}
}
Second in your fragment
private val viewModelScope = getKoin().getOrCreateScope("Scope1",named<BrowseTaskFragment>())
private val browseTaskVM: BrowseTaskVM= viewModelScope.get()
Last in an onDestoy method close your scope.
override fun onDestroy() {
super.onDestroy()
viewModelScope.close()
}
define in application class like this
startKoin {
androidContext(this#ApplicationContext)
// your modules
modules(listOf(your modules))
}
and pass context in you modules

Symbol$CompletionFailure: class file for ActivityDeparturesBinding not found

I have a separate Android library in a separate project for an Android app. However I link the library directly (referencing the library module directly by path or the generated AAR) I get the following error:
A problem was found with the configuration of task ':app:kaptDevelopDebugKotlin'.
> Cannot write to file '/home/m0skit0/Repos/repo/app-android/app/build/intermediates/data-binding/develop/debug/bundle-bin' specified for property 'dataBindingArtifactOutputDir' as it is a directory.
e: error: cannot access ActivityDeparturesBinding
class file for com.blablabla.databinding.ActivityDeparturesBinding not found
Consult the following stack trace for details.
com.sun.tools.javac.code.Symbol$CompletionFailure: class file for com.blablabla.databinding.ActivityDeparturesBinding not found
* What went wrong:
Execution failed for task ':app:kaptDevelopDebugKotlin'.
This shows just after the task :app:transformDataBindingWithDataBindingMergeArtifactsForDevelopDebug
However the class does exist, with full canonical name. It belongs to the the library and it is correctly auto generated (without any errors) by Android's Data Binding processor on both projects. The library compiles correctly on its own. There's no further stacktrace even if the compilation is run with --stacktrace.
I have tried linking the library with compile, implementation and api, all with the same result.
Gradle version is 4.4.
UPDATE:
Updating to Gradle 5 did not solve the problem. Renaming the XML did not solve the problem.
I've also found that the error happens only when I reference the ActivityDeparturesBinding class in my code, even if the part where it is referenced is never actually called. Only importing it without referencing it does not cause the error.
UPDATE2:
This is the activity that uses the layout:
class DeparturesActivity : BaseVinPlateActivity<DeparturesViewModel, ActivityDeparturesBinding>() {
companion object {
fun getStartIntent(context: Context) = Intent(context, DeparturesActivity::class.java)
}
#Inject
override lateinit var viewModel: DeparturesViewModel
override val layout: Int = R.layout.activity_departures
override fun injectThis(component: ActivityComponent) {
component.inject(this)
}
override fun getToolbarTitleId(): Int = R.string.departures_title
override fun initializeDataBindings(dataBinding: ActivityDeparturesBinding) {
dataBinding.viewmodel = viewModel
}
}
abstract class BaseVinPlateActivity<T: BaseVinPlateViewModel, U: ViewDataBinding> : CompoundsBaseActivity() {
protected abstract var viewModel: T
protected abstract val layout: Int
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == BARCODE_RESULT_CODE_ACTIVITY && resultCode == Activity.RESULT_OK) {
val barcodeResult = data?.getStringExtra(BARCODE_RESULT_ACTIVITY)
viewModel.setBarcodeResult(barcodeResult)
}
}
override fun initializeView() {
super.initializeView()
val dataBinding = inflateDataBinding<U>(layout)
initializeDataBindings(dataBinding)
with (viewModel) {
setBindValidator(Validator(dataBinding))
loadData()
}
}
protected abstract fun initializeDataBindings(dataBinding: U)
}
If I remove the initializeDataBindings() function, the error is gone. Note that commenting only the body of the function is not enough, I had to remove the whole function.
This smells like a compiler/tools bug.
I know it's late but I'd like to say that something similar happened to me, in my case I have a library module which was using a third party library, and then in my app module I'm using dagger for injecting dependencies, and I was getting this issue because, I believe dagger couldn't find this thrid party library's class because it wasn't directly implemented in the app's dependencies. So in my case what got it sorted was to change the way I was adding the third party library into my local library module in order to use api instead of implementation.
We could bypass the compilation error in a couple of ways (there are probably more ways). The best way we came up with is converting the abstract function into an abstract lambda property.
Parent class:
abstract class BaseVinPlateActivity<T: BaseVinPlateViewModel, U: ViewDataBinding> : CompoundsBaseActivity() {
protected abstract val initializeDataBinding: U.() -> Unit
// Rest of code
}
Child class:
class DeparturesActivity : BaseVinPlateActivity<DeparturesViewModel, ActivityDeparturesBinding>() {
override val initializeDataBinding: ActivityDeparturesBinding.() -> Unit = { viewmodel = this#DeparturesActivity.viewModel }
// Rest of code
}

Categories

Resources