{% setvar book_path %}/reference/androidx/_book.yaml{% endsetvar %} {% include "_shared/_reference-head-tags.html" %}

CompositionKt

public final class CompositionKt


Summary

Public methods

static final @NonNull Composition
Composition(
    @NonNull Applier<@NonNull ?> applier,
    @NonNull CompositionContext parent
)

This method is the way to initiate a composition.

static final @NonNull Composition
@ExperimentalComposeApi
Composition(
    @NonNull Applier<@NonNull ?> applier,
    @NonNull CompositionContext parent,
    @NonNull CoroutineContext recomposeCoroutineContext
)

Create a Composition using applier to manage the composition, as a child of parent.

static final @NonNull ControlledComposition

This method is a way to initiate a composition.

static final @NonNull ControlledComposition
@TestOnly
@ExperimentalComposeApi
ControlledComposition(
    @NonNull Applier<@NonNull ?> applier,
    @NonNull CompositionContext parent,
    @NonNull CoroutineContext recomposeCoroutineContext
)
static final @NonNull CoroutineContext

The CoroutineContext that should be used to perform concurrent recompositions of this ControlledComposition when used in an environment supporting concurrent composition.

Public methods

Composition

public static final @NonNull Composition Composition(
    @NonNull Applier<@NonNull ?> applier,
    @NonNull CompositionContext parent
)

This method is the way to initiate a composition. Optionally, a parent can be provided to make the composition behave as a sub-composition of the parent or a Recomposer can be provided.

It is important to call Composition.dispose this composer is no longer needed in order to release resources.

import androidx.compose.runtime.AbstractApplier
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composition
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.ComposeNode
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember

// Provided we have a tree with a node base type like the following
abstract class Node {
    val children = mutableListOf<Node>()
}

// We would implement an Applier class like the following, which would teach compose how to
// manage a tree of Nodes.
class NodeApplier(root: Node) : AbstractApplier<Node>(root) {
    override fun insertTopDown(index: Int, instance: Node) {
        current.children.add(index, instance)
    }

    override fun insertBottomUp(index: Int, instance: Node) {
        // Ignored as the tree is built top-down.
    }

    override fun remove(index: Int, count: Int) {
        current.children.remove(index, count)
    }

    override fun move(from: Int, to: Int, count: Int) {
        current.children.move(from, to, count)
    }

    override fun onClear() {
        root.children.clear()
    }
}

// A function like the following could be created to create a composition provided a root Node.
fun Node.setContent(
    parent: CompositionContext,
    content: @Composable () -> Unit
): Composition {
    return Composition(NodeApplier(this), parent).apply {
        setContent(content)
    }
}

// assuming we have Node sub-classes like "TextNode" and "GroupNode"
class TextNode : Node() {
    var text: String = ""
    var onClick: () -> Unit = {}
}
class GroupNode : Node()

// Composable equivalents could be created
@Composable fun Text(text: String, onClick: () -> Unit = {}) {
    ComposeNode<TextNode, NodeApplier>(::TextNode) {
        set(text) { this.text = it }
        set(onClick) { this.onClick = it }
    }
}

@Composable fun Group(content: @Composable () -> Unit) {
    ComposeNode<GroupNode, NodeApplier>(::GroupNode, {}, content)
}

// and then a sample tree could be composed:
fun runApp(root: GroupNode, parent: CompositionContext) {
    root.setContent(parent) {
        var count by remember { mutableStateOf(0) }
        Group {
            Text("Count: $count")
            Text("Increment") { count++ }
        }
    }
}
Parameters
@NonNull Applier<@NonNull ?> applier

The Applier instance to be used in the composition.

@NonNull CompositionContext parent

The parent CompositionContext.

Composition

@ExperimentalComposeApi
public static final @NonNull Composition Composition(
    @NonNull Applier<@NonNull ?> applier,
    @NonNull CompositionContext parent,
    @NonNull CoroutineContext recomposeCoroutineContext
)

Create a Composition using applier to manage the composition, as a child of parent.

When used in a configuration that supports concurrent recomposition, hint to the environment that recomposeCoroutineContext should be used to perform recomposition. Recompositions will be launched into the

ControlledComposition

@TestOnly
public static final @NonNull ControlledComposition ControlledComposition(
    @NonNull Applier<@NonNull ?> applier,
    @NonNull CompositionContext parent
)

This method is a way to initiate a composition. Optionally, a parent can be provided to make the composition behave as a sub-composition of the parent or a Recomposer can be provided.

A controlled composition allows direct control of the composition instead of it being controlled by the Recomposer passed ot the root composition.

It is important to call Composition.dispose this composer is no longer needed in order to release resources.

import androidx.compose.runtime.AbstractApplier
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composition
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.ComposeNode
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember

// Provided we have a tree with a node base type like the following
abstract class Node {
    val children = mutableListOf<Node>()
}

// We would implement an Applier class like the following, which would teach compose how to
// manage a tree of Nodes.
class NodeApplier(root: Node) : AbstractApplier<Node>(root) {
    override fun insertTopDown(index: Int, instance: Node) {
        current.children.add(index, instance)
    }

    override fun insertBottomUp(index: Int, instance: Node) {
        // Ignored as the tree is built top-down.
    }

    override fun remove(index: Int, count: Int) {
        current.children.remove(index, count)
    }

    override fun move(from: Int, to: Int, count: Int) {
        current.children.move(from, to, count)
    }

    override fun onClear() {
        root.children.clear()
    }
}

// A function like the following could be created to create a composition provided a root Node.
fun Node.setContent(
    parent: CompositionContext,
    content: @Composable () -> Unit
): Composition {
    return Composition(NodeApplier(this), parent).apply {
        setContent(content)
    }
}

// assuming we have Node sub-classes like "TextNode" and "GroupNode"
class TextNode : Node() {
    var text: String = ""
    var onClick: () -> Unit = {}
}
class GroupNode : Node()

// Composable equivalents could be created
@Composable fun Text(text: String, onClick: () -> Unit = {}) {
    ComposeNode<TextNode, NodeApplier>(::TextNode) {
        set(text) { this.text = it }
        set(onClick) { this.onClick = it }
    }
}

@Composable fun Group(content: @Composable () -> Unit) {
    ComposeNode<GroupNode, NodeApplier>(::GroupNode, {}, content)
}

// and then a sample tree could be composed:
fun runApp(root: GroupNode, parent: CompositionContext) {
    root.setContent(parent) {
        var count by remember { mutableStateOf(0) }
        Group {
            Text("Count: $count")
            Text("Increment") { count++ }
        }
    }
}
Parameters
@NonNull Applier<@NonNull ?> applier

The Applier instance to be used in the composition.

@NonNull CompositionContext parent

The parent CompositionContext.

ControlledComposition

@TestOnly
@ExperimentalComposeApi
public static final @NonNull ControlledComposition ControlledComposition(
    @NonNull Applier<@NonNull ?> applier,
    @NonNull CompositionContext parent,
    @NonNull CoroutineContext recomposeCoroutineContext
)

getRecomposeCoroutineContext

@ExperimentalComposeApi
public static final @NonNull CoroutineContext getRecomposeCoroutineContext(@NonNull ControlledComposition receiver)

The CoroutineContext that should be used to perform concurrent recompositions of this ControlledComposition when used in an environment supporting concurrent composition.

See Recomposer.runRecomposeConcurrentlyAndApplyChanges as an example of configuring such an environment.