CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-insert-koin--koin-compose-jvm

Koin dependency injection integration with Jetpack Compose for Kotlin Multiplatform development.

Pending
Overview
Eval results
Files

context-access.mddocs/

Context Access

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.

Capabilities

Get Koin Application

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(): Koin

Usage 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"))
}

Get Current Scope

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(): Scope

Usage 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")
    )
}

Advanced Use Cases

Direct Koin API Access

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
}

Scope Hierarchy Navigation

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

Integration with Compose State

Reactive Koin Properties

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

Scope-Based State Management

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

Error Handling

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

Performance Considerations

Caching Context Access

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...
    }
}

Conditional Context Access

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

Best Practices

  1. Cache Context Access: Use remember to cache context access when used multiple times
  2. Handle Exceptions: Always handle UnknownKoinContext appropriately
  3. Conditional Access: Only access contexts when actually needed
  4. Scope Lifecycle: Properly manage created scopes with DisposableEffect
  5. Direct API Usage: Use context access for advanced scenarios not covered by injection APIs
  6. State Integration: Leverage Compose state patterns with Koin contexts for reactive UIs

Install with Tessl CLI

npx tessl i tessl/maven-io-insert-koin--koin-compose-jvm

docs

application-setup.md

context-access.md

dependency-injection.md

index.md

module-management.md

scope-management.md

tile.json