Understanding Android Scopes with Koin

Components Lifecycle in Android is one of the biggest pain points for Android developers. Let’s add dependency injection complexity with scope management over that … and you can go into a very complex and frustrating situation😭
What is a Scope? What do you mean by Android Scope and how to deal with it? Let’s come back to those concepts to better understand them.
⚠️ The following APIs shown below will be available in Koin 3.0.1 & 2.3.0 ⚠️ Check the last release notes at https://insert-koin.io/blog
This article is inspired by Manuel Vivo’s article, Scoping in Android and Hilt. Manuel has shown how it works for Dagger Hilt. I will explain here how it works for Koin.
What is a scope?
A scope/is a fixed duration of time or method calls in which an object exists. In other words, a scope is a context under which a given key refers to the same instance. Another way to look at this is to think of scope as the amount of time an object’s state persists. When the scope context ends, any objects bound under that scope are said to be /out of scope/and cannot be injected again in other instances.
— Dependency Injection by Dhanji R. Prasanna
In a nutshell, a scope is a space where we are maintaining instances for a specific duration of time. What about Android scope? We maintain instances for the duration of an Android component lifecycle.
Android components have their own lifecycle (Activity, Fragment, Service …). Each property inside those instances follows the underlying component’s lifecycle. In other words, your properties will be garbage collected at the end of your Android Component lifecycle.
Let’s take a simple example:
The instance of MyPresenter
will follow MyActivity
instance lifecycle. Once the Activity will finish, the presenter instance will be removed from memory. On new MyActivity
instance, the presenter
property will receive a new instance.

Let’s declare it with Koin 😃
️Do you need a scope?
If our properties can be dropped at the end of the lifecycle, why do we need to care about scopes? 🤔
We need a scope for the following reasons:
- keep the same instance of a component, for all other components of the scope
- keep the same instance alive, for a specific period of time
Here are some regular use-cases of scopes, applied to Android applications:
- Android Lifecycle scope — instance tied to an Android lifecycle component (Activity, Fragment …)
- Custom scope — instance kept for a specific duration of time (more than one Activity, i.e: wallet …)
Let’s declare our scope for MyActivity
with the scope
Koin DSL keyword. By writing scope<MyActivity>
, we open a code block to define our scoped instances. Each scoped component will be declared with the scoped
keyword.
This way we can share our MyPresenter
instance with another definition of the scope. We use the get()
keyword to resolve the MyPresenter
instance for the MyAdapter
instance.
Now, in our MyActivity
class let’s use the AndroidScopeComponent
interface and implement the needed scope
property with activityScope()
delegate function to activate our scope as follows:
📌 By using the
AndroidScopeComponent
interface, you need to override ascope
property. This scope will be automatically used in all default API without doing anything else (inject, get, viewModel…)📌 the
activityScope()
delegate function ensures removal of your scoped instances at the end of your Activity lifecycle
Note that Koin also proposes theScopeActivity
class, to help wrap the Activity scope declaration. Check the documentation for more details.
However, on configuration changes, we still lose our MyPresenter
instance. On a new MyActivity
instance, we are creating a new Activity scope.

ViewModel: a game-changer
Since 2017, the Android architecture components are clearly helping to deal with this kind of lifecycle problem by proposing the ViewModel
class. This new component will follow your Activity/Fragment instance and survive a configuration change. It simplifies the lifecycle management with only one lifecycle method to implement: onCleared()
A ViewModel is super easy to declare in Koin 😁
The ViewModel instance is handled by an internal Android factory, allowing it to survive configuration changes.

Similar Dagger Hilt, there is a special scope to survive configuration changes.
The activityRetainedScope()
function will hold instances via a ViewModel holder instance for you.

Every scope has an End
Taking control of scoped instances makes you responsible for closing them. The Koin Scope API helps automatically handle Android scopes for you:
- the
AndroidScopeComponent
interface will help setup a scope for your Android component, by usingactivityScope()
oractivityRetainedScope()
delegates for yourscope
property ScopeActivity
class helps wrap everything for you
The same API exists for Fragment and Service classes. The Fragment scope automatically binds your parent Activity scope. Check the Android Scope documentation for more details: https://insert-koin.io/docs/reference/koin-android/scope
A custom scope helps you maintain an app state for a given duration. Take care to properly setup your create/close sequence. You can check the following documentation for more information about Scope API: https://insert-koin.io/docs/reference/koin-core/scopes
Be sure to use only scoped instances if you really need them. Keep things as simple as possible 👍
From Manuel Vivo’s article:
Scoping can be costly because the provided object stays in memory until the holder is destroyed. Be thoughtful about the use of scoped objects in your application.
Thank you Manuel Vivo for your very helpful feedback 🙏