How to apply an annotation to a Koin module dependency declaration? - android

I have the following Koin module:
val exampleModule = module {
single<ExampleRepository> { RealExampleRepository() }
}
I need to apply two annotations to RealExampleRepository to supress an experimental coroutines API usage warning.
The annotations I need to apply are:
#FlowPreview
#ExperimentalCoroutinesApi
How can I do this?

I found that it can be done by converting the module to a method and applying the annotations to the method like so:
#FlowPreview
#ExperimentalCoroutinesApi
fun exampleModule() = module {
single<ExampleRepository> { RealExampleRepository() }
}

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())
}
}

How to use a custom AOSP framework classes in Dagger kapt?

I'm using a custom framework headers as a compile time dependencies:
Top-level build.gradle.kts:
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile::class) {
options.compilerArgs.add("-Xbootclasspath/p:sdk/framework.jar")
val newFiles = options.bootstrapClasspath?.files?.toMutableList() ?: mutableListOf<File>()
newFiles.add(File("sdk/framework.jar"))
options.bootstrapClasspath = files(newFiles.toTypedArray())
}
}
}
Module's build.gradle.kts:
compileOnly(project.files("${project.rootDir.absolutePath}/sdk/framework.jar"))
Then if I use a custom class in a «regular» code, it works fine:
val viewProxyManager: ViewProxyManager = getSystemService(Context.VIEW_PROXY_SERVICE) as ViewProxyManager
But if it's used in module's Hilt module, it fails to find the class:
#Provides
#Reusable
fun provideViewProxyManager(
#ApplicationContext
context: Context
): ViewProxyManager {
return context.getSystemService(Context.VIEW_PROXY_SERVICE) as ViewProxyManager
}
ComponentProcessingStep was unable to process 'com.package.remote.agent.app.App_HiltComponents.SingletonC' because 'android.app.ViewProxyManager' could not be resolved.
How to add my framework jar to the kapt tasks classpath?

Android KOIN CRASH - Error Caused by: org.koin.core.error.DefinitionOverrideException: Already existing definition for [Singleton:'java.lang.String'

After updated koin and gradle, the following error prompt
Caused by: org.koin.core.error.DefinitionOverrideException: Already existing definition for [Singleton:'java.lang.String'] at java.lang.String::_root_
I don't know where is the cause of this error.
Here my Application files:
Class MyApplication --> With 2 modules, I'm importing startKoin from: import org.koin.core.context.GlobalContext.startKoin
class MyApplication : Application(), OnMapsSdkInitializedCallback {
override fun onCreate() {
super.onCreate()
startKoin{
if(BuildConfig.DEBUG){
androidLogger(Level.DEBUG)
Timber.plant(Timber.DebugTree())
}
androidContext(this#MyApplication)
modules(applicationModule, viewModelModule)
}
MapsInitializer.initialize(applicationContext, Renderer.LATEST, this)
}
override fun onMapsSdkInitialized(renderer: Renderer) {
when (renderer) {
Renderer.LATEST -> Timber.d("The latest version of the google maps renderer is used.")
Renderer.LEGACY -> Timber.d("The legacy version of the google maps renderer is used.")
}
}
}
MODULE 1 -- applicationModule
// declare a module
val applicationModule = module {
single { BuildConfig.SOME_STRING1 }
single { BuildConfig.SOME_STRING2 }
single { BuildConfig.SOME_STRING3 }
single { BuildConfig.SOME_STRING4 }
single {
Environment(get(named("SOME_STRING1")),
get(named("SOME_STRING2")),
get(named("SOME_STRING3")),
get(named("SOME_STRING4")), get())
} bind GrpcConfiguration::class
//endregion
//region Channel
single {
GrpcChannelBuilder.Companion.prepare(get(), get())
}
//endregion
//region Repository
single { SomeDataRepository(get()) } bind SomeRepository::class
//endregion
//region XXXXProvider
single { XXXXProvider(get()) }
//endregion
//region REST API
single (named("RETROFIT")){
Retrofit.Builder().client(get())
.baseUrl("xxxxxxxxxx")
.addConverterFactory(GsonConverterFactory.create())
.build()
} bind Retrofit::class
//region REST API
single {
val l = HttpLoggingInterceptor()
l.level = HttpLoggingInterceptor.Level.BODY
OkHttpClient.Builder().addInterceptor(l).build()
}
single {
get<Retrofit>(named("RETROFIT")).create(XXXXService::class.java)
} bind XXXXService::class
//endregion
//region DB
single {
MyAppDatabase.getDatabase(get()).someDao()
} bind SomeDao::class
//endregion
//region Util
single {
DarkModeUtil()
} bind DarkModeUtil::class
//endregion
}
Module 2 -- viewModelModule (only for viewmodels)
// declare a module
val viewModelModule: Module = module {
viewModel { HomeViewModel(get(), get(), get()) }
}
build.gradle(:app) KOIN dependencies:
def koin_version = "3.1.6" (I've tried with 3.2.2 and 3.2.1 and got the same error)
// Koin main features for Android
implementation "io.insert-koin:koin-android:$koin_version"
// No more koin-android-viewmodel, koin-android-scope, koin-android-fragment
// Java Compatibility
implementation "io.insert-koin:koin-android-compat:$koin_version"
// Jetpack WorkManager
implementation "io.insert-koin:koin-androidx-workmanager:$koin_version"
// Navigation Graph
implementation "io.insert-koin:koin-androidx-navigation:$koin_version"
ANDROID GRADLE PLUGIN VERSION: 7.2.2
GRADLE VERSION: 7.5
KOTLIN VERSION: 1.7.10
Caused by: org.koin.core.error.DefinitionOverrideException:
Already existing definition for [Singleton:'java.lang.String'] at java.lang.String::_root_
The error indicates that there are many String type definitions without a qualifier.
These lines below are causing the problem.
single { BuildConfig.SOME_STRING1 }
single { BuildConfig.SOME_STRING2 }
If you would like to declare a definition with the same type, you can declare them by giving a name.
single(named("SOME_STRING1")) { BuildConfig.SOME_STRING1 }
single(named("SOME_STRING2")) { BuildConfig.SOME_STRING2 }
single(named("SOME_STRING3")) { BuildConfig.SOME_STRING3 }
single(named("SOME_STRING4")) { BuildConfig.SOME_STRING4 }
You already use named definitions to create an Environment object.
single {
Environment(get(named("SOME_STRING1")),
get(named("SOME_STRING2")), ...
Hope this helps.

Koin Scope and Interface

I am using Koin di library in my project. Version of lib is 1.0.0-RC-1.
My module:
val appModule = module {
scope("UserScope") { UserToaster(androidContext()) as Toaster }
scope("AnonScope") { AnonToaster(androidContext()) as Toaster }
}
I started koin in my Application class and created scope:
override fun onCreate() {
super.onCreate()
startKoin(this, listOf(appModule))
getKoin().getOrCreateScope("AnonScope")
}
And next I tried to inject implementation of Toaster from current scope to variable in Activity. Here the code:
private val toaster: Toaster by inject(scope = "AnonScope")
After this I got an error:
Caused by: org.koin.error.DependencyResolutionException: Multiple definitions found for type 'interface com.example.nkirilov.playground.Toaster (Kotlin reflection is not available)' - Koin can't choose between :
Scope [name='UserScope',class='com.example.nkirilov.playground.Toaster']
Scope [name='AnonScope',class='com.example.nkirilov.playground.Toaster']
Check your modules definition, use inner modules visibility or definition names.
I do not understand why this does not work (If use single with different names - it will work). Is that koin bug? How to avoid this error?
I implemented it like this
Module:
val navigationModule = module {
scope(DI.APP_SCOPE) { ClassA().create }
scope(DI.APP_SCOPE) { get(scopeId = DI.APP_SCOPE).classB }
scope(DI.APP_SCOPE) { get(scopeId = DI.APP_SCOPE).classC }
}
val authModule = module {
scope(DI.AUTH_SCOPE) { ClassA.create(ChildClassB(get(scopeId = DI.APP_SCOPE))) }
scope(DI.AUTH_SCOPE) { get(scopeId = DI.AUTH_SCOPE).classB }
scope(DI.AUTH_SCOPE) { get(scopeId = DI.AUTH_SCOPE).classC }
}
Main Activity:
private val classC: ClassC by inject(scope = getKoin().getOrCreateScope(APP_SCOPE))
AuthActivity:
private val classC: ClassC by inject(scope = getKoin().getOrCreateScope(DI.AUTH_SCOPE))
your definitions have the same name in Koin. Current version (~1.0.*) avoid you to specify which scope to use, by automating resolving a type and it's session id.
Can you avoid describe your definitions with same type, like:
val appModule = module {
scope("UserScope") { UserToaster(androidContext()) }
scope("AnonScope") { AnonToaster(androidContext()) }
}
Else we would need a feature to specify which scope to use when resolving a type. You would resolve it with:
val userScope = getScope("UserScope")
get<Toaster>(scope = userScope)

Dagger2 and Kotlin run failed cause by :app:compileDebugKotlinAfterJava

I'm trying to implement Dagger 2 in a test app to learn Clean Architecture and dependancy injection in Kotlin language.
EDIT :
I can compile thanks to #Logain, but I have always the static member problem with Dagger in my singleton (see below my TaskWorker), so I'm looking for how can I fix this error
But i got a problem, my DaggerComponent is well generated when i do a rebuild, but not when i want to run my app for testing, it fails and disappears. It fails with this error :
Error:(21, 29) Unresolved reference: DaggerInjectorComponent
Error:Execution failed for task ':app:compileDebugKotlinAfterJava'.
> Compilation error. See log for more details
While when i do a rebuild, this task is passed correctly
:app:compileDebugKotlinAfterJava
So i don't understand why it fails.
Here is my InjectorComponent :
#Singleton
#Component(modules = arrayOf(ContextDaggerModule::class, LocalStoreDaggerModule::class))
interface InjectorComponent {
fun inject(realmLocalStore: RealmLocalStore)
fun inject(taskWorker: TaskWorker)
}
ContectDaggerModule :
#Module
class ContextDaggerModule (val app: Application) {
#Provides
#Singleton
fun provideContext(): Context = app
#Provides
#Singleton
fun provideApplication(): Application = app
#Provides
#Singleton
fun provideResources(): Resources = app.resources
}
LocalStoreDaggerModule :
#Module
class LocalStoreDaggerModule {
#Provides
#Singleton
fun provideLocalStore(context: Context): LocalStore {
return RealmLocalStore(context)
}
}
I think the problem is caused because I inject dependencies in Object-declarations but all elements are static and Dagger does not appreciate it.
So, i try to hack it with a simple override getter and injecting data but nop.
Here is my "hack" :
object TaskWorker {
// #Inject lateinit var localStore: LocalStore
// Not work cause it's a static variable
var localStore: LocalStore? = null
#Inject
get() = localStore
// some cool function
}
I follow this code and this tutorial
I use these dependencies :
// Dagger2
compile 'com.google.dagger:dagger:2.11'
kapt 'com.google.dagger:dagger-compiler:2.11'
provided 'org.glassfish:javax.annotation:10.0-b28'
Make sure you are using:
kapt {
generateStubs = true
}
Due to some limitations on kapt
Or just try with:
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
You don't need this.
kapt {
generateStubs = true
}
Just apply the plugin:
apply plugin: 'kotlin-kapt'
and add the dependencies:
compile androidDependencies.dagger2
compile androidDependencies.dagger2Android
kapt androidDependencies.dagger2Kapt
sometimes the tasks fail with errors like that. Try to clean and as last resort use invalidate and restart. Most of the times it works.

Categories

Resources