[go: up one dir, main page]

Menu

Introduction to Decompose

Relevant source files

Purpose and Scope

This page provides a high-level introduction to Decompose, explaining what it is, its core architecture, and fundamental concepts. It covers the library's purpose, supported platforms, key components, and navigation models. For detailed setup instructions, see Installation and Setup. For hands-on examples, see Quick Start Guide. For in-depth coverage of specific concepts, see Core Concepts and Navigation Models.

What is Decompose?

Decompose is a Kotlin Multiplatform library for breaking down code into tree-structured, lifecycle-aware business logic components (BLoC) with routing functionality and pluggable UI. It enables sharing business logic and navigation across multiple platforms while keeping UI platform-specific.

The library provides:

  • Component management: Lifecycle-aware components organized in parent-child hierarchies
  • Navigation models: Multiple navigation patterns (Stack, Slot, Pages, Panels, Items) for different use cases
  • State management: Multiplatform observable state holders that work across all supported platforms
  • UI independence: Business logic is completely separate from UI, allowing any UI framework to be plugged in

Sources: README.md15 docs/index.md5

Supported Platforms

Decompose supports the following Kotlin Multiplatform targets:

PlatformTargets
Androidandroid
JVM/Desktopjvm
iOSiosX64, iosArm64, iosSimulatorArm64
tvOStvosArm64, tvosX64, tvosSimulatorArm64
watchOSwatchosArm32, watchosArm64, watchosX64, watchosSimulatorArm64
macOSmacosX64, macosArm64
Webjs (IR and Legacy), wasmJs

Sources: README.md47 docs/index.md8-15

Core Architecture

Module Structure

Module Description:

  • decompose: Core module providing ComponentContext, navigation models, and Value<T> observable
  • extensions-compose: Stable Compose integration with Children composable and animations
  • extensions-compose-experimental: Experimental features including shared element transitions and predictive back
  • extensions-android: Android View system integration utilities
  • jetpack-component-context: AndroidX Architecture Components integration

Sources: deps.versions.toml1-70 README.md42-48 docs/getting-started/installation.md5-109

Component Foundation

Description:

  • ComponentContext aggregates four essential services from the Essenty library
  • DefaultComponentContext is the standard implementation used to create root components
  • Value<T> provides multiplatform-friendly observable state (Swift/ObjC compatible)
  • Each component receives its own ComponentContext with isolated lifecycle and state

Sources: docs/component/overview.md24-31 decompose/build.gradle.kts56-60

Key Concepts

ComponentContext

ComponentContext is the central abstraction in Decompose. Every component receives a ComponentContext which provides:

  • Lifecycle management: LifecycleOwner from Essenty
  • State preservation: StateKeeperOwner for surviving configuration changes and process death
  • Instance retention: InstanceKeeperOwner for retaining instances (like AndroidX ViewModel)
  • Back handling: BackHandlerOwner for intercepting back button events

Components typically receive ComponentContext via constructor and use delegation:

For detailed information, see ComponentContext.

Sources: docs/component/overview.md24-43 docs/getting-started/quick-start.md26-44

Decompose provides five predefined navigation models, each suited for different use cases:

Navigation Model Use Cases:

  • Child Stack: Traditional screen-to-screen navigation with back stack
  • Child Slot: Dialogs, bottom sheets, or any single optional overlay
  • Child Pages: Horizontal pagers, tab navigation, carousel interfaces
  • Child Panels: Responsive layouts that adapt to screen size (single/dual/triple pane)
  • Child Items: Lazy lists or grids with optimized lifecycle management

For detailed information, see Navigation Models.

Sources: docs/navigation/overview.md6-12 README.md55-59

Component Configurations

Each child component is represented by a persistent configuration class that:

  • Must be immutable
  • Must correctly implement equals() and hashCode()
  • Must be @Serializable (using kotlinx-serialization)
  • Contains only persistent arguments, not dependencies

Configurations are automatically persisted using StateKeeper, allowing child components to be recreated after configuration changes or process death.

Sources: docs/navigation/overview.md19-36 docs/getting-started/quick-start.md152-158

Value Observable State

Value<T> is Decompose's multiplatform observable state holder, providing:

  • Thread-safe state observation via subscribe/unsubscribe
  • Swift/ObjC compatibility for iOS integration
  • No dependency on Kotlin coroutines (works with any reactive library)
  • Direct integration with Compose via subscribeAsState()

MutableValue<T> provides mutable variant for internal state management.

Alternative: You can use any state holder (StateFlow, LiveData, Reaktive Observable) instead of Value<T>. For detailed information, see Value and Observable State.

Sources: docs/component/overview.md190-203 docs/getting-started/quick-start.md51-82

Why Use Decompose?

Clear Separation of Concerns

Decompose draws strict boundaries between UI and business logic:

Benefits:

  • Better testability: Business logic tested with pure multiplatform unit tests
  • Pluggable UI: Same business logic works with any UI framework
  • Code sharing: Maximum code reuse across platforms
  • Maintainability: Changes to UI don't affect business logic and vice versa

Sources: README.md24-28 docs/index.md19-22

Lifecycle-Aware Components

Components have full lifecycle awareness with states matching Android's lifecycle:

StateDescription
CREATEDComponent exists but is not visible
STARTEDComponent is visible but not active
RESUMEDComponent is active and receiving input
DESTROYEDComponent is being destroyed

Key Features:

  • Components in back stack remain CREATED (continue working in background)
  • State and instances preserved across configuration changes
  • Automatic lifecycle management during navigation
  • Proper cleanup when components are destroyed

For detailed information, see Component Lifecycle.

Sources: README.md32-35 docs/component/overview.md3

Type-Safe Navigation

Navigation uses persistent configurations with type-safe arguments:

Advantages:

  • Compile-time safety for navigation arguments
  • Automatic state preservation across process death
  • No string-based routing fragility
  • Proper dependency injection via constructor

Sources: README.md30 docs/navigation/overview.md19-36

Decompose as a Library vs Framework

Decompose can be used as either a library or a framework:

As a Library: Use only the features you need (e.g., just ComponentContext for lifecycle management)

As a Framework: Follow the recommended component-based architecture with navigation models

The ComponentContext interface can be extended with custom implementations, allowing:

  • Adding custom properties and functions
  • Storing additional data per component
  • Creating alternative navigation solutions (e.g., Decompose-Router)

Sources: README.md66-69 docs/index.md31-34

Component Hierarchy Pattern

Characteristics:

  • Tree structure with parent-child relationships
  • Each parent knows only its immediate children
  • Each component has its own ComponentContext and lifecycle
  • Nested navigation is fully supported
  • Back stack components remain alive in CREATED state

Sources: README.md71-82 docs/component/overview.md11-21

Getting Started

To begin using Decompose:

  1. Add dependencies: See Installation and Setup for Gradle configuration
  2. Create your first component: See Quick Start Guide for hands-on examples
  3. Understand core concepts: See Core Concepts for in-depth explanations
  4. Implement navigation: See Navigation Models for different navigation patterns
  5. Integrate with UI: See UI Framework Integration for platform-specific UI setup

Essential Dependencies

The core decompose module depends on the Essenty library, which provides:

  • lifecycle: Lifecycle management
  • state-keeper: State preservation
  • instance-keeper: Instance retention
  • back-handler: Back button handling

These are included as API dependencies, so no manual addition is required.

Sources: docs/getting-started/installation.md31-33 decompose/build.gradle.kts56-60

Platform-Specific Considerations

Android

  • Use defaultComponentContext() extension function in Activity or Fragment
  • Automatic state preservation via SavedStateHandle mechanism
  • Integration with AndroidX components available via jetpack-component-context module

iOS (SwiftUI/Compose)

  • Use ApplicationLifecycle() or manual LifecycleRegistry management
  • StateValue property wrapper for SwiftUI observation
  • Export Decompose and Essenty to iOS framework

Desktop (Compose)

  • Use LifecycleController to bind lifecycle to window state
  • Create root component on UI thread with runOnUiThread
  • Handle back button via keyboard events if needed

Web (JS/Wasm)

  • Attach LifecycleRegistry to document visibility events
  • Use withWebHistory for browser back/forward button integration
  • React integration via useAsState hook

For detailed platform-specific setup, see Quick Start Guide.

Sources: docs/getting-started/quick-start.md304-595 docs/component/overview.md67-187

Sample Applications

Decompose includes comprehensive sample applications demonstrating:

  • Nested reusable components with all navigation models
  • State preservation and instance retention
  • Multiple UI frameworks (Compose, Android Views, SwiftUI, React)
  • Play Feature Delivery for Android
  • Compose UI tests

Sample locations:

For complete sample documentation, see Samples.

Sources: docs/samples.md1-53 README.md87-98


Sources: README.md1-114 docs/index.md1-35 docs/component/overview.md1-285 docs/navigation/overview.md1-51 docs/getting-started/installation.md1-162 deps.versions.toml1-70 mkdocs.yml1-159