docs/reference/koin-android/scope.md
This guide covers Android-specific scope implementations.
:::info For core scope concepts, see Scopes. :::
Scopes in Koin allow you to manage the lifecycle of your dependencies to match Android component lifecycles. This prevents memory leaks and ensures proper resource management.
| Scope Type | Lifetime | Survives Rotation | DSL | Annotation |
|---|---|---|---|---|
| Application | Entire app | ✅ Yes | single { } | @Singleton |
| Activity | Activity lifecycle | ❌ No | activityScope { } | @ActivityScope |
| Activity Retained | Until finish() | ✅ Yes | activityRetainedScope { } | @ActivityRetainedScope |
| Fragment | Fragment lifecycle | ❌ No | fragmentScope { } | @FragmentScope |
| ViewModel | ViewModel lifecycle | ✅ Yes | viewModelScope { } | @ViewModelScope |
Application Scope (single { })
└── Activity Retained Scope (survives rotation)
└── Activity Scope
├── Fragment Scope 1
└── Fragment Scope 2
└── ViewModel Scope (can't access Activity/Fragment scope)
:::info Key Principle: Child scopes can access parent scope definitions, but not vice versa. :::
val appModule = module {
// Activity scope
activityScope {
scoped<ActivityPresenter>()
scoped<ActivityNavigator>()
}
// Fragment scope
fragmentScope {
scoped<FragmentPresenter>()
}
// ViewModel scope
viewModelScope {
scoped<UserCache>()
viewModel<UserViewModel>()
}
}
// Activity scope
@ActivityScope
class ActivityPresenter(private val repository: UserRepository)
@ActivityScope
class ActivityNavigator
// Activity retained scope (survives rotation)
@ActivityRetainedScope
class RetainedPresenter
// Fragment scope
@FragmentScope
class FragmentPresenter
// ViewModel scope
@ViewModelScope
class UserCache
@KoinViewModel
@ViewModelScope
class UserViewModel(private val cache: UserCache) : ViewModel()
val appModule = module {
activityScope {
scoped { ActivityPresenter(get()) }
scoped { ActivityNavigator() }
}
fragmentScope {
scoped { FragmentPresenter(get()) }
}
viewModelScope {
scoped { UserCache() }
viewModel { UserViewModel(get()) }
}
}
class MyActivity : AppCompatActivity(), AndroidScopeComponent {
// Create scope tied to Activity lifecycle
override val scope: Scope by activityScope()
// Inject from scope
private val presenter: ActivityPresenter by inject()
}
Or use the convenience base class:
class MyActivity : ScopeActivity() {
// Scope is already set up
private val presenter: ActivityPresenter by inject()
}
Survives configuration changes (rotation, theme change):
class MyActivity : AppCompatActivity(), AndroidScopeComponent {
// Backed by ViewModel lifecycle - survives rotation
override val scope: Scope by activityRetainedScope()
private val presenter: RetainedPresenter by inject()
}
Or use the convenience base class:
class MyActivity : RetainedScopeActivity() {
private val presenter: RetainedPresenter by inject()
}
Fragment scopes are automatically linked to parent Activity scope:
class MyFragment : Fragment(), AndroidScopeComponent {
override val scope: Scope by fragmentScope()
// From fragment scope
private val presenter: FragmentPresenter by inject()
// Can also access Activity scope dependencies
private val activityPresenter: ActivityPresenter by inject()
}
Or use the convenience base class:
class MyFragment : ScopeFragment() {
private val presenter: FragmentPresenter by inject()
}
Generic scope that works with any Activity/Fragment:
module {
activityScope {
scoped<MyPresenter>()
}
}
// Works with any Activity
class ActivityA : ScopeActivity() {
private val presenter: MyPresenter by inject()
}
class ActivityB : ScopeActivity() {
private val presenter: MyPresenter by inject()
}
Scope tied to a specific class:
module {
scope<MyActivity> {
scoped<MyPresenter>()
}
}
// Only works with MyActivity
class MyActivity : AppCompatActivity(), AndroidScopeComponent {
override val scope: Scope by activityScope()
private val presenter: MyPresenter by inject()
}
ViewModels cannot access Activity or Fragment scopes (to prevent memory leaks). Use ViewModel Scope for scoped dependencies:
module {
viewModelScope {
scoped<UserCache>()
scoped<UserRepository>()
viewModel<UserViewModel>()
}
}
@ViewModelScope
class UserCache
@ViewModelScope
class UserRepository(private val cache: UserCache)
@KoinViewModel
@ViewModelScope
class UserViewModel(
private val repository: UserRepository
) : ViewModel()
For detailed ViewModel scope usage, see Scopes - ViewModel Scope.
Override onCloseScope() to run cleanup before scope is destroyed:
class MyActivity : AppCompatActivity(), AndroidScopeComponent {
override val scope: Scope by activityScope()
override fun onCloseScope() {
// Called BEFORE scope.close()
// Scope is still accessible here
}
}
:::warning
Don't access scope in onDestroy() - it's already closed at that point.
:::
Share instances between components with custom scopes:
module {
scope(named("session")) {
scoped<UserSession>()
}
}
class MyActivity : ScopeActivity() {
fun startSession() {
val sessionScope = getKoin().createScope("session", named("session"))
// Link to current scope
scope.linkTo(sessionScope)
// Now UserSession is accessible
val session: UserSession = get()
}
}
| Component | Delegate | Base Class |
|---|---|---|
| Activity | by activityScope() | ScopeActivity |
| Activity (retained) | by activityRetainedScope() | RetainedScopeActivity |
| Fragment | by fragmentScope() | ScopeFragment |
| Scope | Survives Rotation | Use Case |
|---|---|---|
activityScope | ❌ No | UI state, presenters |
activityRetainedScope | ✅ Yes | Form state, pending requests |
fragmentScope | ❌ No | Fragment-specific presenters |
viewModelScope | ✅ Yes | ViewModel dependencies |
activityScope { } over scope<MyActivity> { } for reusabilityactivityRetainedScope for state that should survive rotation