安卓绘制原理之 MeasureCache优化了什么?

news2025/1/13 15:43:49

安卓绘制原理概览_油炸板蓝根的博客-CSDN博客

        搜了一下,全网居然没有人提过 measureCache。

        在前文中提到过,measure的时候,如果命中了 measureCache,会跳过 onMeasure,同时会设置 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT标志位,其作用顾名思义,需要在 layout 前进行 measure。

public class View {
    public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
        ......
        int cacheIndex = forceLayout? -1: mMeasureCache.indexOfKey(key);
        if (cacheIndex < 0 || sIgnoreMeasureCache) {
                // measure ourselves, this should set the measured dimension flag back
                onMeasure(widthMeasureSpec, heightMeasureSpec);
                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            } else {
                long value = mMeasureCache.valueAt(cacheIndex);
                // Casting a long to int drops the high 32 bits, no mask needed
                setMeasuredDimensionRaw((int) (value >> 32), (int) value);
                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            }
    }

    public void layout(int l, int t, int r, int b) {
        if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
            onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
            mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        }
        ...
    }
}

        这里有点令人疑惑,为什么在 measure 中跳过了 onMeasure,但又在 layout 中找补了回来。不执行可以优化性能耗时,但这里又重新执行了一次,优化在哪里?既然有这段代码,那么就一定是优化的,我们先有一下两种猜测:

  1. 前一次和后一次执行的逻辑不同,前一次的性能耗时长,后一次的性能耗时短,所以有优化。
  2. 优化了执行次数,前者执行次数比后者多。

        让我们先看一下引入 measureCache 的 commit message,看看作者怎么说的。

Skip unnecessary measurements when possible.

This change introduces a new measure cache to View, to remember the measured dimensions for previous pairs of measure specs. The measure cache is cleared whenever a View requests layout.

Unfortunately some Views rely on measure being always called when layout is invoked. To work around this problem, we need to remember when we hit the measure cache to force a call to measure just prior to calling onLayout(). This does not completely removes all measure calls but enough to optimize a number of layouts.

跳过不必要的 measure。这次改动针对 view 引入了新的measure 缓存,其可以记录已经测量过的measure specs。每次 view requestLayout的时候,都会清除 measure cache。

不幸的是,一些 view 在layout 调用的时候,总是需要 measure 调用。为了解决这个问题,我们需要在命中 measure 缓存的时候,强制在 OnLayout中调用  onMeasure。这种做法没有完全移除 measure 的调用,但是也已经足够优化一部分了。

跳过 onMeasure虽然可以提高效率,但是有一些自定义 view 是依赖其 onMeasure 流程保证其正常工作的。换句话说,一些自定义 View 的 onMeasure 方法不仅仅完成了可以被跳过的 measurement,还执行了某些不能被跳过的流程。 例如 ViewPager

public class ViewPager {

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        // measure self and decor
        ...
        // update children
        populate();
        // measure children
        ...
    }
}

        ViewPager 依赖onMeasure 更新 page,如果 onMeasure 被跳过,就有可能出现 page 错位的情况。除了 ViewPager,RecyclerView、CoordinateLayout 等复杂度较高的组件也都在 onMeasure 中做了许多复杂的工作。既然 onMeasure 一定要执行,那么 measureCache 的优化工作又体现在哪里呢?毕竟 commit message 最后写了“but enough to optimize a number of layouts.” 

        measureCache 可以将一次 Traversal 中多次冗余 onMeasure 减少为一次,对于很多 ViewGroup,在 onMeasure 阶段往往会不止一次的调用 child 的 measure,例如RelativeLayout 、使用了 weight 的 LinearLayout、ConstraintLayout 等等,measureCache 的存在使得 child 本应该在 parent view onMeasure 阶段执行的多次 measure 被延后到 layout 阶段,且仅执行一次。

public class RelativeLayout extends ViewGroup {
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildHorizontal(child, params, myWidth, myHeight);
        measureChild(child, params, myWidth, myHeight);
        setMeasuredDimension(width, height);
    }
}

        假设 A、B、C 都是一个需要测量孩子两次的 ViewGroup,那么如果没有 MeasureCache,当执行 A 的 Measure 时候,将会调用 BBCC,共四次 measure,同样的调用DDEEDDEEFFGGFFGG,共 16 次 measure。但是如果有 measureCache,在 measure 阶段,将会调用 A 的 measure(如果 A 是顶 viewGroup),然后直接设置 B、C 的大小。只调用了 1 次。然后在 layout 阶段,调用一次 B 的 onMeasure、一次 C 的 onMeasure,DEFG 的 onMeasure 各一次。所以只调用了六次。已经足够优化了。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/998731.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql树形表的两种查询方案(递归与自连接)

你有没有遇到过这样一种情况&#xff1a; 一张表就实现了一对多的关系&#xff0c;并且表中每一行数据都存在“爷爷-父亲-儿子-…”的联系&#xff0c;这也就是所谓的树形结构 对于这样的表很显然想要通过查询来实现价值绝对是不能只靠select * from table 来实现的&#xff0…

微服务·数据一致-事务与分布式事务

微服务数据一致-事务与分布式事务 概述 事务是计算机科学和数据库管理中的一个关键概念&#xff0c;用于确保数据的一致性和可靠想。事务管理是大多数应用程序和数据库系统中不可或缺的一部分。分布式事务扩展了事务的概念&#xff0c;用于多个分布式系统和服务的数据一致性管…

1、java基本语法

1.、标识符、关键字、注释 标识符&#xff1a;对类、对象、变量、方法、数组等起个名字。 合法的标识符&#xff1a; 由字母、数字、下划线“_”组成&#xff0c;并且首字符不能是数字。不能把java关键字和保留字作为标识符。标识符区分大小写字母。 理论上只要满足上面三个…

Vuex -访问(modules)模块中的 state mutations actions getters

文章目录 四大核心复习一、获取模块内的state数据1.目标&#xff1a;2.使用模块中的数据3.代码示例 二、获取模块内的getters数据1.目标&#xff1a;2.语法&#xff1a;3.代码演示 三、获取模块内的mutations方法1.目标&#xff1a;2.注意&#xff1a;3.调用方式&#xff1a;4.…

LRTA*(Learning-RTA*)

1、基本概念 LRTA* 算法是对RTA* 算法的改进&#xff0c;在RTA* 的原论文中&#xff0c;提到了&#xff1a; Unfortunately, while RTA* as described above is ideally suited to single problem solving trials, it must be modified to accommodate multi-trial learning.…

集成学习-树模型

可以分为三部分学习树模型&#xff1a; 基本树&#xff08;包括 ID3、C4.5、CART&#xff09;.Random Forest、Adaboost、GBDTXgboost 和 LightGBM。 基本树 选择特征的准则 ID3&#xff1a;信息增益max C4.5&#xff1a;信息增益比max CART&#xff1a;基尼指数min 优缺…

【uniapp关联unicloud,阿里云云服务空间】unicloud本地调试服务启动失败:当前项目未关联unicloud服务空间,请调整后重新运行,已解决

最近开发app项目&#xff0c;很多都是第一次上手 1、在Hbuider中运行项目&#xff0c;出现如下提示 2、项目根目录下已有uniCloud文件夹 3、如果云开发环境未创建&#xff0c;可以右击项目&#xff0c;选择创建uniCloud云开发环境 4、创建好的目录如下&#xff0c;index.js中…

图解三重积分的对称性

1.图解三重积分的对称性 关于三重积分详见&#xff1a;三重积分(Triple Integral) 三重积分的对称性原理与二重积分类似&#xff0c;关于二重积分的对称性详见&#xff1a;图解二重积分的对称性 被积函数 f ( x , y , z ) f(x,y,z) f(x,y,z)可以有不同的物理意义&#xff0c;…

查询设计之查询条件对结果的影响

在sql使用中&#xff0c;最常用的就是查询。 在实践过程中&#xff0c;丰富的查询场景也使得查询sql有多种写法&#xff0c;不同的写法会带来不同的效果 以下&#xff0c;就查询条件对结果的影响。 一、数据 二、需求 把查询 type A’的 user 以及 type ‘A’ 的 department…

网络爬虫的意义:连接信息世界的纽带

本文将探讨网络爬虫的意义及其在连接信息世界中的重要作用。网络爬虫作为一种自动化程序&#xff0c;通过收集和提取互联网上的数据&#xff0c;为搜索引擎、数据分析和机器学习等领域提供了宝贵的资源。同时&#xff0c;我们也将探讨网络爬虫的伦理和法律责任&#xff0c;以及…

5、DVWA——文件上传

文章目录 一、文件上传原理二、low2.1 源码分析2.2 通关步骤 三、medium3.1 源码分析3.2 通关思路 四、high4.1 源码分析4.2 通关思路 一、文件上传原理 文件上传漏洞一般指用户上传了一个可执行的脚本文件&#xff0c;并通过此脚本文件获得了执行服务器端命令的能力。文件上传…

C语言经典100例题(45)--学习使用register定义变量的方法

目录 题目 问题分析 代码 运行结果 题目 学习使用register定义变量的方法 问题分析 register是做声明的&#xff0c;为了提高效率。 register变量不能做取地址运算符&操作。 声明变量具有register储类型就要求编译器把变量存储在寄存器中&#xff0c;而不是像其他变量…

第4篇 vue的基本语法操作以及组件,声明周期,路由的操作

一 vue常用操作案例 1.1 事件渲染 1.数据渲染的方式&#xff1a;使用插值表达式{{}}进行数据渲染 2.数据渲染的方式&#xff1a;以使用 v-bind指令&#xff0c;它的简写的形式就是一个冒号&#xff08;:&#xff09;&#xff0c;v-bind 特性被称为指令。指令带有前缀 v- 代…

OLED透明屏交互技术:开创未来科技的新篇章

OLED透明屏交互技术作为一项前沿的科技创新&#xff0c;正在以其高透明度、触摸和手势交互等特点&#xff0c;引领着未来科技的发展。 不仅在智能手机、可穿戴设备和汽车行业有着广泛应用&#xff0c;还在广告和展示领域展现出巨大的潜力。 那么&#xff0c;尼伽在这篇文章中将…

无涯教程-JavaScript - DDB函数

描述 DDB函数使用双倍余额递减法或您指定的某些其他方法返回指定期间内资产的折旧。 语法 DDB (cost, salvage, life, period, [factor])争论 Argument描述Required/OptionalCostThe initial cost of the asset.RequiredSalvage 折旧结束时的价值(有时称为资产的残值)。 该…

三、lock类的编写与解析 —— TinyWebServer

lock类的编写与解析 —— TinyWebServer 一、前言 这个类的作用作者已经给了解释 —— “多线程同步&#xff0c;确保任一时刻只能有一个线程能进入关键代码段.” 对于这句话其实看了&#xff0c;会有似懂非懂的感觉&#xff0c;然后写代码的时候&#xff0c;就会完全不懂。其…

分享一个开发者和设计者的免费图标库

图标是现代界面设计的不可或缺的一部分&#xff0c;无论是移动应用、网页设计还是软件界面。然而&#xff0c;许多开发者和设计师都面临着一个共同的挑战&#xff1a;寻找高品质、开源且免费的矢量图标资源。在这个领域&#xff0c;Yesicon 脱颖而出&#xff0c;成为了一个备受…

【计算机网络】UDP数据包是如何在网络中传输的?

List item 创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多计算机网络知识专栏&#xff1a;计算机网络&#x1f525;…

【性能测试】中间件优化

1、Tomcat 优化连接数、线程池 打开tomcat安装目录\conf\server.xml文件&#xff0c;在server.xml中 有以下配置&#xff1a; tomcat HTTP/1.1 <Connector port"8080" protocol"HTTP/1.1" maxThreads"1000" acceptCount"1500" c…

Python网络爬虫库:轻松提取网页数据的利器

网络爬虫是一种自动化程序&#xff0c;它可以通过访问网页并提取所需的数据。Python是一种流行的编程语言&#xff0c;拥有许多强大的网络爬虫库。在本文中&#xff0c;我们将介绍几个常用的Python网络爬虫库以及它们的使用。 Requests库 Requests是一个简单而优雅的HTTP库&…