河北青山建设集团有限公司网站,建程网工程信息网,怎样登录建设银行官方网站,外包加工网缝纫机外放加工活1.概述
我们都知道#xff0c;在传统的View中#xff0c;若要改变UI#xff0c;需要我们修改View的私有属性#xff0c;比如要修改一个TextView的文字#xff0c;我们需要通过它的setText(“xxx”)方法去修改。而Compose 则是通过重组来刷新UI。在之前的状态管理的文章中…1.概述
我们都知道在传统的View中若要改变UI需要我们修改View的私有属性比如要修改一个TextView的文字我们需要通过它的setText(“xxx”)方法去修改。而Compose 则是通过重组来刷新UI。在之前的状态管理的文章中也提到过重组的概念。本章主要就是介绍Compose的重组和刷新相关的内容
2.Compose智能重组 compose的重组是很智能的当重组发生的时候只有状态发生改变的Composable函数才会参与重组没有变化的Composable则会跳过本次重组。例如在计数器的demo中 class ComposeCounterAct : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyComposeTheme {// A surface container using the background color from the themeSurface(modifier Modifier.fillMaxSize(),color MaterialTheme.colorScheme.background) {CounterComponent()}}}}Composablefun CounterComponent() {Column(modifier Modifier.padding(16.dp)) {var counter by remember { mutableStateOf(0) }Text($counter,Modifier.fillMaxWidth(),textAlign TextAlign.Center)Row {Button(onClick { counter-- },modifier Modifier.weight(1f)) {Text(-)}Spacer(Modifier.width(16.dp))Button(onClick { counter },modifier Modifier.weight(1f)) {Text()}}}}
}当点击Button按钮的时候counter的状态变化会触发整个Coloum范围的重组。重组过程中显示计数器值的文字组件会被赋予新的counter值以显示更新后的数字。但是如果此时有另外一个不依赖counter状态的文字组件则它是不参与重组的因为Compose编译器会在编译期间插入相关的比较代码这些比较代码会让没有依赖变更的状态的组件在对应状态更新时不参与重组。
有读者可能会疑惑在Button的onclick方法中也依赖了counter那它会发生重组吗答案是不会因为重组只会在Composable函数中进行而onClick并非是一个Composable函数所以和重组无关。此外Button控件也没有依赖counter状态所以也不会参与重组
3.避免掉入重组的“坑”
在前面的文章中我们提到过Composable在编译期间代码会发生变化所以代码的实际运行情况可能并不如我们预期的那样。所以我们需要了解下Composable在重组执行时的一些特性避免掉入重组的坑”。所以我们需要理解掌握下面的内容
3.1 Composable函数的执行顺序不固定
当我们的代码中出现多个Composable函数时他们并不一定会按照代码中出现的顺序执行比如在Navigation中处于Stack最上方的UI会优先被绘制在一个Box布局中处于前景的UI会具有较高的优先级因此Composable函数会根据优先级执行。例如 Composablefun ButtonRow(){NavigationBar { StartScreen()MiddleScreen()EndScreen()}}如上面的代码所示在代码中ButtonRow函数一次调用了 StartScreen()、MiddleScreen()、 EndScreen()三个方法我们不能预设这三个方法一定是按照顺序执行的。也不要试图去在StartScreen中添加一个全局变量然后在MiddleScreen()中获取到这个变化这种关联被称作副作用在Web前端开发的Vue中也有这个概念。副作用会让我们的UI状态混乱而且不易维护所以我们编写Compose时应该尽量避免副作用。 3.2 Composable 会并发执行
Composable在进行重组时不一定执行在主线程中他们可能在后台线程池中并行执行这样有利于发挥多核处理器的性能优势但是由于多个composable在同一时间执行在不同线程此时必须要注意考虑线程安全的问题。如下面例子所示来自于《Jetpack Compose 实战》一书 Composablefun EventsFeed(localEvents:ListEvent,nationalEvent:ListEvent){var totalEvents 0Row{Column { // 注释1localEvents.forEach { event - Text(Item: ${event.name}) totalEvents }}Spacer(modifier Modifier.height(10.dp))Column { // 注释2nationalEvent.forEach { event - Text(Item: ${event.name}) totalEvents }}Text(if(totalEvents 0) No Events. else Total events $totalEvents)}}在上面的例子中想通过totalEvents记录events的数量并在Text上显示但是注释1和注释2 处的Column代码有可能在不同的线程中并行执行所以就导致了totalEvents的累加是非线程安全的结果可能是不正确的。即使totalEvents的结果正确但是由于Text可能运行在单独线程所以也不一定能显示正确的结果所以这里还是副作用带来的问题需要我们避开。
3.3 Composable会反复的执行
除了重组会造成Composable的再次执行外在动画等场景中每一帧的变化都可能引起Composable的执行。所以Composable在短时间内可能会反复的执行而且我们无法准确的判断它的执行次数。因此我们必须考虑到即使多次执行也不应该出现性能问题更不能对外部产生额外有害的影响。同样。借用书中的例子 Composablefun EventsFeed(netWorkService: EventsNetWorkService) {val events netWorkService.loadAllEvents()LazyColumn {items(events) { event -{Text(text event.name)}}}}如上面代码所示在方法EventsFeed中loadAllEvents是一个IO操作是一个耗时操作执行的成本高如果在Composable中同步调用那么在重组时会造成严重的卡顿问题。所以我们编写代码的时候需要注意Composable会反复的执行编写UI的时候需要时刻注意这一点
3.4.Composable的执行时“乐观”的
所谓的“乐观”是指Composable最终总会依据最新的状态正确地完成重组。某些场景下UI状态可能会连续的发生变化这可能会导致中间态的重组在执行中被打断新的重组会插入进来。对于被打断的重组Composable不会将执行一般的重组结果反馈到视图树上因为它 知道最后一次状态总归是正确的所以中间的状态丢失了也不影响。
4 总结
本节介绍了Compose的智能重组和刷新以及重组过程中可能会掉入的“坑”这些坑我们需要去属性它因为Compose框架要求Composable作为一个无副作用的纯函数运行我们只要在开发的过程中遵循这一原则那么重组中的“坑”就不会再是坑而是我们提高程序执行性能的有效方法。 为了帮助大家更好的熟知Jetpack Compose 这一套体系的知识点这里记录比较全比较细致的《Jetpack 入门到精通》(内含Compose) 学习笔记 对Jetpose Compose这块感兴趣的小伙伴可以参考学习下……
Jetpack 全家桶Compose
Jetpack 部分
Jetpack之LifecycleJetpack之ViewModelJetpack之DataBindingJetpack之NavigationJetpack之LiveData Compose 部分 1.Jetpack Compose入门详解 2.Compose学习笔记 3.Compose 动画使用详解