Compose的一些小Tips - 可组合项的绘制

2023-09-20 14:36:03

系列文章

Compose的一些小Tips - 可组合项的生命周期
Compose的一些小Tips - 可组合项的绘制(本文)
Compose的一些小Tips - 列表的优化

前言

本系列介绍Compose的一些常识,了解这些tips并不会让人摇身一变成为大佬,但可以帮助到一些学习Compose的安卓开发者避免一些误区,也是对Compose入门详解中遗漏的一个补充。本文介绍可组合项的绘制

View的绘制 ≈ 可组合项的绘制

在说可组合项之前,我们先说说原生view的绘制过程,面试时也经常问到,并且可组合项的展现和view的绘制过程非常的相似。
在这里插入图片描述

原生view的绘制

我们简单复习下原生view的三个主要的阶段,值得注意的是,每一个view的绘制,都会经历这必不可少的三个阶段

  • onMeasure( int , int ) 测量所有子view的大小
  • onLayout( boolean , int , int , int , int ) 再次测量所有子view的大小并分配所有的子元素的位置
  • onDraw(Canvas) 渲染内容

ps:可以看到onMeasure会进行一次测量,onLayout也会进行一次测量,这是二次测量,有兴趣的可以自行了解,因为和本文内容不相关

在这里插入图片描述

可组合项的绘制

可组合项的展现到屏幕前的三个阶段分别为

  • Composition (组合) ,这是Compose的一大特性,与view的绘制不同,Compose 会运行可组合函数并创建界面说明。
  • Layout(布局) , 测量所有子可组合项并分配所有子可组合项的位置,与view的绘制不同,这里的测量会包含view中onMeasure的测量
  • Drawing(绘制),渲染内容

在这里插入图片描述

Compose会根据跟踪可组合项中的状态智能的跳过重组时不必要(没发生过变化)的阶段,这也是Compose对性能的优化。

可组合项的绘制不同阶段对应的具体方法

对于view来说onMeasure这些方法都是view的实现方法,而可组合项中好像也没有叫Composition 的方法暴露出来,这是因为Compose都是基于可组合项和它的状态来绘制的,因此三个阶段的具体方法也是二者的结合。并且因为单向数据流的关系,可能会因为对组合的状态的监听而影响到测量和绘制阶段(也可能不影响,下面会举例),所以下面的例子都是讲的直接影响这个阶段的作用域,并不是只影响这个阶段的作用域,希望读者不要误解。

组合

@Composable 函数或 lambda 代码块中的状态改变时,Compose会监听到状态的改变并开始重组(重新绘制),这也涉及到可组合项的生命周期相关知识,如果不了解的可以去看下Compose的一些小Tips - 可组合项的生命周期,我这边直接说结论,就是状态如果改变了内容则组合会发生改变,影响可组合项的绘制,而内容如果没发生改变,则会跳过重组。

我们可以来看一个简单的例子

    var state by remember {
        mutableStateOf(0)
    }
    Column() {
        Text(text = "重组$state")
        Text(text = "不重组")
    }

在上诉例子中第一个Text会因为state 的改变而进行重新进行组合这个阶段,因此重新进行绘制,如果state 从 0 变为1 ,则在理想情况下第一个Text会经历组合和绘制阶段,但因为Text的大小和位置都没有发生变化,所以会跳过测量阶段,而第二个Text因为不涉及状态的变化,会跳过所有的阶段。

测量

我们可以再来看一个简单的例子理解影响到测量阶段的值

    var width by remember {
        mutableStateOf(10.dp)
    }
    var offsetX by remember { mutableStateOf(8.dp) }
    Text(
        text = "位置和大小发生变化",
        modifier = Modifier
            .width(width)
            .offset {
            IntOffset(offsetX.roundToPx(), 0)
        }
    )

在上诉的简单代码示例中,影响到可组合项大小的width 状态和影响到可组合项位置的offsetX 状态会使Compose进行可组合项的测量阶段,然后再进行绘制阶段。

绘制

而绘制阶段的最明显的作用范围用最简单的话来说就是每一次从屏幕上肉眼可见的变化,都经历了绘制阶段,包括上面两段示例代码,都经历了绘制阶段。

为什么≈

为什么说View的绘制是约等于可组合项的绘制而不是等于呢,上面其实已经吧答案说过了

  • view的绘制阶段是每个阶段都要进行的,哪怕什么都没有变化,只要执行了重绘,所有的阶段都会重新进行一遍。
  • Compose的可组合项会根据状态智能的跳过不需要的阶段,从而进行性能的优化

这是原生xml和Compose除了写法以外,原理的不同。

Compose的智能取决于写法

上面已经说过,Compose的可组合项会根据状态智能的跳过不需要的阶段,以优化性能,而这个智能就很有嚼头,如果写法对了,就会智能的跳过,如果写的不对,就会造成额外的开销,甚至因为Compose的代码还在发展中,还不够成熟,会比原生xml更消耗性能,这也是一些不愿意学习的读者所说的,“我跑起来性能就是比原生差,跨平台还不如选flutter,哪儿哪儿都不行,再看两年吧”。在写法错误情况下,Compose的性能确实不如原生xml的。

更多推荐

豆瓣图书评分数据的可视化分析

导语豆瓣是一个提供图书、电影、音乐等文化产品的社区平台,用户可以在上面发表自己的评价和评论,形成一个丰富的文化数据库。本文将介绍如何使用爬虫技术获取豆瓣图书的评分数据,并进行可视化分析,探索不同类型、不同年代、不同地区的图书的评分特征和规律。概述本文的主要步骤如下:使用scrapy框架编写爬虫程序,从豆瓣图书网站抓取图

使用 docker-compose 构建你的项目

使用docker-compose构建你的项目1.Docker1.1安装1.2docker-compose2准备项目2.1初始化一个node项目4.准备一个Dockerfile文件5.构建镜像3.docker-compose构建3.1配置docker-compose.yml文件3.2编排多个服务重新构建镜像--force

【PostgreSQL内核学习(十四)—— (PortalRunMulti 和 PortalRunUtility)】

PortalRunMulti概述PortalRunMulti函数ProcessQuery函数PortalRunUtility函数声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。本文主要参考了《PostgresSQL数据库内核分析》

Dubbo高手之路4,Dubbo服务提供者详解

目录一、服务提供者1、Dubbo服务提供者的定义2、服务暴露的方式3、服务注册的实现(1)创建服务接口(2)实现服务接口(3)注册服务(4)服务消费者二、服务提供者的配置1、服务提供者的XML配置2、服务提供者的注解配置3、服务提供者的容错处理(1)失败重试机制(2)隔离机制(3)超时机制三、服务提供者集群1、集群容错

[Qt]事件

文章摘于爱编程的大丙文章目录1.事件处理器1.1事件1.2事件处理器函数1.2.1鼠标事件1.2.2键盘事件1.2.3窗口重绘事件1.2.4窗口关闭事件1.2.5重置窗口大小事件1.3重写事件处理器函数1.3.1头文件1.3.2源文件1.3.3效果1.4自定义按钮1.4.1添加子类1.4.2使用自定控件1.4.3设置图

SOME/IP

介绍SOME/IP是一种汽车中间件解决方案,可用于控制消息。它从一开始就被设计为完美地适应不同尺寸和不同操作系统的设备。这包括小型设备,如相机、AUTOSAR设备,以及头戴设备或远程通信设备。它还确保SOME/IP支持信息娱乐域以及车辆中其他域的功能,从而允许SOME/IP用于大多数替换场景以及更传统的CAN场景。SO

4G版本云音响设置教程腾讯云平台版本

文章目录4G本云音响设置教程介绍一、申请设备三元素1.腾讯云物联网平台2.创建产品3.设置产品参数4.添加设备5.获取三元素二、设置设备三元素1.打开MQTTConfigTools2.计算MQTT参数3.使用USB连接设备4.设置参数三、腾讯云物联网套件协议使用说明1.推送协议信息2.topic规则说明3.播放协议说明

逻辑漏洞挖掘之XSS漏洞原理分析及实战演练 | 京东物流技术团队

一、前言2月份的1.2亿条用户地址信息泄露再次给各大公司敲响了警钟,数据安全的重要性愈加凸显,这也更加坚定了我们推行安全测试常态化的决心。随着测试组安全测试常态化的推进,有更多的同事对逻辑漏洞产生了兴趣,本系列文章旨在揭秘逻辑漏洞的范围、原理及预防措施,逐步提升大家的安全意识。作为开篇第一章,本文选取了广为熟知的XSS

vue3 封装公共弹窗函数

前言:博主封装了一个公共弹窗函数接收四个参数,(title:弹窗标题,ContentComponent:弹窗中显示的组件内容,opt:接收弹窗本身的属性和props,beforeSure:点击确定做的操作(请求后端接口))封装的公共函数:import{defineComponent,h,ref,getCurrentIn

提升预算管控精度,助力保险资管协会财务管理数字化转型

数字化转型是当前中国经济社会发展的重要趋势和根本方向。中国保险资产管理业协会(以下称“协会”)是专门履行保险资产管理自律职能的全国性金融自律组织。过去几年,协会一直在积极探索应用信息化手段,加强预算管理。近期,协会与百望云合作,重构了预算项目,整合了核算、报销、OA系统,通过智能管票、系统控制,搭建全流程自动化、智能化

为什么我们总是被赶着走

最近发生了一些事情,让shigen不禁的思考:为什么我们总是被各种事情赶着走。一第一件事情就是工作上的任务,接触的是一个老系统ERP,听说是2018年就在线上运行的,现在出现问题了,需要我去修改一下。在这里,我需要记录一下技术背景:ERP系统背景后端采用的是jfinal框架,让我觉得很奇葩的地方有:接受前端的参数采用的

热文推荐