AndroidUI绘制流程

news2024/11/29 8:48:08

Android源码阅读 UI绘制流程

环境

  • Java 11
  • android 11

由于学习的课程api 不一致 导致源码有些关键方法无法进入仔细阅读 采用截图的方式理解思路

view添加到窗口

进入到源码中可以发现 ,每个activity 默认生成的代码中都会有一个setContentView方法,这个方法用于加载输入路径当前的布局以及后续的操作

底层本质还是调用一个委托去设置资源

  @Override
    public void setContentView(@LayoutRes int layoutResID) {
        initViewTreeOwners();
        getDelegate().setContentView(layoutResID);
    }

在继续走进这个委托类的接口实现方法

image-20230711161927489

    @Override
    public void setContentView(int resId) {
        ensureSubDecor();
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        LayoutInflater.from(mContext).inflate(resId, contentParent);
        mAppCompatWindowCallback.getWrapped().onContentChanged();
    }

ensureSubDecor() 进入这个decor 方法 下图为部分代码

     if (!mSubDecorInstalled) 
     mSubDecor = createSubDecor();

createSubDecor() 根据实装值 来判断是否创建对应的decor

image-20230711162250175

这个方法中有大量的系统资源整合 ,都是一些系统主题的装饰器放入到对应需要创建的window中,比如

  • content
  • themedContext
  • subDecor 等等系统资源

再继续往下看 会看到一个赋值操作 将 mWindow.setContentView(subDecor);赋值,

PS: WINDOW 对象的主要实现都在phone window 中 所以我们去phone window 寻找这个主要的方法

这个方法有两个主要实现 这里我们主要看 layouResId为参数的实现内容

   @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        
        // 先判断上下文父对象是否存在 是否创建内容装饰器(用于拿到需要的基础主题资源)
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

image-20230711164741590

这里我们点进 generateLayout 方法,见名知意 这个方法主要是组装布局需要的主题属性和样式属性 这里看到

  mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

加载资源的方法 根据不同的 feature 给layout赋不同的值,之后将布局信息添加到 mdecor

之后再 generateLayout() 返回一个 contentParent 也就是一个viewGroup

流程图

image-20230711172049149

总结

image-20230711172822341

  1. 在进入到activity 之后 会优先创建顶层布局 decorView 来设置系统需要的主题参数
  2. 将decorView 添加到基础布局中 返回 viewGroup 不同的主题加载不同的viewGroup 但是都会有一个容器OnDraw的id
  3. 最后被setContentView添加到布局中

View的绘制流程

image-20230711163004442

根据上图 我们可以先去查看ActivityThread 找到 H这个类 他继承自 handle 内部实现了一个handleMessage方法 内部会有一个调用链路

  1. handleMessage 调用 handleLaunchActivity 标识 启动一个选择的activity
  2. handleLaunchActivity 调用 handleResumeActivity
  3. handleResumeActivity 调用performResumeActivity最终在这个方法回调

image-20230711175042268

需要注意的是在这个调用链路中 viewRootImpl performTraversal() 这个方法 ,绘制view的三个步骤就是在这个线程中完成的

image-20230711175532161

image-20230711175608056

image-20230711175632714

测量

image-20230711175815720

​ 从最底层源码的测量可以看出 执行测量其实就是不断调用到最低层的 setMeasureDimensionRow 中对两个成员变量标记赋值,保存测量控件的宽高。

​ 在view 绘制之前 安卓底层会先去利用 measure测量对应view 的模式和尺寸,安卓给我们提供了一个叫做 measurespec类 是一个三十二位int的存储值,前两位代表模式,后三十位代表尺寸

  • SpecMode(前两位) + SpecSize(后三十位)

核心方法

makeMeasureSpec

image-20230711180346695

用于取值 mode 只需要取前两位 size 只需要取后三十位 组合成一个 MeasureSpec

同样 MeasureSpec 也有对应的getsizegetmode 获取对应的值

getRootMeasureSpec

参数

  1. 子容器高度/宽度
  2. 顶级容器 高度/宽度

根据设置的布局属性 来设置对应的mode

image-20230711181416911

image-20230711181510179

帮助 performMeasure 是拿到需要的 measurespec

image-20230711181120529

decor view 继承自 framelayout 查看他的 onMeasure 方法

通过递归的方式 判断并且设置不同规则父容器和子控件的测量方式

image-20230711182103316

View 测量的对比图

image-20230711182200787

完整测量自身流程

image-20230711183000873

image-20230711182532080

ps: 在自定义view 的时候 一定要重写 onmeasureDiemsion方法

在 view 设置测量自己之前会调用getdefaultsize 根据不同的模式获取到size 有趣的是 at 和 exactly 赋值都是父容器剩余的大小,所以在自定义view 需要重写一系列方法不然就可能出现问题

image-20230711183506916

自定义容器和viwe 区别 :

  1. 自定义容器需要先测量子控件再量自己
  2. view 直接测量自己即可

布局

image-20230711183856133

核心方法

view.setFrame()

image-20230711184313298

对控件的上下左右赋值 设置完成 控件需要摆放的位置就确定了

view.onlayout()

如果此时是容器 则需要调用此方法 确定子控件的位置

绘制

image-20230711185425080

核心方法

view.draw()

        /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         *      7. If necessary, draw the default focus highlight
         */

image-20230711185902270

viewGroup.dispatchDraw()

image-20230711190035041

总结

绘制过程

ViewGroup

  1. 绘制背景
  2. 绘制自己
  3. 绘制 子控件
  4. 绘制前景 滚动条等

View

  1. 绘制背景
  2. 调用自己的 ondraw
  3. 绘制前景 滚动条等

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

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

相关文章

Python采集课堂视频教程, m3u8视频解密

前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 环境使用: Python 3.8 解释器 Pycharm 编辑器 模块使用: requests >>> pip install requests pycryptodome --> pip install pycryptodome re 第三方模块安装方法: win R 输…

SpringBoot+MinIO实现minio部署和使用

Minio是一个go编写基于Apache License v2.0开源协议的对象存储系统,是为海量数据存储、人工智能、大数据分析而设计,它完全兼容Amazon S3接口,十分符合存储大容量的非结构化数据从几十kb到最大5T不等。是一个小而美的开源分布式存储软件。 特点 简单、可…

windows系统下载大白菜制作iso镜像文件

背景 1. ventory制作了U盘启动盘,ventory只能加载iso文件, 我们有些操作需要进入到winpe系统进行操作,故需要制作大白菜pe的iso文件 操作步骤 下载大白菜 大白菜u盘启动盘制作工具_大白菜u盘装系统_大白菜pe_大白菜官网-首页 (windowsrw.…

一个判断 I2C 总线通信异常原因的方法

一个判断 I2C 总线通信异常原因的方法 参考链接 【经验分享】一个判断 I2C 总线通信异常原因的方法 (stmicroelectronics.cn)https://shequ.stmicroelectronics.cn/thread-633302-1-1.html 至于如何在i2c总线中如何使用还没有弄明白。后续再看。 使用方法记录 阻值分配 图中…

Confidence Regularized Self-Training 阅读笔记

Confidence Regularized Self-Training 领域自适应研究的最新进展表明,深度自训练是实现无监督领域自适应的有效手段。这些方法通常涉及到一个迭代过程,即在目标域上进行预测,然后将自信的预测作为伪标签进行再训练。然而,由于伪…

泛微打造国资委国企双端的监管平台,数据互联,动态管理

数字政府和数字监管成为趋势。数字化方式能够助力完善国有资产管理体制,促进国有资产保值增值,推动国有资本做强做优做大,有效防止国有资产流失。 国资监管过程中存在着诸多挑战 监管企业众多,需要建立不同的管理模式。既要发挥…

C/C++库函数之——str类和mem篇(常用速学)

目录 一,str类 1)strlen 2)strcpy 3)strcmp 4)strcat 5)strstr 二,mem类函数 1)memcpy 2)memmove 一,str类 1)strlen 用途&#xff1a…

光伏5G多合一融合终端|光伏多合一融合终端|光伏多合一群调群控网关|分布式光伏群控群调|光伏AGC/AVC系统这几者之间什么技术关系,多少钱一套预算?

光伏5G多合一融合终端|光伏多合一融合终端|光伏多合一群调群控网关|分布式光伏群控群调|光伏AGC/AVC系统这几者之间什么技术关系,多少钱一套预算? 一:光伏5G多合一融合终端的功能 光伏5G多合一融合终端的功能:群调群控/AGC/AVC功…

[MMDetection]生成测试集预测的test.bbox.json文件

基于MMdetection3.10 困扰了大半天的问题,终于解决了。 方法1:定位到configs\_base_\datasets\coco_detection.py 将里面的路径全部换为自己的路径,最重要的是将以下注释取消掉,特别注意以下两个参数 改好的文件示例 # datase…

数据结构 - 线性表(C语言版)

线性表分为顺序表和单链表 线性表的操作主要是查询、插入、删除 1、顺序表 首先,定义一个顺序表的结构体 #define MAX_SIZE 10 typedef struct {int data[MAX_SIZE];int length; }SqList, * PsqList;创建一个线性表 void createSqList(PsqList pSqList) {pSqLis…

Spring—事务及事务的传播机制

Spring—事务及事务的传播机制 🔎事务的定义🔎Spring—事务的实现铺垫Spring 编程式事务Spring 声明式事务Transactional 的参数注意事项Transactional 的工作原理 🔎Spring—事务的隔离级别MySQL—事务的隔离级别Spring—事务的隔离级别Spri…

剑指 Offer 04. 二维数组中的查找(java)

二维数组中的查找 剑指 Offer 04. 二维数组中的查找题目描述抽象 BST 解题 二叉树专题 剑指 Offer 04. 二维数组中的查找 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof 题目描述…

js为啥是设计成单线程而不是多线程呢

了解这个问题之前,需要先了解一下以下问题: 什么是进程?什么是线程?二者有啥关联?任务队列是什么?宏任务?微任务?eventloop?为什么说js是单线程,为什么要设计…

UWB高精度定位标签方案,厘米级室内测距,实时人员物品位置确定

随着科技的不断进步,UWB技术正逐渐成为各个领域的定位解决方案的首选。其高精度、安全、实时的特性使其在安全免提访问控制、实时室内定位等应用领域发挥着重要的作用。 安全免提访问控制是目前应用UWB技术的重要领域之一。通过将UWB标签(如手机、钥匙扣…

Django如何删除数据库表中的数据【不断积累】

这篇博客积累Django的数据库常用删除方法。 假设有表模型Author定义如下: class Author(models.Model):name models.CharField(max_length100)def __str__(self):return self.name01-根据记录的id号来删除指定的记录 Django 默认为每个模型添加一个名为 id 的自…

RPA赋能日化产业,实在智能广东日化共推行业数字化转型

广东日化,因其独特的地域、产能优势,成为广东制造业的支柱产业之一,占据了全国日化行业的半壁江山。作为本土最具影响力商会组织之一,广东省日化商会凝聚了一批具有影响力的日化企业,其经济总量、市场占有率、品牌知名…

python网站创建:初识网站(001)

1. 初识网站:首先来认识一下,前端、后端、数据库它是怎么分工合作来形成网站的 使用python创建网站之前,需要先稍微认识一下两个最流行python web框架:(Flask)和(Django) Flask是一个轻量级的框架,适用于比较轻巧&…

【*1900倍数遍历】CF1627 D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 在枚举数列子集的gcd时&#xff0c;通常可以枚举倍数 对于这道题要注意&#xff0c;j/i的gcd要为1&#xff0c;这样才能保证i是这个子集的最大公约数 Code&#xff1a; #include <bits/stdc.h>//#define…

三菱FX3U简单工程编程

1.简单工程编程 1.1.元件 常开触点&#xff08;ld&#xff09; 选中位置&#xff0c;点击图标&#xff0c;输入软元件&#xff0c;完成添加。 选中位置&#xff0c;快捷键F5添加。 选中位置&#xff0c;输入ld 软元件添加。常闭触点&#xff08;ldi&#xff09;横线、竖线 …

红黑树增删操作详解(相信我,这次你一定会弄懂)

前言&#xff1a; 网上众多关于红黑树的讲解&#xff0c;但大多数都是重复的&#xff0c;只列出了几种简单情况&#xff0c;逻辑和思维深度都不足以解答吾之困惑。。。 直到看到张彦峰先生的 对红黑树的认识总结&#xff0c;基本可以说是集大成者&#xff0c;本文会基于…