Mr.*_*hie 4 android android-jetpack android-jetpack-compose android-jetpack-compose-text
我正在使用新的撰写库在 android 中实现OutstandingTextField 。但奇怪的是,文本字段中的输入数据没有更新。
于是我搜索了一下,发现了一个叫做Recomposition in android compose的主题。我没有完全明白。
不过,我确实找到了解决方案:
@Composable
fun HelloContent(){
var name:String by remember {mutableStateOf("")}
OutlinedTextField(
value = name,
onValueChange = {name = it},
label = {Text("Name")}
)
}
Run Code Online (Sandbox Code Playgroud)
我还阅读了jetpack compose 中的状态概念。但我没能完全理解它。
有人可以用简单的话解释一下吗?
Ric*_*per 20
基本上,重组只是 Compose 中的一个事件,其中相关的可组合项被重新执行。在声明性编码(Compose 的基础)中,我们将 UI 编写为函数(或更常见的是方法)。现在,重组基本上是一个事件,其中通过再次执行所述可组合“函数”的主体来重新发出UI。这就是重组的核心。现在讨论它何时被触发。
好的,为了触发重组,我们需要一种特殊类型的变量。这种类型内置于 compose 中,专门设计用于让它知道何时重新组合。而提到的类型是MutableState
. 顾名思义,就是State,可以Mutate,即改变;各不相同。
那么,我们有一个 类型的变量MutableState
,下一步是什么?你猜怎么着,你没有类型变量MutableState
,因为我没有教你如何创建一个变量!在 Compose 中最常见的分配是助手mutableStateOf
。这是一个预定义的方法MutableState
,实际上返回类型为 的值MutableState<T>
。T
这里是State的类型,见下文
var a = mutableStateOf(999)
上面,如您所见,999 是一个Int
,因此,mutableStateOf
这里将返回一个MutableState<Int>
类型值。很容易。
现在,我们有了一个MutableState<Int>
值,但老实说,这有点难看。每次需要从 中获取值时MutableState<T>
,您都需要引用一个方便命名的属性.value
。
因此,要从上述内容中获取 999 var a
,您需要致电a.value
。现在,这对于一两个地方使用来说没问题,但每次调用它看起来都很混乱。这就是Kotlin 属性委托的用武之地(我知道,我不需要将最后两个词大写)。我们使用by
关键字从状态中检索值,并将其分配给我们的变量 - 这就是您应该关心的。
因此,var a by mutableStateOf(999)
实际上会返回999
type Int
,而不是 type MutableState<Int>
,但最精彩的部分是 Compose 仍然知道该变量a
是 State-Holder。所以基本上mutableStateOf
可以被认为是一个注册计数器,你只需要通过它一次,就可以在 的列表中注册State-Holders
。从那时起,每当其中一个国家持有者的价值发生变化时,就会触发重组。这是粗略的想法,但让我们来谈谈技术吧;现在讨论“如何”重组。
要触发重组,您需要确保两件事:
有了佩里,一切都会变得更好示例:-
var a by mutableStateOf(999)
情况 1:可组合项接收a
参数值 ,MyComposable(a)
然后运行a = 0
,结果 1:触发重组
情况二:这个变量声明a
实际上是在可组合本身内部,然后我运行a = 12344
结果二:触发重组
案例 III:我重复案例 1 和 II,但使用不同的变量,如下所示:var b = 999
结果 III:未触发重组;原因:b
不是国家持有者
太好了,我们现在已经掌握了基础知识。那么,这是本次讲座的最后一个阶段。
记住!!
你看,当我说在重组期间,整个 Composable 被重新执行,我的意思是整个 Composable 被重新执行,也就是说,每一行和每一个赋值都被重新执行,没有例外。你发现这有什么问题了吗?让我演示一下
假设我想要一个Text
可组合项显示一个数字,并在单击它时增加该数字。
我可以实现像这样简单的东西
@Composable
fun CountingText(){
var n = mutableStateOf(0) //Starts at 0
Text(
value = n.toString(), //The Composable only accepts strings, while n is of Int type
modifier = Modifier
.clickable { n++ }
)
}
Run Code Online (Sandbox Code Playgroud)
好的,这就是我们认为可行的实现。如果您不熟悉Modifier
s,请暂时保留它并相信我,clickable
当您实际单击 时,它只会触发大括号内的代码Text
。现在,让我们想象一下这将如何执行。
首先,Compose 会将变量注册n
为状态持有者。然后它将渲染Text
初始值为0
的Composable n
。
现在,它Text
实际上是click
编辑过的。里面的块clicakble
将被执行,在本例中只是n++
,这将更新 的值n
。Compose 看到 的值n
已更新,并遍历状态持有者列表。Compose 发现n
确实是状态持有者,然后决定触发重组。现在,整个 Composable 的读取值n
将被重新组合。在这种情况下,该可组合项是 CountingText
因为Text
它的内部正在读取(以显示它)的值n
。因此,CountingText
将被“重新执行”。让我们来看看这里的重新执行。
可组合项中的第一行,
var n = mutableStateOf(0)
n
变成0。
下一行:-
Text(
value = n.toString(), //Just displays 0
modifier = Modifier
.clickable { n++ } //Just tells it to increase n upon click
)
Run Code Online (Sandbox Code Playgroud)
所以你看,这里的问题是,在重新执行时,它n
是完全从头开始创建的,就好像它以前从未存在过一样。它已从可组合项的内存中删除。为了解决这个问题,我们需要 Composable to remember
n
. 这样,Compose 就知道这是一个状态持有者,并且拥有一个需要在重组时重新分配给它的值。所以,这是更新后的第一行(其余部分相同,只是更新了初始化)
var n by remember { mutableStateOf(0) }
现在,在第一次执行时,n
将收到 0,因为它实际上是第一次n
创建。感谢remember
,n
现在可以访问 的Composable
内存,因此将存储在内存中以供将来使用。
因此,在重组过程中,会发生这样的情况 - 当执行器 (???) 到达分配的行时n
,
var n by remember { mutableStateOf(0) }
remember
实际上充当看门人的角色,不允许执行者进入其中包含的块。相反,它会将之前记住的值传递给它并要求它继续前进。由于当用户单击 时Text
,它已经将 的值增加到n
1,该值保留在内存中,因此现在可以按预期工作。
这与您的问题的情况相同TextField
。该字段最初读取一个空值,每次用户键入字母时该值都会更新,触发重组并最终在屏幕上显示正确的值。
它能变得足够简单吗?让我知道我花了半个小时打字。
归档时间: |
|
查看次数: |
6982 次 |
最近记录: |