Koin dependency injection integration with Jetpack Compose for Kotlin Multiplatform development.
—
Functions to retrieve current Koin application and scope contexts from anywhere in the Compose hierarchy, providing access to the underlying Koin framework for advanced use cases.
Retrieve the current Koin application instance from the Compose context for direct access to Koin APIs.
/**
* Retrieve the current Koin application instance from composition
* @return Koin instance
* @throws UnknownKoinContext if Koin context is not found
*/
@Composable
fun getKoin(): KoinUsage Examples:
@Composable
fun AdvancedComponent() {
val koin = getKoin()
// Access Koin APIs directly
val hasDefinition = koin.getOrNull<UserService>() != null
val scopeIds = koin.scopeRegistry.getAllScopeIds()
// Create custom scopes
val customScope = koin.createScope("custom-scope", named("feature"))
// Access properties
val apiUrl = koin.getProperty<String>("api.url")
// Manual dependency resolution
val service = koin.get<ApiService>(qualifier = named("v2"))
}Retrieve the current Koin scope from the Compose context for scope-specific operations.
/**
* Retrieve the current Koin scope from composition
* @return Scope instance
* @throws UnknownKoinContext if Koin context is not found
*/
@Composable
fun currentKoinScope(): ScopeUsage Examples:
@Composable
fun ScopeAwareComponent() {
val currentScope = currentKoinScope()
// Get scope information
val scopeId = currentScope.id
val scopeQualifier = currentScope.scopeQualifier
// Resolve scoped dependencies manually
val scopedService = currentScope.get<ScopedService>()
// Check if definition exists in current scope
val hasService = currentScope.getOrNull<MyService>() != null
// Create linked scope
val linkedScope = currentScope.createScope(
scopeId = "linked-scope",
qualifier = named("linked")
)
}Use getKoin() for advanced Koin framework features not directly exposed through Compose APIs:
@Composable
fun KoinIntrospection() {
val koin = getKoin()
// Module management
val modules = koin.loadModules(listOf(dynamicModule))
koin.unloadModules(listOf(obsoleteModule))
// Property access
val config = mapOf(
"debug" to koin.getProperty<Boolean>("debug", false),
"version" to koin.getProperty<String>("app.version", "unknown")
)
// Scope registry inspection
val allScopes = koin.scopeRegistry.getAllScopes()
val rootScope = koin.scopeRegistry.rootScope
// Bean registry inspection
val definitions = koin.instanceRegistry.instances.size
}Use currentKoinScope() to navigate and manipulate scope hierarchies:
@Composable
fun ScopeHierarchy() {
val scope = currentKoinScope()
// Navigate scope hierarchy
val rootScope = scope.koin.scopeRegistry.rootScope
val parentScope = scope.getSource()
// Scope lifecycle management
val isActive = !scope.closed
val scopeDefinition = scope._scopeDefinition
// Linked scope creation
val childScope = scope.createScope(
scopeId = "child-${UUID.randomUUID()}",
qualifier = named("child")
)
// Cleanup on disposal
DisposableEffect(scope) {
onDispose {
if (!childScope.closed) {
childScope.close()
}
}
}
}Create reactive state from Koin properties:
@Composable
fun ReactiveConfig() {
val koin = getKoin()
// Convert Koin properties to Compose state
val debugMode by remember {
derivedStateOf { koin.getProperty<Boolean>("debug", false) }
}
val theme by remember {
derivedStateOf { koin.getProperty<String>("ui.theme", "light") }
}
// React to configuration changes
LaunchedEffect(debugMode) {
if (debugMode) {
println("Debug mode enabled")
}
}
}Use scopes for component-specific state management:
@Composable
fun ScopedState() {
val scope = currentKoinScope()
// Create scope-specific state
val scopedData by remember(scope) {
mutableStateOf(scope.get<InitialData>())
}
// Scope-specific effects
LaunchedEffect(scope) {
scope.get<ScopeListener>().onScopeCreated(scope.id)
}
DisposableEffect(scope) {
onDispose {
scope.get<ScopeListener>().onScopeDestroyed(scope.id)
}
}
}Both functions throw UnknownKoinContext when Koin context is not properly initialized:
@Composable
fun SafeContextAccess() {
try {
val koin = getKoin()
val scope = currentKoinScope()
// Use Koin and scope
NormalOperation(koin, scope)
} catch (e: UnknownKoinContext) {
// Handle missing Koin context
ErrorMessage("Koin context not initialized")
}
}
@Composable
fun ErrorMessage(message: String) {
Text(
text = message,
color = MaterialTheme.colors.error,
style = MaterialTheme.typography.body1
)
}Cache Koin context access when used multiple times in the same composable:
@Composable
fun OptimizedContextAccess() {
val koin = remember { getKoin() }
val scope = remember { currentKoinScope() }
// Multiple operations with cached contexts
LaunchedEffect(koin, scope) {
val service1 = koin.get<Service1>()
val service2 = scope.get<Service2>()
val property = koin.getProperty<String>("config")
// Perform operations...
}
}Access contexts only when needed to avoid unnecessary exceptions:
@Composable
fun ConditionalAccess(needsKoin: Boolean) {
if (needsKoin) {
val koin = getKoin()
val scope = currentKoinScope()
// Use contexts only when needed
KoinDependentContent(koin, scope)
} else {
StaticContent()
}
}remember to cache context access when used multiple timesUnknownKoinContext appropriatelyDisposableEffectInstall with Tessl CLI
npx tessl i tessl/maven-io-insert-koin--koin-compose-jvm