InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
9.07k stars 718 forks source link

Application: org.koin.core.error.DefinitionOverrideException: Already existing definition or try to override an existing one: [type:Single,primary_type:'yodgorbek.komilov.musobaqayangiliklari.internet.SportNewsInterface'] #756

Closed kyodgorbek closed 4 years ago

kyodgorbek commented 4 years ago

'I am developing android app using but I have declaring multiple modules in my Application class this

class SportNewsApplication : Application() {

override fun onCreate() {
    super.onCreate()
    // Adding Koin modules to our application
    startKoin {

      //  androidContext(this@SportNewsApplication)
        modules(
        listOf(appModules, bbcModules))

    }
}

}

but I am getting following exception

ava.lang.RuntimeException: Unable to create application yodgorbek.komilov.musobaqayangiliklari.di.application.SportNewsApplication: org.koin.core.error.DefinitionOverrideException: Already existing definition or try to override an existing one: [type:Single,primary_type:'yodgorbek.komilov.musobaqayangiliklari.internet.SportNewsInterface'] at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5971) at android.app.ActivityThread.access$1300(ActivityThread.java:206) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1700) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:201) at android.app.ActivityThread.main(ActivityThread.java:6820) 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:922) Caused by: org.koin.core.error.DefinitionOverrideException: Already existing definition or try to override an existing one: [type:Single,primary_type:'yodgorbek.komilov.musobaqayangiliklari.internet.SportNewsInterface'] at org.koin.core.registry.BeanRegistry.addDefinition(BeanRegistry.kt:144) at org.koin.core.registry.BeanRegistry.saveDefinition(BeanRegistry.kt:101) at org.koin.core.registry.BeanRegistry.saveDefinitions(BeanRegistry.kt:71) at org.koin.core.registry.BeanRegistry.loadModules(BeanRegistry.kt:49) at org.koin.core.KoinApplication.loadModulesAndScopes(KoinApplication.kt:66) at org.koin.core.KoinApplication.modules(KoinApplication.kt:60) at yodgorbek.komilov.musobaqayangiliklari.di.application.SportNewsApplication$onCreate$1.invoke(SportNewsApplication.kt:19) at yodgorbek.komilov.musobaqayangiliklari.di.application.SportNewsApplication$onCreate$1.invoke(SportNewsApplication.kt:11) at org.koin.core.context.GlobalContextKt.startKoin(GlobalContext.kt:72) at yodgorbek.komilov.musobaqayangiliklari.di.application.SportNewsApplication.onCreate(SportNewsApplication.kt:16) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1155) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5966) ... 8 more

below appModules.kt const val BASE_URL = "https://newsapi.org/"

val appModules = module { // The Retrofit service using our custom HTTP client instance as a singleton single { createWebService( okHttpClient = createHttpClient(), factory = RxJava2CallAdapterFactory.create(), baseUrl = BASE_URL ) } // Tells Koin how to create an instance of CatRepository factory { (NewsRepositoryImpl(sportsNewsApi = get())) } // Specific viewModel pattern to tell Koin how to build MainViewModel viewModel { MainViewModel(newsRepository = get()) } }

/ Returns a custom OkHttpClient instance with interceptor. Used for building Retrofit service / fun createHttpClient(): OkHttpClient { val client = OkHttpClient.Builder() client.readTimeout(5 * 60, TimeUnit.SECONDS) return client.addInterceptor { val original = it.request() val requestBuilder = original.newBuilder() requestBuilder.header("Content-Type", "application/json") val request = requestBuilder.method(original.method, original.body).build() return@addInterceptor it.proceed(request) }.build() }

/ function to build our Retrofit service / inline fun createWebService( okHttpClient: OkHttpClient, factory: CallAdapter.Factory, baseUrl: String ): T { val retrofit = Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create())) .addCallAdapterFactory(CoroutineCallAdapterFactory()) .addCallAdapterFactory(factory) .client(okHttpClient) .build() return retrofit.create(T::class.java) }

below

bbcModules.kt

const val base_url = "https://newsapi.org/"

val bbcModules = module { // The Retrofit service using our custom HTTP client instance as a singleton single { createBBCWebService( okHttpClient = createBBCHttpClient(), factory = RxJava2CallAdapterFactory.create(), baseUrl = base_url ) } // Tells Koin how to create an instance of CatRepository factory { (BBCRepositoryImpl(bbcsportNewsApi = get())) } // Specific viewModel pattern to tell Koin how to build MainViewModel viewModel { BBCSportViewModel(bbcRepository = get()) } }

/ Returns a custom OkHttpClient instance with interceptor. Used for building Retrofit service / fun createBBCHttpClient(): OkHttpClient { val client = OkHttpClient.Builder() client.readTimeout(5 * 60, TimeUnit.SECONDS) return client.addInterceptor { val original = it.request() val requestBuilder = original.newBuilder() requestBuilder.header("Content-Type", "application/json") val request = requestBuilder.method(original.method, original.body).build() return@addInterceptor it.proceed(request) }.build() }

/ function to build our Retrofit service / inline fun createBBCWebService( okHttpClient: OkHttpClient, factory: CallAdapter.Factory, baseUrl: String ): T { val retrofit = Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create())) .addCallAdapterFactory(CoroutineCallAdapterFactory()) .addCallAdapterFactory(factory) .client(okHttpClient) .build() return retrofit.create(T::class.java) }

I want to know where I am making mistake

kyodgorbek commented 4 years ago

fixed

DraganMaricDeveloper commented 4 years ago

Hi kyodgorbek. Can you please tell me how you fixed it? I am facing the same problem. I have implemented teh same logic in application class.

Jimaloo commented 3 years ago

Hi kyodgorbek. Can you please tell me how you fixed it? I am facing the same problem. I have implemented teh same logic in application class.

I'd like to know as well.

NickPerozzi commented 2 years ago

@kyodgorbek do you remember how you fixed this by chance?

fcat97 commented 2 years ago

I had the same problem with ObjectBox database. Maybe the problem is getting singleton instance inside factory { } block multiple times.

Problematic code: Trying to get a singleton instance inside a factory block doesn't provide a singleton, rather a new instance.


// singleton for `BoxStore` Database
// No problem here. See last lines...
single {
MyObjectBox.builder()
.androidContext(androidContext())
.name(BuildConfig.LIBRARY_PACKAGE_NAME)
.build()
}

// factory for local repository factory { LocalRepositoryImpl( pageBox = get(), tagBox = get() ) }

// factory for entities // here is the main problem. Maybe in factory block get is trying to get new instance each time. factory { get().boxFor(Page::class.java) } factory { get().boxFor(TrxTag::class.java) }


> Solution: Get singleton instance once in factory block
```kotlin
// using function resolves the issue
fun provideLocalRepository(boxStore: BoxStore): LocalRepository {
    return LocalRepositoryImpl(
        pageBox = boxStore.boxFor(Page::class.java),
        tagBox = boxStore.boxFor(TrxTag::class.java),
    )
}

// singleton for `BoxStore` Database
single {
    MyObjectBox.builder()
        .androidContext(androidContext())
        .name(BuildConfig.LIBRARY_PACKAGE_NAME)
        .build()
}

// factory for local repository which depends on `BoxStore` only
factory { provideLocalRepository(get()) }