ComposeSource

View层次结构

graph TB
contentFrameLayout-->ComposeView-->AndroidComposeView-->ViewLayerContainer
ViewLayerContainer-->ViewLayer1
ViewLayerContainer-->ViewLayer2
ViewLayerContainer-->ViewLayer3
ViewLayerContainer-->ViewLayer...

View类继承结构

classDiagram
class ComposeView {
 -val content
}

class AndroidComposeView {
+onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
}

class OwnedLayer {
 <<interface>>
 +resize(size: IntSize)
 +drawLayer(canvas: Canvas)
 +updateDisplayList()
 +invalidate()
}
class GraphicLayerInfo {
 <<interface>
 +layerId: Long
}

View<|--ViewGroup

ViewGroup<|--AbstractComposeView
AbstractComposeView<|--ComposeView

ViewGroup<|--AndroidComposeView
ViewGroup<|--ViewLayerContainer

View<|--ViewLayer
OwnedLayer<|--ViewLayer
OwnedLayer<|--RenderNodeLayer
GraphicLayerInfo<|--OwnedLayer

图解

sequenceDiagram

ComposeView->>ComposeView: onAttachedToWindow
activate ComposeView

ComposeView->>ComposeView: ensureCompositionCreated
activate ComposeView
deactivate ComposeView

ComposeView->>ComposeView: setOnViewTreeOwnersAvailable{闭包}
activate ComposeView
Note right of ComposeView: AndroidComposeView.onAttachedToWindow后执行闭包
deactivate ComposeView


AndroidComposeView->>AndroidComposeView: onAttachedToWindow

AndroidComposeView->>CompositionImpl:setContent

CompositionImpl->>ComposerImpl: composeContent

ComposerImpl->>ComposableLambdaImpl: invoke

ComposableLambdaImpl->>ComposableLambdaImpl: c.startRestartGroup
ComposableLambdaImpl->>ComposableLambdaImpl: (_block as (c: Composer, changed: Int) -> Any?)

ComposableLambdaImpl->>ComposableLambdaImpl: c.endRestartGroup().updateScope

ComposableLambdaImpl->>ComposeView: Content()

ComposeView->>ComposeView:content.value?.invoke()

Note right of ComposeView: Activity调用setContent设置下来的闭包

deactivate ComposeView

setContent

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val appContainer = (application as JetnewsApplication).container
        setContent {//main
            JetnewsApp(appContainer, navigationViewModel)
        }
    }
}
public fun ComponentActivity.setContent(
    parent: CompositionContext? = null,
    content: @Composable () -> Unit
) {
    val existingComposeView = window.decorView
        .findViewById<ViewGroup>(android.R.id.content)
        .getChildAt(0) as? ComposeView

    if (existingComposeView != null) with(existingComposeView) {
        setParentCompositionContext(parent)
        setContent(content)
    } else ComposeView(this).apply {
        // Set content and parent **before** setContentView
        // to have ComposeView create the composition on attach
        setParentCompositionContext(parent)
        setContent(content)
        setContentView(this, DefaultActivityContentLayoutParams)
    }
}

ComposeView

//AbstractComposeView
override fun onAttachedToWindow() {
    super.onAttachedToWindow()

    if (shouldCreateCompositionOnAttachedToWindow) {
        ensureCompositionCreated()//main
    }
}

AbstractComposeView.ensureCompositionCreated

abstract class AbstractComposeView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ViewGroup(context, attrs, defStyleAttr) {
    
@Suppress("DEPRECATION") // Still using ViewGroup.setContent for now
private fun ensureCompositionCreated() {
    if (composition == null) {
        try {
            creatingComposition = true
            composition = setContent(
                parentContext ?: findViewTreeCompositionContext() ?: windowRecomposer
            ) {
                Content()
            }
        } finally {
            creatingComposition = false
        }
    }
}
internal fun ViewGroup.setContent(
    parent: CompositionContext,
    content: @Composable () -> Unit
): Composition {
    GlobalSnapshotManager.ensureStarted()
    val composeView =
        if (childCount > 0) {
            getChildAt(0) as? AndroidComposeView
        } else {
            removeAllViews(); null
        } ?: AndroidComposeView(context).also { addView(it.view, DefaultLayoutParams) }
    return doSetContent(composeView, parent, content)//main
}
@OptIn(InternalComposeApi::class)
private fun doSetContent(
    owner: AndroidComposeView,
    parent: CompositionContext,
    content: @Composable () -> Unit
): Composition {
    if (inspectionWanted(owner)) {
        owner.setTag(
            R.id.inspection_slot_table_set,
            Collections.newSetFromMap(WeakHashMap<CompositionData, Boolean>())
        )
        enableDebugInspectorInfo()
    }
    val original = Composition(UiApplier(owner.root), parent)
    val wrapped = owner.view.getTag(R.id.wrapped_composition_tag)
        as? WrappedComposition
        ?: WrappedComposition(owner, original).also {
            owner.view.setTag(R.id.wrapped_composition_tag, it)
        }
    wrapped.setContent(content)
    return wrapped
}
//WrappedComposition
@OptIn(InternalComposeApi::class)
override fun setContent(content: @Composable () -> Unit) {
    owner.setOnViewTreeOwnersAvailable {
        ......//AndroidComposeView.onAttachedToWindow之后才会被执行闭包中的逻辑
    }

AndroidComposeView

AndroidComposeView.onAttachedToWindow

internal class AndroidComposeView(context: Context) :
    ViewGroup(context), Owner, ViewRootForTest, PositionCalculator {
        
    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        invalidateLayoutNodeMeasurement(root)
        invalidateLayers(root)
        ......
        onViewTreeOwnersAvailable?.invoke(viewTreeOwners)

WrappedComposition.setContent

private class WrappedComposition(
    val owner: AndroidComposeView,
    val original: Composition
) : Composition, LifecycleEventObserver {
    
    @OptIn(InternalComposeApi::class)
    override fun setContent(content: @Composable () -> Unit) {
            owner.setOnViewTreeOwnersAvailable {
                if (!disposed) {
                val lifecycle = it.lifecycleOwner.lifecycle
                lastContent = content//important,为ensureCompositionCreated()时setContent时配置的闭包Content()
                if (addedToLifecycle == null) {
                    addedToLifecycle = lifecycle
                    // this will call ON_CREATE synchronously if we already created
                    lifecycle.addObserver(this)//main
                    
//WrappedComposition
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
    if (event == Lifecycle.Event.ON_DESTROY) {
        dispose()
    } else if (event == Lifecycle.Event.ON_CREATE) {
        if (!disposed) {
            setContent(lastContent)//main
        }
    }
}
@OptIn(InternalComposeApi::class)
override fun setContent(content: @Composable () -> Unit) {
    owner.setOnViewTreeOwnersAvailable {
         ......
            else if (lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
                    original.setContent {//main

                        @Suppress("UNCHECKED_CAST")
                        val inspectionTable =
                            owner.getTag(R.id.inspection_slot_table_set) as?
                                MutableSet<CompositionData>
                                ?: (owner.parent as? View)?.getTag(R.id.inspection_slot_table_set)
                                    as? MutableSet<CompositionData>
                        if (inspectionTable != null) {
                            @OptIn(InternalComposeApi::class)
                            inspectionTable.add(currentComposer.compositionData)
                            currentComposer.collectParameterInformation()
                        }

                        LaunchedEffect(owner) { owner.keyboardVisibilityEventLoop() }
                        LaunchedEffect(owner) { owner.boundsUpdatesEventLoop() }

                        CompositionLocalProvider(LocalInspectionTables provides inspectionTable) {
                            ProvideAndroidCompositionLocals(owner, content)
                        }
                    }

CompositionImpl.setContent

internal class CompositionImpl(
    private val parent: CompositionContext,
    applier: Applier<*>,
    private val onDispose: (() -> Unit)? = null,
    recomposeContext: CoroutineContext? = null
) : ControlledComposition {

    override fun setContent(content: @Composable () -> Unit) {
      check(!disposed) { "The composition is disposed" }
      this.composable = content
      parent.composeInitial(this, composable)//main
    }

Recomposer.composeInitial

@OptIn(InternalComposeApi::class)
class Recomposer(
    effectCoroutineContext: CoroutineContext
) : CompositionContext() {
    
internal override fun composeInitial(
    composition: ControlledComposition,
    content: @Composable () -> Unit
) {
    val composerWasComposing = composition.isComposing
    composing(composition, null) {
        composition.composeContent(content)//main
    }

CompositionImpl.composeContent

//CompositionImpl
    private val composer: ComposerImpl = ComposerImpl(applier, parent, this).also {
        parent.registerComposer(it)
    }

override fun composeContent(content: @Composable () -> Unit) {
    // TODO: This should raise a signal to any currently running recompose calls
    // to halt and return
    synchronized(lock) {
        drainPendingModificationsForCompositionLocked()
        composer.composeContent(content)//main
    }
}

ComposerImpl.composeContent

internal class ComposerImpl(
    /**
     * An adapter that applies changes to the tree using the Applier abstraction.
     */
    override val applier: Applier<*>,

    /**
     * Parent of this composition; a [Recomposer] for root-level compositions.
     */
    private val parentContext: CompositionContext,

    /**
     * The composition that owns this composer
     */
    override val composition: ControlledComposition
) : Composer {
    
internal fun composeContent(content: @Composable () -> Unit) {
    check(changes.isEmpty()) { "Expected applyChanges() to have been called" }
    trace("Compose:recompose") {
        var complete = false
        val wasComposing = isComposing
        isComposing = true
        try {
            startRoot()
            startGroup(invocationKey, invocation)
            invokeComposable(this, content)//main
            endGroup()
            endRoot()
            complete = true
        } finally {
            isComposing = wasComposing
            if (!complete) abortRoot()
        }
    }
}
    
internal fun invokeComposable(composer: Composer, composable: @Composable () -> Unit) {
    @Suppress("UNCHECKED_CAST")
    val realFn = composable as Function2<Composer, Int, Unit>
    realFn(composer, 1)
}

ComposableLambdaImpl.invoke

internal class ComposableLambdaImpl(
    val key: Int,
    private val tracked: Boolean,
    private val sourceInformation: String?
) : ComposableLambda {
    
override operator fun invoke(c: Composer, changed: Int): Any? {
    val c = c.startRestartGroup(key, sourceInformation)
    trackRead(c)
    val dirty = changed or if (c.changed(this)) differentBits(0) else sameBits(0)
    val result = (_block as (c: Composer, changed: Int) -> Any?)(c, dirty)//main
    c.endRestartGroup()?.updateScope(this as (Composer, Int) -> Unit)
    return result
}

CompositionLocalProvider

original.setContent {

    ....
    LaunchedEffect(owner) { owner.keyboardVisibilityEventLoop() }
    LaunchedEffect(owner) { owner.boundsUpdatesEventLoop() }

    CompositionLocalProvider(LocalInspectionTables provides inspectionTable) {//main
        ProvideAndroidCompositionLocals(owner, content)//main
    }
}

ProvideAndroidCompositionLocals

@Composable
@OptIn(ExperimentalComposeUiApi::class)
internal fun ProvideAndroidCompositionLocals(
    owner: AndroidComposeView,
    content: @Composable () -> Unit
) {
    
    val view = owner
    val context = view.context
    ......
    CompositionLocalProvider(//main
        LocalConfiguration provides configuration,
        LocalContext provides context,
        LocalLifecycleOwner provides viewTreeOwners.lifecycleOwner,
        LocalSavedStateRegistryOwner provides viewTreeOwners.savedStateRegistryOwner,
        LocalSaveableStateRegistry provides saveableStateRegistry,
        LocalView provides owner.view
    ) {
        ProvideCommonCompositionLocals(//main
            owner = owner,
            uriHandler = uriHandler,
            content = content
        )
    }
    

ProvideCommonCompositionLocals

@ExperimentalComposeUiApi
@Composable
internal fun ProvideCommonCompositionLocals(
    owner: Owner,
    uriHandler: UriHandler,
    content: @Composable () -> Unit
) {
    CompositionLocalProvider(//main
        LocalAccessibilityManager provides owner.accessibilityManager,
        LocalAutofill provides owner.autofill,
        LocalAutofillTree provides owner.autofillTree,
        LocalClipboardManager provides owner.clipboardManager,
        LocalDensity provides owner.density,
        LocalFocusManager provides owner.focusManager,
        LocalFontLoader provides owner.fontLoader,
        LocalHapticFeedback provides owner.hapticFeedBack,
        LocalLayoutDirection provides owner.layoutDirection,
        LocalTextInputService provides owner.textInputService,
        LocalTextToolbar provides owner.textToolbar,
        LocalUriHandler provides uriHandler,
        LocalViewConfiguration provides owner.viewConfiguration,
        LocalWindowInfo provides owner.windowInfo,
        content = content//main
    )
}

ComposeView.Content

执行ensureCompositionCreated()时配置的闭包回调Content()

class ComposeView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AbstractComposeView(context, attrs, defStyleAttr) {
    
@Composable
override fun Content() {
    content.value?.invoke()//value类型为ComposableLambdaImpl,也就是Activity调用setContent设置下来的闭包
}

其他

CompositionLocalProvider

@Composable
@OptIn(InternalComposeApi::class)
fun CompositionLocalProvider(vararg values: ProvidedValue<*>, content: @Composable () -> Unit) {
    currentComposer.startProviders(values)
    content()
    currentComposer.endProviders()
}

observeAsState

@Composable
fun <T> LiveData<T>.observeAsState(): State<T?> = observeAsState(value)

@Composable
fun <R, T : R> LiveData<T>.observeAsState(initial: R): State<R> {
    val lifecycleOwner = LocalLifecycleOwner.current
    val state = remember { mutableStateOf(initial) }
    DisposableEffect(this, lifecycleOwner) {
        val observer = Observer<T> { state.value = it }
        observe(lifecycleOwner, observer)
        onDispose { removeObserver(observer) }
    }
    return state
}

LocalLifecycleOwner

val LocalLifecycleOwner = staticCompositionLocalOf<LifecycleOwner> {
    noLocalProvidedFor("LocalLifecycleOwner")
}

staticCompositionLocalOf

fun <T> staticCompositionLocalOf(defaultFactory: () -> T): ProvidableCompositionLocal<T> =
    StaticProvidableCompositionLocal(defaultFactory)

mutableStateOf

fun <T> mutableStateOf(
    value: T,
    policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
): MutableState<T> = SnapshotMutableStateImpl(value, policy)

SnapshotMutableStateImpl

private class SnapshotMutableStateImpl<T>(
    value: T,
    override val policy: SnapshotMutationPolicy<T>
) : StateObject, SnapshotMutableState<T> {
    @Suppress("UNCHECKED_CAST")
    override var value: T
        get() = next.readable(this).value
        set(value) = next.withCurrent {
            if (!policy.equivalent(it.value, value)) {
                next.writable(this) { this.value = value }
            }
        }

remember

rememberUpdatedState

@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
    mutableStateOf(newValue)
}.apply { value = newValue }

remember

@OptIn(ComposeCompilerApi::class)
@Composable
inline fun <T> remember(calculation: @DisallowComposableCalls () -> T): T =
    currentComposer.cache(false, calculation)//composerImpl实例
@ComposeCompilerApi
inline fun <T> Composer.cache(invalid: Boolean, block: () -> T): T {
    @Suppress("UNCHECKED_CAST")
    return rememberedValue().let {
        if (invalid || it === Composer.Empty) {//invalid或没有cache数据时,走block初始化value并记住
            val value = block()
            updateRememberedValue(value)
            value
        } else it
    } as T
}
//ComposerImpl
override fun rememberedValue(): Any? = nextSlot()
@PublishedApi
@OptIn(InternalComposeApi::class)
internal fun nextSlot(): Any? = if (inserting) {
    validateNodeNotExpected()
    Composer.Empty
} else reader.next()
//composerImpl
override fun updateRememberedValue(value: Any?) = updateValue(value)

ComposerImpl.updateValue

@PublishedApi
@OptIn(InternalComposeApi::class)
internal fun updateValue(value: Any?) {
    if (inserting) {
        writer.update(value)//main
        if (value is RememberObserver) {
            record { _, _, rememberManager -> rememberManager.remembering(value) }
        }
    } else {
        val groupSlotIndex = reader.groupSlotIndex - 1
        recordSlotTableOperation(forParent = true) { _, slots, rememberManager ->
            if (value is RememberObserver) {
                abandonSet.add(value)
                rememberManager.remembering(value)
            }
            when (val previous = slots.set(groupSlotIndex, value)) {
                is RememberObserver ->
                    rememberManager.forgetting(previous)
                is RecomposeScopeImpl -> {
                    if (previous.composer != null) {
                        previous.composer = null
                        pendingInvalidScopes = true
                    }
                }
            }
        }

SlotWriter图解

图片

图片

internal class SlotWriter(
    /**
     * The [SlotTable] for whom this is writer.
     */
    internal val table: SlotTable
) {
    /**
     * The gap buffer for groups. This might change as groups are inserted and the array needs to
     * be expanded to account groups. The current valid groups occupy 0 until [groupGapStart]
     * followed [groupGapStart] + [groupGapLen] until groups.size where [groupGapStart]
     * until [groupGapStart] + [groupGapLen] is the gap.
     */
    private var groups: IntArray = table.groups
    /**
     * The gap buffer for the slots. This might change as slots are inserted an and the array
     * needs to be expanded to account for the new slots. The current valid slots occupy 0 until
     * [slotsGapStart] and [slotsGapStart] + [slotsGapLen] until slots.size where [slotsGapStart]
     * until [slotsGapStart] + [slotsGapLen] is the gap.
     */
    private var slots: Array<Any?> = table.slots
    
   private var slotsGapLen: Int = slots.size - table.slotsSize
   private fun dataIndexToDataAddress(dataIndex: Int) =
        if (dataIndex < slotsGapStart) dataIndex else dataIndex + slotsGapLen
fun update(value: Any?): Any? {
    val result = skip()
    set(value)
    return result
}
fun skip(): Any? {
    if (insertCount > 0) {
        insertSlots(1, parent)
    }
    return slots[dataIndexToDataAddress(currentSlot++)]
}

SlotTable

internal class SlotTable : CompositionData, Iterable<CompositionGroup> {

Anchor

/**
 * An [Anchor] tracks a groups as its index changes due to other groups being inserted and
 * removed before it. If the group the [Anchor] is tracking is removed, directly or indirectly,
 * [valid] will return false. The current index of the group can be determined by passing either
 * the [SlotTable] or [SlotWriter] to [toIndexFor]. If a [SlotWriter] is active, it must be used
 * instead of the [SlotTable] as the anchor index could have shifted due to operations performed
 * on the writer.
 */
internal class Anchor(loc: Int) {
    internal var location: Int = loc
    val valid get() = location != Int.MIN_VALUE
    fun toIndexFor(slots: SlotTable) = slots.anchorIndex(this)
    fun toIndexFor(writer: SlotWriter) = writer.anchorIndex(this)
}

State

@Stable
interface State<T> {
    val value: T
}