Jetpack Compose integration for Koin dependency injection framework providing Compose-specific APIs for dependency injection
—
Functions for accessing the current Koin application instance and scope within Compose functions, providing fallback mechanisms to ensure reliable access to dependency injection context.
Retrieve the current Koin application from the composition with automatic fallback to the default platform context.
/**
* Retrieve the current Koin application from the composition.
* Falls back to default context if composition context is not available.
*
* @return Current Koin application instance
* @throws Exception if no Koin context is available
*/
@Composable
fun getKoin(): KoinUsage Examples:
import org.koin.compose.getKoin
@Composable
fun DiagnosticsScreen() {
val koin = getKoin()
// Access Koin application properties
val logger = koin.logger
val scopeRegistry = koin.scopeRegistry
// Create custom scopes
val customScope = koin.createScope<MyScope>("custom-scope-id")
// Log current state
LaunchedEffect(Unit) {
logger.info("Current Koin instance: $koin")
logger.info("Active scopes: ${scopeRegistry.size}")
}
}
@Composable
fun ManualDependencyAccess() {
val koin = getKoin()
// Manually get dependencies (alternative to koinInject)
val userService = koin.get<UserService>()
val apiClient = koin.get<ApiClient>(qualifier = named("public"))
// Access with parameters
val sessionService = koin.get<SessionService> {
parametersOf("user-123")
}
}Retrieve the current Koin scope from the composition with automatic fallback to root scope.
/**
* Retrieve the current Koin scope from the composition
* Falls back to root scope if composition scope is not available or closed
*
* @return Current Koin scope instance
* @throws Exception if no Koin scope is available
*/
@Composable
fun currentKoinScope(): ScopeUsage Examples:
import org.koin.compose.currentKoinScope
@Composable
fun ScopeAwareComponent() {
val currentScope = currentKoinScope()
// Check scope properties
val scopeId = currentScope.id
val isRootScope = currentScope.isRoot
val isClosed = currentScope.closed
// Use scope directly for dependency resolution
val service = currentScope.get<MyService>()
Text("Current scope: $scopeId (root: $isRootScope)")
}
@Composable
fun ScopeInspector() {
val scope = currentKoinScope()
// Access scope metadata
LaunchedEffect(scope) {
scope.logger.debug("Accessing scope: ${scope.id}")
// Check if specific dependency exists in this scope
val hasUserService = try {
scope.get<UserService>()
true
} catch (e: Exception) {
false
}
scope.logger.info("UserService available in scope: $hasUserService")
}
}Both functions integrate with Compose's CompositionLocal system:
/**
* Current Koin Application context, as default with Default Koin context
*/
val LocalKoinApplication: ProvidableCompositionLocal<Koin>/**
* Current Koin Scope, as default with Default Koin context root scope
*/
val LocalKoinScope: ProvidableCompositionLocal<Scope>Usage with CompositionLocalProvider:
import androidx.compose.runtime.CompositionLocalProvider
import org.koin.compose.LocalKoinApplication
import org.koin.compose.LocalKoinScope
@Composable
fun CustomKoinProvider(
customKoin: Koin,
customScope: Scope,
content: @Composable () -> Unit
) {
CompositionLocalProvider(
LocalKoinApplication provides customKoin,
LocalKoinScope provides customScope
) {
content()
}
}The function includes comprehensive error handling with fallback mechanisms:
// Internal implementation with fallback
@Composable
fun getKoin(): Koin = currentComposer.run {
try {
consume(LocalKoinApplication)
} catch (e: Exception) {
KoinPlatform.getKoinOrNull()?.let {
it.logger.debug("Error while accessing Koin context. Fallback on default context ...")
it
} ?: error("Can't get Koin context due to error: $e")
}
}The function handles closed scope exceptions gracefully:
// Internal implementation with fallback
@Composable
fun currentKoinScope(): Scope = currentComposer.run {
try {
consume(LocalKoinScope)
} catch (e: ClosedScopeException) {
KoinPlatform.getKoinOrNull()?.let {
it.logger.debug("Error while accessing Koin scope. Fallback on default root scope...")
it.scopeRegistry.rootScope
} ?: error("Can't get Koin scope due to error: $e")
}
}@Composable
fun ValidatedKoinAccess() {
val koin = try {
getKoin()
} catch (e: Exception) {
null
}
if (koin != null) {
// Koin is available
val service = koin.get<MyService>()
ServiceContent(service)
} else {
// Koin not available, show error or fallback
Text("Dependency injection not available")
}
}@Composable
fun ScopeLifecycleMonitor() {
val scope = currentKoinScope()
DisposableEffect(scope) {
scope.logger.debug("Scope ${scope.id} entered composition")
onDispose {
scope.logger.debug("Scope ${scope.id} left composition")
}
}
}@Composable
fun ManualResolution() {
val koin = getKoin()
val scope = currentKoinScope()
// Different ways to resolve dependencies
val service1 = koin.get<MyService>() // From Koin instance
val service2 = scope.get<MyService>() // From specific scope
val service3 = koinInject<MyService>() // Using koinInject (recommended)
// All three approaches can yield the same or different instances
// depending on scope configuration
}// Core Koin interfaces
interface Koin {
val logger: Logger
val scopeRegistry: ScopeRegistry
fun <T : Any> get(clazz: KClass<T>, qualifier: Qualifier? = null): T
fun <T : Any> get(qualifier: Qualifier? = null, parameters: ParametersDefinition): T
fun createScope(scopeId: String): Scope
fun createScope<T>(scopeId: String): Scope
}
interface Scope {
val id: String
val isRoot: Boolean
val closed: Boolean
val logger: Logger
fun <T : Any> get(clazz: KClass<T>, qualifier: Qualifier? = null): T
fun <T : Any> getWithParameters(clazz: KClass<T>, qualifier: Qualifier?, parameters: ParametersHolder): T
fun close()
}
// Composition local types
interface ProvidableCompositionLocal<T> {
val defaultFactory: () -> T
}The fallback mechanisms work differently across platforms:
Falls back to KoinPlatform.getKoin() which looks for Application-level Koin setup
Falls back to global Koin instance managed by KoinPlatform
Falls back to platform-specific Koin platform implementations
// Common exceptions
class ClosedScopeException : Exception()
class UnknownKoinContext : Exception()
class NoBeanDefFoundException : Exception()Common error scenarios:
Install with Tessl CLI
npx tessl i tessl/maven-io-insert-koin--koin-compose