1 min read

Dependency injection with Koin

Scopes

The scopes determine how many instances will be created. There are 3 main scopes:

  • factory: a new instance is created every time an object is requested.
  • single: only one instance is created within an application.
  • viewModel: only one instance is created within an activity, fragment or navigation graph. It replaces the viewModel scope from Koin allowing to provide interfaces that do not extend Android ViewModel component but with implementations that extend PoqViewModel.

The platform uses special scopes to declare dependencies which clients do NOT need to use: poqFactory, poqSingle, poqViewModel. Instead, client should use the scopes defined above.

To identify the scope of a dependency, visit the platform module where that definition is declared. In Android Studio to find the scope of a dependency, you can use Find in Path (Mac: Command+Shift+F, Windows: Control+Shift+F) and search with Scope for the interface you need between chevrons (<InterfaceYouAreLookingFor>).

How to customize dependencies

In order to customise dependencies with Koin you will need to:

  1. Create a Koin module.
    val myModule = { ... }
  2. Identify the dependency that you want to override and its scope.
    val myModule = {
    factory<InterfaceToOverride> {
    MyNewImplementation()
    }
    }
  3. In your application that extends CoreApplication, you need to load your new module before calling super.onCreate adding your modules to extraKoinModules list.
    class MyApplication : CoreApplication() {
    override fun onCreate() {
    extraKoinModules.addAll(
    listOf(myModule)
    )
    super.onCreate()
    }
    }

How to get PoqSDK instances

When you need to get the platform instance for a definition to, for example, create a decorator pattern, you can use getPoq() method which will provide the platform instance.

factory<InterfaceToOverride> {
MyNewImplementationWithDecorator(getPoq())
}

If you need to get a platform instance of a ViewModel, you need to use getPoqViewModel() extensions function over context which will provide the platform ViewModel instance attached to the fragment lifecycle:

viewModel<ViewModelToOverride> { (context: Context) ->
MyNewImplementationWithDecorator(context.getPoqViewModel())
}

How to inject dependencies

When you need to inject dependencies, you can use the default Koin methods (get and inject) to inject dependencies with factory and single scopes. For dependencies with viewModel scope, platform has extensions functions over context to get the right scope:

  • poqViewModelActivity / getPoqViewModelActivity: to obtain the viewModel attached to the activity lifecycle.
  • poqViewModelFragment / getPoqViewModelFragment: to obtain the viewModel attached to the fragment lifecycle.
  • poqViewModelNavGraph / getPoqViewModelNavGraph: to obtain the viewModel attached to a navigation graph.

Named dependencies

Some dependencies are named, mostly mappers with a generic interface. All the names are defined and they are accessible in the same module file as where the dependencies are. You need the name when injecting or overriding the dependency:

factory<InterfaceToOverride>(named(definitionName)) {
MyNewImplementation()
}