koin-android

Koin for Android Developers

Gradle Setup

Choose the needed koin-android dependency below:

// Add Jcenter to your repositories if needed
repositories {
    jcenter()    
}
dependencies {
    // Koin for Android
    implementation 'org.koin:koin-android:1.0.0-RC-1'
    // Android Scope feature
    implementation 'org.koin:koin-android-scope:1.0.0-RC-1'
    // Android Scope feature - AndroidX
    implementation 'org.koin:koin-androidx-scope:1.0.0-RC-1'
    // Android Architecture ViewModel feature
    implementation 'org.koin:koin-android-viewmodel:1.0.0-RC-1'
    // Android Architecture ViewModel feature - AndroidX
    implementation 'org.koin:koin-androidx-viewmodel:1.0.0-RC-1'
}

Declare a module

To declare a Koin module, we use the Koin DSL. Below is a short example:

val appModule = module {

    // Factory of MyPresenter - resolve Repository instance
    // produce a new instance on each demand
    factory<MyPresenter>()

    // Single instance of Repository
    single<Repository> { MyRepository() }
}

All components described in modules can/should be injected by constructor.

NB: you can get the Android Context instance by using androidContext() function.

Start Koin

The startKoin() function is called from an Application class:

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        
        // start Koin context
        startKoin(this, listOf(appModule)
    }
}

You can specify the following options at start:

  • extraProperties - addtionnal properties
  • loadProperties - use assets/koin.properties file
  • logger - Koin logger (default is AndroidLogger)
  • createOnStart - create tagged createOnStart instances at start (default is true)

If you want to start it elsewhere, just use the standard StandAloneContext.startKoin() or loadKoinModules() if you have already started it.

Inject into Android Components

Activity, Fragment & Service are extendend by Koin to be considered as KoinComponent out of the box:

class MyActivity : AppCompatActivity(){

    // Inject MyPresenter
    val presenter : MyPresenter by inject()

    override fun onCreate() {
        super.onCreate()

        // or directly retrieve instance
        val presenter : MyPresenter = get()
    }
}

If you need to inject dependencies from another class and can’t declare it in a module, you can still tag it with KoinComponent interface.

Using Scopes with Android

Extended scope feature for Android are available with koin-android-scope & koin-androidx-scope.

See Scope API section to better know about Scopes basics.

Activity & Fragment scopes

You can retrieve (get or create) the scope associated from your Activity or Fragment with the getCurrentScope() function.

Binding scopes & lifecycle

Koin gives the bindScope function to bind the actual Android component lifecycle, to a given scope. On lifecycle’s end, this will close the bound scope.

class MyActivity : AppCompatActivity() {

    // inject Presenter instance, tied to current MyActivity's scope
    val presenter : Presenter by inject(scope = getCurrentScope())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // bind current lifecycle to Activity's scope
        bindScope(getCurrentScope())
    }

Sharing an instance between components

In a more extended usage, you can use a Scope instance across components. For example, if we need to share a UserSession instance.

First declare a scope definition:

module {
    // Shared user session data
    scope { UserSession() }
}

When needed to begin use a UserSession instance, create a scope for it:

getKoin().createScope("session")

Then use it anywhere you need it:

class MyActivity1 : AppCompatActivity() {

    // inject Presenter instance, tied to current MyActivity's scope
    val userSession : UserSession by inject(scope = getKoin().getScope("session"))
}
class MyActivity2 : AppCompatActivity() {

    // inject Presenter instance, tied to current MyActivity's scope
    val userSession : UserSession by inject(scope = getKoin().getScope("session"))
}

or you can also inject it with Koin DSL. If a presenter need it:

class Presenter(val userSession : UserSession)

Just inject it into constructor, with teh right scope:

module {
    // Shared user session data
    scope { UserSession() }
    // Inject UserSession instance from "session" Scope
    factory { Presenter(get(scope = getScope("session")))}
}

When you have to finish with your scope, just close it:

val session = getKoin().getScope("session")
session.close()

Android Architecture ViewModel

With koin-android-viewmodel & koin-androidx-viewmodel projects, Koin brings special features to manage ViewModel:

  • viewModel special DSL keyword to declare a ViewModel
  • by viewModel() & getViewModel() to inject ViewModel instance (from Activity & Fragment)
  • by sharedViewModel() & getSharedViewModel() to reuse ViewModel instance from hosting Activity (from Fragment)

Let’s declare a ViewModel in a module:

val myModule : Module = applicationContext {
    
    // ViewModel instance of MyViewModel
    // get() will resolve Repository instance
    viewModel<MyViewModel>()

    // Single instance of Repository
    single<Repository> { MyRepository() }
}

Inject it in an Activity:

class MyActivity : AppCompatActivity(){

    // Lazy inject MyViewModel
    val model : MyViewModel by viewModel()

    override fun onCreate() {
        super.onCreate()

        // or direct retrieve instance
        val model : MyViewModel = getViewModel()
    }
}

More about Koin Android Features