graph TB
contentFrameLayout-->ComposeView-->AndroidComposeView-->ViewLayerContainer
ViewLayerContainer-->ViewLayer1
ViewLayerContainer-->ViewLayer2
ViewLayerContainer-->ViewLayer3
ViewLayerContainer-->ViewLayer...
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
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)
}
}
//AbstractComposeView
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (shouldCreateCompositionOnAttachedToWindow) {
ensureCompositionCreated()//main
}
}
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之后才会被执行闭包中的逻辑
}
internal class AndroidComposeView(context: Context) :
ViewGroup(context), Owner, ViewRootForTest, PositionCalculator {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
invalidateLayoutNodeMeasurement(root)
invalidateLayers(root)
......
onViewTreeOwnersAvailable?.invoke(viewTreeOwners)
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)
}
}
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
}
@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
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
}
}
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)
}
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
}
original.setContent {
....
LaunchedEffect(owner) { owner.keyboardVisibilityEventLoop() }
LaunchedEffect(owner) { owner.boundsUpdatesEventLoop() }
CompositionLocalProvider(LocalInspectionTables provides inspectionTable) {//main
ProvideAndroidCompositionLocals(owner, content)//main
}
}
@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
)
}
@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
)
}
执行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设置下来的闭包
}
@Composable
@OptIn(InternalComposeApi::class)
fun CompositionLocalProvider(vararg values: ProvidedValue<*>, content: @Composable () -> Unit) {
currentComposer.startProviders(values)
content()
currentComposer.endProviders()
}
@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
}
val LocalLifecycleOwner = staticCompositionLocalOf<LifecycleOwner> {
noLocalProvidedFor("LocalLifecycleOwner")
}
fun <T> staticCompositionLocalOf(defaultFactory: () -> T): ProvidableCompositionLocal<T> =
StaticProvidableCompositionLocal(defaultFactory)
fun <T> mutableStateOf(
value: T,
policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
): MutableState<T> = SnapshotMutableStateImpl(value, policy)
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 }
}
}
@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
mutableStateOf(newValue)
}.apply { value = newValue }
@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)
@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
}
}
}
}
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++)]
}
internal class SlotTable : CompositionData, Iterable<CompositionGroup> {
/**
* 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)
}
@Stable
interface State<T> {
val value: T
}