gpt4 book ai didi

What does "composition" exactly mean in jetpack compose(“组合”在喷气背包组合中的确切含义是什么?)

转载 作者:bug小助手 更新时间:2023-10-25 14:03:45 24 4
gpt4 key购买 nike



I'm trying to understand the lifecycle of composable in jetpack compose. It is written in the docs:

我正在尝试理解Jetpack Compose中Composable的生命周期。它写在文件中:



The lifecycle of a composable is defined by the following events: entering the Composition, getting recomposed 0 or more times, and leaving the Composition.



enter image description here


But I don't really get the meaning of entering and leaving the composition. Can we roughly assume that at any moment of time, each composable that is shown on the screen is "in the composition"? Let me explain it with an example from the docs. Consider the following code snippet:

但我真的不明白进入和离开作文的意义。我们能不能粗略地假设,在任何时刻,屏幕上显示的每一首乐曲都是“在乐曲中”?让我用文档中的一个例子来解释一下。请考虑以下代码片段:


@Composable
fun LoginScreen(showError: Boolean) {
if (showError) {
LoginError()
}
LoginInput()
}

@Composable
fun LoginInput() { /* ... */ }

@Composable
fun LoginError() { /* ... */ }

If we pass false to the LoginScreen() is LoginError() out of the composition? and if the state changes and the we pass true to LoginScreen() will LoginError() enters the composition?

如果我们将FALSE传递给LoginScreen(),LoginError()是否不在组合中?如果状态发生变化,并且我们将true传递给LoginScreen(),LoginError()是否会进入组合?


更多回答

Yes and yes. It's a reactive paradigm: the UI will only get recomposed when a state reactively changes.

是的,是的。这是一种反应式范例:只有当状态发生反应性更改时,才会重新组合UI。

IMHO, you have the right idea at a high level. "On the screen" may or may not be accurate depending on the container -- for example, a LazyColumn() might have some nodes that are off-screen but ready to be used when the user starts scrolling. But, if we assume in this case that all the composables from LoginScreen() up to the root do not do this, then enter/leave will generally align with "included in the UI"/"removed from the UI".

我看,你在高层有一个正确的想法。“在屏幕上”可能是准确的,也可能不准确,具体取决于容器--例如,LazyColumn()可能有一些不在屏幕上但在用户开始滚动时可以使用的节点。但是,如果我们在这种情况下假设从LoginScreen()到根的所有可组合元素都没有这样做,那么Enter/Leave通常会与“Included in the UI”/“Remove from the UI”保持一致。

优秀答案推荐

Composition can be described as how nodes of composition tree are structured. They don't have to be necessarily be ui Composables either and they don't have to be drawn on screen to be part of composition.

合成可以描述为合成树的节点是如何构造的。它们也不一定是UI可组合的,也不一定要绘制在屏幕上才能成为组合的一部分。


Your example is correct any conditional statement can change how it will be structured on recomposition.

你的例子是正确的,任何条件语句都可以改变它在重新组合时的结构。


Composition is first time a Composable takes place in composition tree, when any State is read any part of scope of that Composable or whole Composable is updated with new value, based on some other factors it might be updated with same value as well such as SnapshotMutationPolicy or stability of Composable, this is recomposition. When some logic removes a Composable from the tree that Composable leaves composition.

Composable是Composable第一次出现在Composable树中,当读取任何状态时,该Composable或整个Composable的作用域的任何部分都会更新为新值,基于一些其他因素,它可能也会更新为相同的值,例如SnapshotMutationPolicy或Composable的稳定性,这是重新组合。当某个逻辑从树中删除一个Composable时,该Composable将离开Composable。


DisposableEffect function is a non ui Composable that you can track when a Composable enters or exits composition.

DisposableEffect函数是一个非UI Composable,您可以跟踪Composable何时进入或退出合成。


In example below Text and DisposableEffect enters recomposition when counter is 3, stays in composition and Text is recomposed with new counter value until 6 and when it reaches 6 DisposableEffect and Text leaves composition

在下面的示例中,当Counter为3时,Text and DisposableEffect进入重新合成,停留在合成中,文本使用新的计数器值重新合成,直到6,当它达到6时,DisposeEffect和Text离开合成


@Preview
@Composable
private fun UIComposableSample() {

val context = LocalContext.current

var counter by remember { mutableStateOf(0) }

if (counter in 3..5) {
Text("Counter: $counter")

DisposableEffect(Unit){
Toast.makeText(context, "enter recomposition $counter", Toast.LENGTH_SHORT).show()
onDispose {
Toast.makeText(context, "exit recomposition $counter", Toast.LENGTH_SHORT).show()
}
}
}


Button(onClick = { counter++ }) {
Text("Counter: $counter")
}

}

And there is no need to be ui composable for enter, recomposition, leave composition lifecycle either.

而且进入、重新组合、离开组合生命周期也不需要是UI可组合的。


@Composable
private fun NonUIComposableSample() {

val context = LocalContext.current

var counter by remember { mutableStateOf(0) }
var color by remember { mutableStateOf(Color.Red) }

if (counter in 3..5) {
DisposableEffect(Unit) {

Toast.makeText(context, "Entering Composition counter: $counter", Toast.LENGTH_SHORT).show()
color = Color.Yellow
onDispose {
color = Color.Green
Toast.makeText(context, "Exiting Composition counter: $counter", Toast.LENGTH_SHORT).show()
}
}
}

Button(onClick = { counter++ }) {
Text("Counter: $counter", color = color)
}

}

or this one LaunchedEffect enter composition when counter is bigger than 0 and multiply of 3 LaunchedEffect enters composition and Snackbar is shown if you press Button and counter increases Snackbar stops is removed otherwise it waits until it's time out to fade out and leave composition.

或者当计数器大于0且3的倍数时启动生效进入合成效果进入合成并显示Snackbar如果您按下按钮并增加计数器,Snackbar停止将被移除,否则它将等到超时淡出并离开合成。


/**
* Adding this LaunchedEffect to composition when condition is true
* Same goes for if this was remember(LaunchedEffect under the hood uses `remember(key){}`
* when condition is met remember gets added to composition and it gets removed when it's not met
*/
@Composable
private fun LaunchedEffectExample(scaffoldState: ScaffoldState) {

var counter by remember { mutableStateOf(0) }

if (counter > 0 && counter % 3 == 0) {
// `LaunchedEffect` will cancel and re-launch if
// `scaffoldState.snackbarHostState` changes
LaunchedEffect(scaffoldState.snackbarHostState) {
// Show snackbar using a coroutine, when the coroutine is cancelled the
// snackbar will automatically dismiss. This coroutine will cancel whenever
// if statement is false, and only start when statement is true
// (due to the above if-check), or if `scaffoldState.snackbarHostState` changes.
scaffoldState.snackbarHostState.showSnackbar("LaunchedEffect snackbar")
}
}

// This button increase counter that will trigger LaunchedEffect
OutlinedButton(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
onClick = {
counter++
}
) {
Text("LaunchedEffect Counter $counter")
}
}

And for Ui Composable there are three phases alongside with composition which is invoked in depth three trevesal.

而对于Ui Composable,有三个阶段,以及深度调用的三个三叉树的组成。


Compose has three main phases:

合成有三个主要阶段:


Composition: What UI to show. Compose runs composable functions and creates a description of your UI.

构图:显示什么UI。Compose运行可组合的函数并创建对您的UI的描述。


Layout: Where to place UI. This phase consists of two steps: measurement and placement. Layout elements measure and place themselves and any child elements in 2D coordinates, for each node in the layout tree.

布局:放置UI的位置。这一阶段包括两个步骤:测量和放置。对于布局树中的每个节点,布局元素测量并放置自身以及2D坐标中的任何子元素。


Drawing: How it renders. UI elements draw into a Canvas, usually a device screen.

绘画:它是如何渲染的。UI元素绘制到画布中,通常是设备屏幕。


Even if a Composasble has 0.dp size or not drawn on screen(if you assign Modifier.drawWithContent{} not draw content), or even if it's not or placed( if you don't call place in placement scope) it still might be part of composition tree and means that it's composed.

即使Composasble有0.dp大小或没有在屏幕上绘制(如果您指定Modifier.DrawWithContent{}不绘制内容),或者即使它没有或放置(如果您不在放置范围内调用Place),它仍然可能是合成树的一部分,并且意味着它是合成的。


Let's say you have ui tree like the one below

假设您有如下所示的UI树


Column() {
println("Parent Scope")
Column() {
println("Child1 Outer Scope")
Text("Child1 Outer Content")
Column() {
println("Child1 Inner Scope")
Text("Child1 Inner Content")
}
}

Column() {
println("Child2 Scope")
Text("Child2 Content")
}
}

Composition creates nodes such as like the one below

合成会创建如下所示的节点


        Parent Layout
/ \
/ \
/ \
/ \
Child1 Outer Child2
|
Child1 Inner

Prints

版画


 I  Parent Scope
I Child1 Outer Scope
I Child1 Inner Scope
I Child2 Scope

This is the order of Composition happening starts tree from left goes until inner child, goes to next branch and so on. Then in Layout phase child1 Inner gets measured first, Child1 Outer, Child2 then Parent gets measured with info from child and they get place same order Composition happens.

这是作文发生的顺序,从左开始树到内子,再到下一个树枝,依此类推。然后在布局阶段,首先测量孩子1内部、孩子1外部、孩子2,然后用孩子的信息测量父母,它们得到的位置相同的顺序组成发生。


If the Composables are like this

如果合成物是这样的


            Parent Composable
/ | \
/ | \
/ | \
/ | \
/ | \
C1 Outer C2Outer C3outer
/ | \
/ / \ \
/ / \ \
/ / \ \
C1 Middle C2 InnerA C2 InnerB C3 Inner
|
C1 Inner

Prints:

I Paren Scope
I Child1 Outer Scope
I Child1 Middle Scope
I Child1 Inner Scope
I Child2 Outer Scope
I Child2 InnerA Scope
I Child2 InnerB Scope
I Child3 Outer Scope
I Child3 Inner Scope

This is how they are composed in composition. On recomposition based on which composable reads a value only it or one its parent or entire composition tree might get recomposed.

这就是它们在构图中的组成方式。在重新组合时,Composable只读取值,或者它的父树或整个合成树可能会被重新组合。


https://stackoverflow.com/a/73181512/5457853

Https://stackoverflow.com/a/73181512/5457853


https://stackoverflow.com/a/73181512/5457853

Https://stackoverflow.com/a/73181512/5457853


https://stackoverflow.com/a/77007725/5457853

Https://stackoverflow.com/a/77007725/5457853



In Jetpack Compose, understanding the lifecycle of composables and when they are "in the composition" can be a bit nuanced, so let's clarify it: 1. Composition: A composition is essentially a tree of composables that represents your UI. When you build a Composable function (like LoginScreen), you are creating a node in this tree. Each composable function defines a part of your UI, and the entire UI is a composition of these composable functions. 2. Entering and Leaving the Composition: The concept of "entering" and "leaving" the composition usually refers to whether a composable function is currently part of the composition tree or not. Now, let's look at your example:

在Jetpack Compose中,理解可组合组件的生命周期以及它们何时“在组合中”可能会有一些细微差别,因此让我们澄清一下:1.组合:组合本质上是代表用户界面的组合组件树。当您构建可组合函数(如LoginScreen)时,您在此树中创建了一个节点。每个可组合函数定义了用户界面的一部分,而整个用户界面是这些可组合函数的组合。2.进入和离开组合:进入和离开组合的概念通常是指可组合函数当前是否属于组合树的一部分。现在,让我们看一下您的示例:


    @Composable
fun LoginScreen(showError: Boolean) {
if (showError) {
LoginError()
}
LoginInput()
}

@Composable
fun LoginInput() { /* ... */ }

@Composable
fun LoginError() { /* ... */ }

In this example, LoginScreen is the root of a composition. It calls LoginInput and conditionally calls LoginError based on the value of showError. - If you pass false to LoginScreen(), the LoginError() composable will not be part of the composition. It won't be included in the composition tree, and it won't be displayed on the screen. - If you pass true to LoginScreen(), the LoginError() composable will be included in the composition. It will enter the composition tree, and its UI will be displayed on the screen. So, yes, you can roughly assume that at any moment, each composable that is shown on the screen is "in the composition." When you change the state and re-compose your UI (e.g., by changing showError from false to true), Jetpack Compose will automatically update the composition to reflect the changes in your state, which may involve adding or removing composables from the composition tree as needed.

在本例中,LoginScreen是合成的根。它调用LoginInput,并根据showError的值有条件地调用LoginError。-如果将False传递给LoginScreen(),则可合成的LoginError()将不会是合成的一部分。它不会包含在合成树中,也不会显示在屏幕上。-如果将true传递给LoginScreen(),则可合成的LoginError()将包含在合成中。它将进入合成树,其UI将显示在屏幕上。所以,是的,你可以粗略地假设,在任何时刻,屏幕上显示的每个组成元素都是“在组成中”。当您更改状态并重新合成您的UI时(例如,通过将showError从False更改为True),Jetpack Compose将自动更新合成以反映您状态中的更改,这可能涉及根据需要在合成树中添加或删除可合成内容。


更多回答

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com