gpt4 book ai didi

android - Jetpack Compose 实际上适用于类而不是函数?

转载 作者:行者123 更新时间:2023-12-05 03:24:18 28 4
gpt4 key购买 nike

当您声明@Composable Function 时,您实际上是在声明一个类

  • 您在该函数中声明的每个变量实际上充当类属性

  • 您在该函数内声明的每个事件(如 onClick)实际上充当类方法

这就是为什么在 onClick 之间会记住变量值的原因。每次单击都会执行增加类属性的类方法。这可以在控制台中看到,因为此时我们没有更新 UI(没有发生重组)。

因此,Jetpack Compose 的工作方式和解释方式完全具有误导性。据解释,您使用函数,但在后台它们的行为类似于类,以便使它们有状态。因此,他们没有使用像类这样的众所周知的结构来实现 UI View ,而是使用在幕后有很多魔法的函数,使它们像类一样表现得有状态。我错过了什么吗?

//======================================================================
// MAIN ACTIVITY
//======================================================================
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Column {
MyComposable("Object1") //Create Object of Class MyComposable
MyComposable("Object2") //Create Object of Class MyComposable
}
}
}
}

//======================================================================
// MY COMPOSABLE
//======================================================================
// Instead of Function you are actually creating Object behind the scene
// So this Function actually works as Constructor for MyComposable Class
@Composable
fun MyComposable(name: String) { //CLASS

//CLASS PROPERTY
var myProperty = name

//CLASS METHOD: onClick
Text(text = myProperty, modifier = Modifier.clickable(onClick = {
myProperty += " clicked"
println(myProperty)
}))

}

控制台

Object1 clicked
Object1 clicked clicked

Object2 clicked

最佳答案


来自本书Jetpack Compose Internals

任何被注解为@Composable 的函数都会被 Jetpack Compose 编译器翻译成一个函数,该函数隐式地将一个 Composer 上下文的实例作为参数传递给它,并且还将该实例转发给它的 Composable 子代。我们可以将其视为运行时和开发人员可以保持不可知的注入(inject)隐式参数。它看起来像这样。假设我们有以下可组合项来表示铭牌:

NamePlate.kt

@Composable
fun NamePlate(name:String,lastname:String){
Column(modifier = Modifier.padding(16.dp)) {
Text(text = name)
Text(text = lastname, style = MaterialTheme.typography.subtitle1)
}
}

编译器将为树上的每个可组合调用添加一个隐式可组合参数,并为每个可组合的开始和结束添加一些标记。请注意,以下代码已简化,但结果将如下所示:

fun NamePlate(name:String,lastname:String, $composer:Composer<*>){
$composer.start(123)
Column(modifier = Modifier.padding(16.dp), $composer) {
Text(text = name, $composer
Text(text = lastname, style = MaterialTheme.typography.subtitle1, $composer)
$composer.end()
}
}

在您展示的示例中,您基本上使用的是 closure通过引用其外部上下文来保持本地状态。

您不需要 Compose 来实现这一点, Vanilla Kotlin(或 Java)的行为如下:

fun main() {
val createCounter = {
var x = 0
{
x += 1
"x=$x"
}
}
val nextValue = createCounter()

print(nextValue()) // x=1
print(nextValue()) // x=2
print(nextValue()) // x=3
}

虽然该语言允许您这样做,但您实际上打破了 Compose 的先决条件之一,即您的函数应该是纯函数,或者至少没有不受控制的副作用。

Compose 函数的作用类似于访问者模式,在该模式中,composer 被传递到树中,每个函数都发送给该 composer。由于没有副作用,compose 编译器可以假设如果参数的值没有改变,那么函数发出的内容也不会改变,因此不需要重新组合(函数的重新运行)。

关于android - Jetpack Compose 实际上适用于类而不是函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72318231/

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