recomposição是JetPack组成功能的基本步骤。如果您不知道它是什么,基本上,它是通过应用状态更新重新设计屏幕的阶段。
换句话说,每次我们在屏幕上都有一些新的东西,无论是文本字段,动物,颜色变化等的编辑。
每次发生koude0更新时都会发生建议,或更准确,源自State
并允许更新值发生重新组件的Abiaqian2。 /p>
尽管看起来很简单,但是在使用此行为开发应用程序时,我们需要小心避免某些陷阱,无论是不必要的,甚至是无限的循环!
要进行简单的演示,我们可以添加一名会计师并在屏幕上显示:
var counter = 0
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PlaygroundTheme {
Surface(
Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
var text by remember {
mutableStateOf("")
}
Column {
Text(text = "${counter++}")
TextField(value = text, onValueChange = {
text = it
})
}
}
}
}
}
}
请参阅仅写“ Alex Felipe”并删除所有字母,有22个重新组件!
尽管它有很大的数量,但通常会发生更多的重新组件,毕竟,屏幕可以执行多个更新,具有动物,懒惰的结构等。但是,有比我们应有的重新组成!让我们开始探索一点,例如试图寻求信息并在组成中更新状态。
模拟不必要的重新分配
为了举例说明,我将创建一种模拟所有常规搜索的方式:
class User(
val id: Long,
val name: String
)
fun findAllUsers() = flow {
delay(Random.nextLong(100, 500))
emit(listOf(User(1, "alex")))
}
即使是一种返回“享受列表”的方式(每次创建新列表的细化时),也是一个非常有趣的情况,可以观察到重新分配不必要!
delay()
的周期为100至500毫秒,是在测试过程中促进结果的视图。 Engy,在组合中,我们可以提出列表的竞赛:
val users by findAllUsers().collectAsState(initial = emptyList())
Column {
Text(text = "${counter++}")
for (user in users) {
Column {
Text(text = user.id.toString())
Text(text = user.name)
}
}
}
一个好奇的结果...您同意吗?尽管屏幕“没有添加新的常规”,但重新组件的发生通常是徒劳的,通常趋向于无穷大...
了解陷阱的危险
重要的是要注意,这是一个受到一定延迟的受控实现,但现在可以想象,在情况下,搜索信息来自消耗设备,Internet等功能的集成。我们将创建一个效率低下的解决方案,以损害应用程序的质量,体验并可以使产品更昂贵!毕竟,有某些服务,例如REST API,这些服务收费用于访问...
换句话说,由于重新组件的过量循环,所有进行状态修饰的耳朵都必须在组成的组成之外进行!现在是一个很好的问题:
“我如何执行不受重新组件影响的方式?”
使用副作用API
要执行它不受重新组件的影响,我们需要使用APIs de Side-effect。基本上,此API提供了几种工具,使您可以执行修改状态并不受重新组件影响的状态。
非常常见的可能性之一是LaunchedEffect()
,它是一个不发行视觉元素并通过lambda表达式运行coroutine的组合:
var users by remember {
mutableStateOf(emptyList<User>())
}
LaunchedEffect(null) {
findAllUsers().collect {
users = it
}
}
Column {
Text(text = "${counter++}")
for (user in users) {
Column {
Text(text = user.id.toString())
Text(text = user.name)
}
}
}
通过此调整,该应用程序没有更多的循环行为!发生这种情况,因为findAllUsers()
仅执行一次...现在,让我们了解发生了什么。
了解JetPack Compiss Chaves API
有几个JetPack Compiss Apis接收钥匙作为参数,例如Koud6和Koud4。关键机制是指示组合可执行量的一种方法。
例如,当使用remember
而不发送任何密钥时,这意味着它将仅执行一次,因此当使用koud4发送koud10时,这也意味着它将仅执行一次!毕竟,koud10不会更改其价值...
换句话说,如果您打算多次运行这些组合,则会发送一个可变的价值。有摘要?让我们以koud4的示例:
var users by remember {
mutableStateOf(emptyList<User>())
}
LaunchedEffect(users) {
findAllUsers().collect {
users = it
}
}
随着这种调整,无限环路再次返回,因为每次重新组件发生时,我们都会为users
提供一个新值...因此,选择副作用API中的键。P>>
密钥机制可以通过varargs接收多个密钥,并且每次键都具有新值时可以重新执行...
避免在组成的事件中重新组成
避免重新组件问题的另一种方法,它正在使用可复合事件,例如点击事件:
var users by remember {
mutableStateOf(emptyList<User>())
}
val scope = rememberCoroutineScope()
Column {
Button(onClick = {
scope.launch {
findAllUsers().collect {
users = it
}
}
}) {
Text(text = "Find all users")
}
// ...
}
请参阅重新组件仅在执行点击时才发生!这种行为的秘密是这些事件在内部使用副作用API!
避免随着重新分配的流动而循环
另一个重要的细节是,正如我们在初始样本中看到的那样,JetPack Compiss中的流量通常是从转换后的Koud0进行的...
中所看到的。要使用这种方法并避免无限循环,流程的实现不应改变状态!这意味着流程的暴露仅应是读取或修改数据读取流。
因此,必须在另一个呼叫中进行新排放的更改,该呼叫不会在组成的组成中执行。让我们跟随一个ViewModel的示例:class UsersViewModel : ViewModel() {
private val _users = MutableStateFlow(emptyList<User>())
val users = _users.asStateFlow()
fun findAllUsers() {
_users.update {
listOf(User(1, "alex"))
}
}
}
以这种方式,Koud5对返回阅读流的返回,而是发出新值的负责。考虑到这种方法,这种方式往往被称为在构图范围之外,就像副作用的API一样。
要读取此实现中发现的用途,我们将其与属性users
(是StateFlow
)的对话进行了收集,这些内容将通知每个更改,因为findAllUsers()
被调用。看到它是可以合并的:
val viewModel by viewModels<UsersViewModel>()
val users by viewModel.users.collectAsState(
initial = emptyList()
)
Column {
Button(onClick = {
viewModel.findAllUsers()
}) {
Text(text = "Find all users")
}
Text(text = "${counter++}")
for (user in users) {
Column {
Text(text = user.id.toString())
Text(text = user.name)
}
}
}
请注意,即使流量收集代码为组成,我们也没有循环问题,因为这是一种仅对仅在API和副作用中进行的更新的方式!
,在那里,您如何看待JetPack中重新组成的这些细节?您是否经历了这种类型的十字架上复杂的一些挑战?喜欢分享评论。