Skip to main content
Version: 4.2

Android Scopes

This guide covers Android-specific scope implementations.

info

For core scope concepts, see Scopes.

Overview

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 Hierarchy

Scope TypeLifetimeSurvives RotationDSLAnnotation
ApplicationEntire app✅ Yessingle { }@Singleton
ActivityActivity lifecycle❌ NoactivityScope { }@ActivityScope
Activity RetainedUntil finish()✅ YesactivityRetainedScope { }@ActivityRetainedScope
FragmentFragment lifecycle❌ NofragmentScope { }@FragmentScope
ViewModelViewModel lifecycle✅ YesviewModelScope { }@ViewModelScope

Scope Relationships

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.

Declaring Scoped Dependencies

Compiler Plugin DSL

val appModule = module {
// Activity scope
activityScope {
scoped<ActivityPresenter>()
scoped<ActivityNavigator>()
}

// Fragment scope
fragmentScope {
scoped<FragmentPresenter>()
}

// ViewModel scope
viewModelScope {
scoped<UserCache>()
viewModel<UserViewModel>()
}
}

Annotations

// 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()

Classic DSL

val appModule = module {
activityScope {
scoped { ActivityPresenter(get()) }
scoped { ActivityNavigator() }
}

fragmentScope {
scoped { FragmentPresenter(get()) }
}

viewModelScope {
scoped { UserCache() }
viewModel { UserViewModel(get()) }
}
}

Using Scopes in Android Components

Activity Scope

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()
}

Activity Retained Scope

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 Scope

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()
}

Type-Based vs Archetype Scopes

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()
}

Type-Based Scope

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()
}

ViewModel Scope

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.

Scope Lifecycle

Handling Scope Close

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()
}
}

Quick Reference

ComponentDelegateBase Class
Activityby activityScope()ScopeActivity
Activity (retained)by activityRetainedScope()RetainedScopeActivity
Fragmentby fragmentScope()ScopeFragment
ScopeSurvives RotationUse Case
activityScope❌ NoUI state, presenters
activityRetainedScope✅ YesForm state, pending requests
fragmentScope❌ NoFragment-specific presenters
viewModelScope✅ YesViewModel dependencies

Best Practices

  1. Use archetypes - Prefer activityScope { } over scope<MyActivity> { } for reusability
  2. Retained for rotation - Use activityRetainedScope for state that should survive rotation
  3. Don't leak - Never inject Activity/Fragment into singletons
  4. Close custom scopes - Always close manually created scopes
  5. Use onCloseScope - For cleanup before scope destruction

Next Steps