Android Jetpack Compose之UI的重组和自动刷新

这篇具有很好参考价值的文章主要介绍了Android Jetpack 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 theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    CounterComponent()

                }
            }
        }
    }

    @Composable
    fun 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函数会根据优先级执行。例如:

   @Composable
    fun ButtonRow(){
        NavigationBar { 
            StartScreen()
            MiddleScreen()
            EndScreen()
        }
    }

如上面的代码所示,在代码中ButtonRow函数一次调用了 StartScreen()、MiddleScreen()、 EndScreen()三个方法,,我们不能预设这三个方法一定是按照顺序执行的。也不要试图去在StartScreen中添加一个全局变量,然后在MiddleScreen()中获取到这个变化,这种关联被称作副作用,在Web前端开发的Vue中也有这个概念。副作用会让我们的UI状态混乱,而且不易维护,所以我们编写Compose时应该尽量避免副作用。

3.2 Composable 会并发执行

Composable在进行重组时不一定执行在主线程中,他们可能在后台线程池中并行执行,这样有利于发挥多核处理器的性能优势,但是由于多个composable在同一时间执行在不同线程,此时必须要注意考虑线程安全的问题。如下面例子所示来自于《Jetpack Compose 实战》一书:

 @Composable
    fun EventsFeed(localEvents:List<Event>,nationalEvent:List<Event>){
        var totalEvents = 0
        Row{
            Column { // 注释1
                localEvents.forEach { 
                    event -> Text("Item: ${event.name}") 
                    totalEvents ++
                }
            }
            Spacer(modifier = Modifier.height(10.dp))
            Column { // 注释2
                nationalEvent.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在短时间内可能会反复的执行,而且我们无法准确的判断它的执行次数。因此我们必须考虑到:即使多次执行也不应该出现性能问题,更不能对外部产生额外有害的影响。同样。借用书中的例子:

 @Composable
    fun 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 部分

  1. Jetpack之Lifecycle
  2. Jetpack之ViewModel
  3. Jetpack之DataBinding
  4. Jetpack之Navigation
  5. Jetpack之LiveData

Android Jetpack Compose之UI的重组和自动刷新,移动开发,Android,Compose,android jetpack,ui,android,移动开发,Compose,安卓

Compose 部分
1.Jetpack Compose入门详解
2.Compose学习笔记
3.Compose 动画使用详解

Android Jetpack Compose之UI的重组和自动刷新,移动开发,Android,Compose,android jetpack,ui,android,移动开发,Compose,安卓文章来源地址https://www.toymoban.com/news/detail-731319.html

到了这里,关于Android Jetpack Compose之UI的重组和自动刷新的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android笔记(六):JetPack Compose常见的UI组件

    Text显示的文本来源可以引用res-values-strings.xml中的资源,如第一个显示文本所示。 点击按钮前: 点击按钮后: 点击第一个圆角按钮不放时,显示为按钮:true Button有两方面需要注意: (1) Buttton有一个参数interactionSource,用来监听组件状态的事件源,通过它获取组件的状态来

    2024年02月04日
    浏览(55)
  • Android Jetpack组件库(第七部分)---UI工具包 Compose

    Android Jetpack 是 Google 推出的一整套帮助 Android 应用程序开发的库、工具包和架构指南,旨在为 Android 应用程序提供更快,更轻松,更稳定的开发体验。自推出以来已经发展成了一个庞大的技术生态系统,包括了许多使用方便、功能强大的库,以下是其中一些新特性、新组件:

    2024年01月16日
    浏览(52)
  • Android Jetpack Compose 用计时器demo理解Compose UI 更新的关键-------状态管理(State)

    我们都知道了Compose使用了声明式的开发范式,在这样的范式中,UI的职责更加的单一,只会对数据状态的变化作出反应,如果数据状态没有发生变化,则UI就永远不会自行的改变。假如我们把Composable的执行看成是一个函数的运算的话,那么状态就是函数的参数,输出就是生成

    2024年02月09日
    浏览(52)
  • Android Jetpack Compose 用计数器demo理解Compose UI 更新的关键-------状态管理(State)

    我们都知道了Compose使用了声明式的开发范式,在这样的范式中,UI的职责更加的单一,只会对数据状态的变化作出反应,如果数据状态没有发生变化,则UI就永远不会自行的改变。假如我们把Composable的执行看成是一个函数的运算的话,那么状态就是函数的参数,输出就是生成

    2024年02月08日
    浏览(43)
  • 现代化 Android 开发:Jetpack Compose 最佳实践

    作者:古哥E下 如果一直关注 Compose 的发展的话,可以明显感受到 2022 年和 2023 年的 Compose 使用讨论的声音已经完全不一样了, 2022 年还多是观望,2023 年就有很多团队开始采纳 Compose 来进行开发了。不过也有很多同学接触了下 Compose,然后就放弃了。要么使用起来贼特么不顺手

    2024年02月17日
    浏览(71)
  • 对于Android开发,我们为何要学Jetpack Compose?

    Jetpack Compose 是用于构建原生 Android 界面的新工具包。它可简化并加快 Android 上的界面开发,使用更少的代码、强大的工具和直观的 Kotlin API,快速让应用生动而精彩。Compose 使用全新的组件——可组合项 (Composable) 来布局界面,使用修饰符 (Modifier) 来配置可组合项。 为何Jetp

    2024年02月10日
    浏览(53)
  • Jetpack Compose | State状态管理及界面刷新

    我们知道 Jetpack Compose(以下简称Compose) 中的 UI 可组合项是通过 @Composable 声明的函数来描述的,如: 上面的代码描述的是一个静态的 Text ,那么如何让 Compose 中的 UI 更新呢? 状态和重组 Compose 更新UI的唯一方法是通过新参数调用同一可组合项。可组合项中的状态更新时,就

    2024年02月08日
    浏览(41)
  • Jetpack Compose UI架构

    Jetpack Compose是我职业生涯中最激动人心的事。它改变了我工作和问题思考的方式,引入了易用且灵活的工具,几乎可轻松实现各种功能。 早期在生产项目中尝试了Jetpack Compose后,我迅速着迷。尽管我已有使用Compose创建UI的经验,但对新的Jetpack Compose驱动特性的组织和架构引发

    2024年02月11日
    浏览(51)
  • Jetpack Compose 深入探索系列四: Compose UI

    通过 Compose runtime 集成 UI Compose UI 是一个 Kotlin 多平台框架。它提供了通过可组合函数发出 UI 的构建块和机制。除此之外,这个库还包括 Android 和 Desktop 源代码,为 Android 和 Desktop 提供集成层。 JetBrains积极维护Desktop代码库,而Google维护Android和通用代码库。Android和Desktop源代码

    2024年02月12日
    浏览(48)
  • Jetpack Compose 不止是一个UI框架~

    Jetpack Compose是用于构建原生Android UI的现代工具包。 Jetpack Compose使用更少的代码,强大的工具和直观的Kotlin API,简化并加速了Android上的UI开发。这是Android Developers 官网对它的描述。 本文不是教你Jetpack Compose 的一些基本使用方法,而是为啥我们需要Jetpack Compose 的一些简洁,让

    2024年02月03日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包