Decompose

repository·master·Indexed 25 days ago

https://github.com/arkivanov/decompose

A Kotlin Multiplatform library for building tree-structured, lifecycle-aware business logic components. Decompose decouples business logic from the UI, enabling shared navigation and state management across Android, iOS, Desktop, and Web. It provides tools for routing, state preservation, and lifecycle management, supporting pluggable UIs such as Jetpack Compose, SwiftUI, and Kotlin/React.

Tokens
60.5K
Snippets
106
Records
205
Agent score
83%

What's inside Decompose

  1. Overview of Decompose

    master

    Decompose is a Kotlin Multiplatform library designed to break down code into tree-structured, lifecycle-aware business logic components (BLoC). It provides routing functionality and supports pluggable UIs such as Jetpack/Multiplatform Compose, Android Views, SwiftUI, and Kotlin/React.

    Key benefits include:

    • Separation of Concerns: Clear boundaries between UI and non-UI code.
    • Testability: Business logic can be tested with pure multiplatform unit tests.
    • Navigation: Navigation state is fully exposed, allowing for custom animations and UI implementations. Navigation is treated as a pure function from old state to new state.
    • Lifecycle Awareness: Components are lifecycle-aware and can continue working in the background even when their UI is not present.
    • State Preservation: Supports automatic state preservation on Android and manual preservation on other targets via kotlinx-serialization.
    • Dependency Injection: Supports proper DI and IoC via constructors.
  2. Understand the Child Items navigation model

    master

    The Child Items navigation model (experimental since 3.4.0-alpha02) is designed for managing a list of components with flexible lifecycle states. Unlike other models, it allows multiple active components to exist simultaneously with different lifecycle states. This is ideal for lazy lists or grids where component lifecycles are updated based on the viewport.

    Key Entities:

    • Items: Represents the navigation state. It contains items (a unique list of child configurations) and activeItems (a map of lifecycle states for instantiated components).
    • ChildItems: A data class storing the list of configurations and the map of active components/lifecycles.
    • ItemsNavigation: An interface used to accept navigation commands and forward them to observers.

    Important Constraints:

    • Uniqueness: Child configurations must be unique (by equality) within the Child Items model. Duplicate configurations will trigger an IllegalStateException regardless of any experimental flags.
  3. Choose a navigation model

    master

    Decompose provides several predefined navigation models depending on your UI requirements. Use childStack for permanent components, or one of the following for dynamic switching:

    • Child Stack: Organize child components in a stack and navigate between them.
    • Child Slot: Activate or dismiss one child component at a time.
    • Child Pages: Organize child components in a list with one selected component.
    • Child Panels: Organize child components in a multi-pane mode with dynamic switching.
    • Child Items: Manage an arbitrary list of child components (e.g., for a lazy list).
    • Generic Navigation: Use this if you need to create a custom navigation model.

    Note: If a parent component contains multiple navigation models of the same kind, you must provide unique key arguments to distinguish them.

  4. Understand the Component concept

    master

    A component is a class that encapsulates logic and potentially child components. Each component has its own lifecycle managed by Decompose, meaning everything inside a component is scoped to its lifecycle.

    Key architectural principles:

    • UI is optional and pluggable: Components do not depend on UI; instead, the UI depends on components.
    • Navigation via Components: Unlike traditional approaches where ViewModels drive navigation from the UI, Decompose uses components for navigation. This keeps the UI layer thin and allows for high code sharing across platforms.
    • Testability: Components can be unit or integration tested without instrumentation, making tests fast and reliable.
  5. Understand the Web Navigation API

    master

    The Web Navigation API (experimental since 3.3.0-alpha01) synchronizes a Decompose navigation model with the browser's URL and history. It supports the following navigation models:

    • Child Stack
    • Child Pages
    • Child Panels

    Note: Child Slot is currently not supported. The API allows for nested navigation, but a component can have at most one child WebNavigationOwner at a time.

  6. Understand the Child Stack navigation process

    master

    When navigating with a Child Stack:

    • Lifecycle Management: The model compares the new stack with the previous one. Removed components are destroyed, and only the top component is resumed. Components in the back stack are either stopped or destroyed.
    • Synchronicity: Navigation is usually synchronous. However, if navigation is triggered recursively (e.g., calling pop from the onResume callback of a component being pushed), the calls are queued and performed one by one after the current navigation finishes.
  7. Understand the Child Slot navigation model

    master

    A Child Slot is a navigation model that manages at most one active child component at a time. It allows you to activate a child, replace the current child with a new one, or dismiss the child entirely.

    Common use cases include:

    • Displaying dialogs
    • Showing drawers or bottom sheets
    • Toggling the visibility of specific views

    The model relies on two main entities:

    • ChildSlot: A data class holding the currently active child (if any).
    • SlotNavigation: An interface used to issue navigation commands (like activate or dismiss) which are then propagated to observers.
  8. Understand the Child Stack navigation model

    master

    The Child Stack is a navigation model for managing a stack of components, similar to FragmentManager. It manages component lifecycles: when a new component is pushed, the active component is stopped; when a component is popped, the previous one is resumed.

    Key entities:

    • ChildStack: A data class containing the stack of components and their configurations.
      • active: The currently active component.
      • backStack: The stack of inactive components.
    • StackNavigation: An interface used to issue navigation commands (like push or pop) which are then forwarded to observers.
  9. Understand the Child Panels navigation model

    master

    The Child Panels navigation model manages a set of up to three child components (panels):

    • Main (required)
    • Details (optional)
    • Extra (optional)

    This model is useful for implementing List-Details layouts. Each panel has its own Lifecycle controlled by the ChildPanelsMode.

    Warning: This navigation model is experimental (since version 3.2.0-beta01) and the API is subject to change.

  10. Understand the Child Pages navigation model

    master

    Child Pages is a navigation model designed for managing a list of components (pages) where one component is selected (active) at a time. It is ideal for pager-like interfaces.

    Lifecycle Behavior

    By default, the lifecycle states of the components are:

    • Selected page: ACTIVE
    • Immediate neighbors: INACTIVE
    • All other pages: DESTROYED

    You can implement custom logic (e.g., circular behavior) for these states.

    Core Entities

    • Pages: Represents the navigation state. It contains items (a unique list of child configurations) and selectedIndex.
    • ChildPages: A data class storing the actual list of child components (items) and the selectedIndex.
    • PagesNavigation: An interface used to issue navigation commands to observers.

    Configuration Requirements

    Each child component has a configuration. For Child Pages, configurations must be unique (by equality) within the Child Pages model to ensure proper identification and state management.

  11. Use Decompose-Router for Conductor-inspired navigation

    master
    Decompose-Router is a lightweight Compose-multiplatform navigation library that leverages Decompose. It provides an API inspired by Conductor, which may be easier to use if you find the standard Decompose API cumbersome.
  12. Explore the Multi-Feature Sample App

    master

    The Multi-Feature Sample App is a comprehensive demonstration of Decompose capabilities. It showcases various navigation models, state management, and multi-platform UI integration.

    Key features demonstrated include:

    • Navigation Models: Child Stack, Child Slot, Child Pages, Child Items, and Generic Navigation.
    • State & Instance Management: Using StateKeeper for state preservation and InstanceKeeper for retaining instances (e.g., surviving Android configuration changes).
    • Pluggable UI: Support for Android Views, Compose, SwiftUI, and Kotlin/React.
    • Advanced Layouts: Single-pane and multi-pane navigation.
    • Dynamic Features: Integration with Android Play Feature Delivery.
    • Testing: Integration tests for components and Compose UI tests.

    Note: The Gradle files in this sample are configured for library maintenance and should not be used as a reference for your own KMP projects. Refer to the official KMP documentation for project configuration.