Understanding the Relationship Between Child and Child.Created in Decompose
In Decompose, Child.Created is a concrete subclass of the sealed Child class that represents an active navigation instance with a non-null component, while Child serves as the polymorphic base type for both active and destroyed children.
Decompose is a Kotlin Multiplatform library for building component-based architectures with navigation. At the heart of its navigation system lies the Child sealed class hierarchy, which models the lifecycle state of each screen or component in the navigation stack. Understanding the relationship between the base Child type and its Child.Created subclass is essential for working with routers like ChildStack and ChildPages.
The Child Sealed Class Hierarchy
The foundation of Decompose's navigation model is defined in decompose/src/commonMain/kotlin/com/arkivanov/decompose/Child.kt. This file declares Child as a generic sealed class with two type parameters: C for the configuration type and T for the component instance type.
sealed class Child<out C : Any, out T : Any> {
abstract val configuration: C
abstract val instance: T?
abstract val key: String
}
The class exposes three abstract properties:
configuration: The immutable configuration object used to create the componentinstance: The live component instance, which may be null if the child has been destroyedkey: A unique string identifier used for state restoration and diffing
Child.Created vs Child.Destroyed
The Child sealed class has two concrete implementations that represent distinct lifecycle states. This design allows Decompose to maintain type safety while handling both active and inactive navigation entries.
Child.Created - The Active Instance
Child.Created represents a child that is currently instantiated and active. It is the primary type you will encounter when working with visible screens in your navigation stack.
Key characteristics:
- The
instanceproperty is guaranteed to be non-null - It appears in router outputs like
ChildStack.activeandChildPages.items - It carries the full component lifecycle
Child.Destroyed - The Inactive State
Child.Destroyed represents a child that has been removed from the active navigation state but whose configuration is retained. This is useful for back-stack persistence and state restoration scenarios.
Key characteristics:
- The
instanceproperty is always null - It maintains the
configurationandkeyfor potential recreation - It appears in historical navigation records
Working with Child.Created in Practice
When building UIs with Decompose, you will typically interact with Child.Created instances obtained from routers. The sealed class structure enables exhaustive when-expressions for type-safe handling.
Pattern matching on Child types:
when (val child = someChild) {
is Child.Created -> {
// child.instance is guaranteed non-null
render(child.instance)
}
is Child.Destroyed -> {
// Handle destroyed state or placeholder
}
}
Accessing the active child from ChildStack:
import com.arkivanov.decompose.router.stack.ChildStack
val stack: ChildStack<String, MyScreenComponent> = routerState()
val topChild: Child.Created<String, MyScreenComponent> = stack.active
val screen = topChild.instance // Non-null, safe to use
Filtering created children from a collection:
val configs = children
.filterIsInstance<Child.Created<*, *>>()
.map { it.configuration }
Key Implementation Files
The following source files define and utilize the Child hierarchy in the Decompose library:
| File | Role |
|---|---|
decompose/src/commonMain/kotlin/com/arkivanov/decompose/Child.kt |
Defines the sealed Child class and its Created and Destroyed subclasses. |
decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/ChildStack.kt |
Exposes navigation state as a stack of Child objects; the active property returns Child.Created. |
decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/pages/ChildPages.kt |
Implements pager-style navigation using Child.Created for visible pages. |
extensions-compose/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/stack/Children.kt |
Provides Compose integration that renders children via a @Composable (Child.Created<C, T>) -> Unit lambda. |
Summary
Childis a sealed base class that represents any navigation entry in Decompose, whether active or destroyed.Child.Createdis a concrete subclass that guarantees a non-null component instance and represents an active screen in the navigation stack.Child.Destroyedrepresents inactive entries with null instances, useful for back-stack persistence.- The sealed hierarchy enables type-safe pattern matching and polymorphic handling in routers like
ChildStackandChildPages. - Source files
Child.kt,ChildStack.kt, andChildPages.ktimplement this architecture.
Frequently Asked Questions
Is Child.Created always returned by routers in Decompose?
Yes, active router outputs like ChildStack.active and visible items in ChildPages always return Child.Created instances, which guarantees that the component instance is available for rendering. Historical or destroyed entries may be represented as Child.Destroyed when maintaining back-stack state.
Can I create Child.Created instances manually?
While the framework typically creates Child.Created instances internally through routers, you can instantiate them directly using the constructor if needed for testing or custom navigation implementations. The constructor accepts the configuration, instance, and key parameters as defined in the sealed class hierarchy.
Why does Child.instance return a nullable type if Child.Created guarantees a non-null instance?
The base Child class defines instance as nullable (T?) to accommodate Child.Destroyed, where the instance is always null. When you have a Child.Created reference, smart casting in Kotlin automatically narrows the type to non-null, allowing safe access without additional null checks.
How does Decompose use Child.Destroyed in navigation state restoration?
Child.Destroyed maintains the configuration and unique key of a removed child without holding the component instance, allowing Decompose to persist navigation history efficiently. When restoring state, the framework can recreate the component from the stored configuration if the user navigates back to that destination.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →