https://kotlinlang.org logo
#koin
Title
# koin
c

Colton Idle

09/22/2023, 9:41 PM
So I'm still new to koin. How would I convert this Dagger/Hilt AppModule providing a single class to be injectable to whoever wants it?
Copy code
@InstallIn(SingletonComponent::class)
@Module
class AppModule {
  @Singleton
  @Provides
  fun provideApiService(): ApiService {
    return ApiServiceBuilder()
      .build(//baseUrl Will GO here)
  }
Would that just be
Copy code
val appModule = module {
  single { ApiServiceBuilder().build() }
}
?
j

Javier

09/22/2023, 9:55 PM
Yes
c

Colton Idle

09/22/2023, 9:56 PM
Awesome... and then on the ViewModel side of it... I currently have this:
Copy code
@HiltViewModel
class MyScreenViewModel
@Inject
constructor(
    val apiService: ApiService,
    val savedStateHandle: SavedStateHandle
) : ViewModel() {
Not sure actually what I would do to convert that^
The docs talk about a viewModel {} keyword... but it makes it seem like those deps would be viewModel scoped (like a viewmodel scope in hilt)
j

Javier

09/22/2023, 9:57 PM
I think there is a viewModel dsl similar to that single. Koin docs are very good as they are oriented with examples
c

Colton Idle

09/22/2023, 9:58 PM
but it sounds like thats not what I want?
it makes it seem like its a scope
j

Javier

09/22/2023, 9:58 PM
you must use viewmodel inside the module dsl and later when you fetch it too, with by viewModel and so on
c

Colton Idle

09/22/2023, 10:00 PM
interesting...
okay. lemme give it a whirl. lol
i feel like there are a few different things to learn with the annotation approach (thats sorta new AFAIK?) and then also theres compile time safety, which is also new from what ive seen.
Alright. This seemed to work. Feel free to critique my very small impl for now
Copy code
class MyApplication : Application(){
  override fun onCreate() {
    super.onCreate()
    startKoin {
      androidContext(this@MyApplication)
      modules(appModule)
    }
  }
}
Copy code
val appModule = module {
  single { buildApiService("<https://myapiUrl>") }
  factory { CloseableCoroutineScope() }
  viewModel { MyViewModel(get(), get()) }
}
Copy code
class MyViewModel (
  private val apiService: ApiService,
  private val closeableCoroutineScope: CloseableCoroutineScope
) : ViewModel(closeableCoroutineScope) {
and
Copy code
@Composable
fun MyScreen() {
  val myViewModel = koinInject<MyViewModel>()
The only thing I'm sorta worried about is whether or not my ViewModel will be properly scoped to the nav graph like how hilt + compose + AAC nav works.
also not sure if i should wrap the koinInject in a remember{}
a

ascii

09/23/2023, 5:52 AM
I'm curious as to why you're moving from Hilt to Koin. The way I see it, most people want to migrate to Hilt because it's AndroidX and integrates better with pretty much any other AndroidX lib. Plus, Hilt does its magic compile-time, while Koin is fully-runtime I think? Meaning Hilt just offers better performance. Feel free to correct me.
v

Vlad

09/23/2023, 10:40 AM
The only reason I see to migrate from hilt to koin - is that koin is KMP.
c

Colton Idle

09/23/2023, 1:45 PM
@ascii yeah. thats pretty much it. i do think that hilt/dagger will overall have better support for how it integrates with compose/navigation/lifecycle/etc. + i invested a lot of time to understand dagger. it made sense to use. im still not a fan of the syntax of koin, but I want to do kmp compose and so i want something that can do that.
👍 1
so yeah, @Vlad is right on that
m

Matt Rea

09/23/2023, 5:17 PM
There is the
koin-androidx-compose-navigation
artifact that exposes
koinNavViewModel()
, which uses
LocalViewModelStoreOwner
. However I don’t think this is set automatically by androidx navigation? You could always inspect your app at runtime and see if that CompositionLocal is populated. But you may need to set it yourself https://stackoverflow.com/questions/69002018/why-a-new-viewmodel-is-created-in-each-compose-navigation-route
Also, there’s other ways to declare your dependencies, if you don’t like the syntax I prefer singleOf(::MyObject), viewModelOf(::MyViewModel), etc. This allows you to avoid writing
get()
at all. For most objects, you just declare your dependency once and never have to update the declaration again https://insert-koin.io/docs/reference/koin-android/dsl-update But there’s also the KSP codegen stuff, which works pretty well. But I like a little more control. Sometimes I want to put a small bit of code in my DI - like instantiating OkHttpClient.Builder() for example https://insert-koin.io/docs/reference/koin-annotations/start
a

arnaud.giuliani

09/26/2023, 3:43 PM
The way I see it, most people want to migrate to Hilt because it's AndroidX and integrates better with pretty much any other AndroidX lib. Plus, Hilt does its magic compile-time, while Koin is fully-runtime I think? Meaning Hilt just offers better performance.
@ascii Koin is using the same Android API, and save up to 75% of your compilation time. It's also far more easy to lear and use, and doesn't constraint you in terms of development paradigm
👍 1
In terms of time access, an instance in Koin is retrieve in around 0,01ms thanks to optimized tree searching.
Scalability is neither a problem, as you can organize scale over hundreds of modules easily. Big company are using it 👍
and if you need compilation safety, look at Koin Annotations
❤️ 1
2 Views