Skip to main content
Version: 4.2 - LTS

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​