Android面试官:“来给我讲讲View绘制?”

news2024/11/26 22:33:41

前言

迎面走来的一位中年男子,他一手拿着保温杯,一手抱着笔记本电脑,顶着惺忪的睡眼,不紧不慢地走着,不多的几根头发在他头顶自由飞翔。过了一会,他面对着我坐下,放下电脑和保温杯,边揉眉头边对我说

“来面试的?”

“对对对” 我赶紧答应

“行吧,那你讲讲 View 的绘制流程吧”

起一个好头

View 的绘制流程应该是每个初高级 Android 攻城狮必知必会的东西,也是面试必考的内容,每个人都有不同的回答方式。

简单点譬如 measure,layout,draw 分别对应测量,布局,绘制三个过程,高明一点的会引申出 Handler,同步屏障,View 的事件传递,甚至 activity 的启动过程。掌握哪些东西,如何回答,能够给面试官一种清晰,了然于胸的感觉,同时又不会被追问三连一问三不知。各位老爷听我慢慢道来。

“噢噢,View 的绘制啊。这个可以分为顶级 View 的绘制,Viewgroup 的绘制和 View 的绘制三个方面。顶级 View 就是 ViewrootImpl”

将回答的内容分类是体现自己思考能力和知识结构的重要表现。

什么是 ViewRootImpl

相比 Viewgroup 和 View,ViewRootImpl 可能更为陌生,实际开发中我们基本用不到它。那么

什么是 ViewRootImpl 呢?

从结构上来看,ViewRootImpl 和 ViewGroup 其实是一种东西

它们都继承了 ViewParent。ViewParent 是一个接口,定义了一些父 View 的基本行为,比如 requestlayout,getparent 等。不同的是,ViewRootImpl 并不会像 ViewGroup 一样被真正绘制在屏幕上。在 activity 中,它是专门用来绘制 DecorView 的,核心方法是 setView

回答的好好的偏要问我其他问题

提到 DecorView,就不得不说一下 window 了。面试中常常我们提到一个点,或者一个词,面试官会马上引申出这个知识点相关的问题。如果我们只是死记硬背,自顾自背一堆绘制相关的东西而回答不上来,会大大减分。所以储备与必问内容相关的东西对面试和自己的知识体系很有帮助。不少老爷被面试的时候都会被问到一个问题

“activity,window,View 三者之间的关系是什么?”

我们可以通过一张图来说明。

如图所示,window 是 activity 里的一个实例变量,本质是一个接口,唯一的实现类是 PhoneWindow。

activity 的 setContentView 方法实际上是就是交给 phonewindow 去做的。window 和 View 的关系可以类比为显示器显示的内容

每个 activity 都有一个“显示器” window,“显示的内容”就是 DecorView。这个“显示器”定义了一些方法来决定如何显示内容。比如 setTitleColor setTitle 是设置导航栏的颜色和 title , setAllowReturnTransitionOverlap 设置进/出场动画等等。

所以 window 是 activity 的一个成员变量,window 和 View 是“显示器”和“显示内容”的关系。

这就是他们的关系

View 是怎么绘制的

“呦呵,不错嘛,这个比喻不错,看来平时还挺爱思考的。行,你继续说说 View 是怎么绘制的”

在整个 activity 的生命周期中,setContentView 是在 onCreate 中调用的,它实现了对资源文件的解析,完成了 xml 文件到 View 的转化。那么 View 真正开始绘制是在哪个生命周期呢?

答案是 onResume 结束后

他们的关系在源码中一目了然。

从源码中可以看到,onResume 之后,ActivityThread 通过调用 activity 中 windowmanager 的 addView 方法,将 decorView 传入到 ViewRootImpl 的 setView 方法中,通过 setView 来完成 View 的绘制。

问题又来了,setView 到底有什么魔法,为什么他就能完成 View 的绘制工作呢?

ViewRootImpl 是如何绘制 View 的

我们再来看一下 setView 方法

简单来说 setView 做了三件事

① 检查绘制的线程是不是创建 View 的线程。这里可以引申出一个问题,View 的绘制必须在主线程吗?

② 通过内存屏障保证绘制 View 的任务是最优先的

③ 调用 performTraversals 完成 measure,layout,draw 的绘制

看到这里,ViewRootImpl 的绘制基本就完成了。其实这也是面试官希望听到的内容。考察的是面试者对 View 绘制体系的理解。

后续 ViewGroup 和 View 的绘制其实是 performTraversals 对整个 ViewTree 的绘制。他们的关系可以用下面这张图表示

考考你对知识的运用

“不错不错,看来你对 Viewrootimpl 的绘制过程掌握的不错嘛,你刚才提到 View 的绘制是在 onResume 之后才开始的,那为什么我在 onCreate 中调用 View.post 方法可以得到 View 的宽高呢”

这个问题乍看挺唬人的。其实看一眼源码大概就明白了

View.post 会判断当前 View 是否已经被添加到 window 上。如果添加了则立即执行 runnable,如果没有被添加则先放到一个队列中存储起来,等添加到 window 上时再执行。

而 View 被测量完成后才会 attachToWindow。所以当 post 的 runnable 执行时,View 已经绘制完成了。

MeasureSpec 的理解

“可以可以。看来这个小细节你注意到了。再问你个简单的问题,你刚才说到 measure 方法吧,那你说说什么是 MeasureSpec?为什么测量宽高要用它作为参数呢?”

这个问题看似很简单死板,其实是想考察对 View 测量的理解。

View 的大小不仅仅取决于自身的宽高,还取决于父 View 的大小和测量模式。一个 200200 的父 View 是不可能容纳一个 300300 的子 View 的,父 View 的 wrap_content 和 match_content 也会影响子 View 的大小。

所以 View 的 measure 函数其实应该有 4 个参数:父 View 的宽父 View 的高宽的测量模式高的测量模式

Android 这里用了一个巧妙的设计,用一个 Int 值来表示宽/高的测量模式和大小。一个 int 有 32 位,前 2 位表示测量 MODE,后 30 位表示 SIZE。

为什么要用 2 位表示 MODE 呢?因为 MODE 只有 3 种呀,UNSPECIFIED,EXACTLY,AT_MOST,小傻瓜。

“不错啊小伙子,那我自定义一个 View 的时候,如果不对 MeasureSpec 做处理。使用这个 View 时宽高传入 wrap_content,结果会怎么样?”

这个考察的就是 View 绘制的实际运用了。当我们自定义一个 View 时,如果继承的是 View,measure 方法走的就是 View 默认的逻辑

所以当我们自定义 View 时,如果没有对 MODE 做处理,设置 wrap_content 和 match_content 结果其实是一样的,View 的宽高都是取父 View 的宽高。

再来点细节

“呦呵,那你说说 invaliate 和 requestlayout 方法的区别”

前面我们说到,ViewRootImpl 作为顶级 View 负责 View 的绘制。所以简单来说,requestlayout 和 invaliate 最终都会向上回溯调用到 ViewRootImpl 的 postTranversals 方法来绘制 View。

不同的是 requestlayout 会绘制 View 的 measure,layout 和 draw 过程。invaliate 因为只添加了绘制 draw 的标志位,只会绘制 draw 过程。

这也能考算法

“可以可以,看来 View 绘制这块你理解的不错嘛。来考你个小算法,实现一下 findViewbyid 的过程”

一般对开发而言,算法的考察都不会太深,主要是常见算法的简单使用。目的是对业务中遇到的一些问题有更好的解决思路。像这个问题其实是想考察一下递归算法的简单使用。

“小伙子准备的不错嘛,好了,View 绘制这块我没有什么问题了,我们来聊聊 View 事件处理吧…”

最后

针对Android 中不同的技术模块,整理了一些相关的 学习文档笔记 及相应的 面试习题(含答案),大家可以针对性的进行参考学习与复习。

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

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

相关文章

【腾讯云Cloud Studio实战训练营】用Vue+Vite快速构建完成律师H5页面

👀前置了解:(官网 https://cloudstudio.net/) 什么是Cloud Studio? Cloud Studio 是基于浏览器的集成式开发环境(IDE),为开发者提供了一个永不间断的云端工作站。用户在使用 Cloud Studio 时无需安装&#…

计算机设计大赛国赛一等奖项目分享——基于多端融合的化工安全生产监管可视化系统

文章目录 一、计算机设计大赛国赛一等奖二、项目背景三、项目简介四、系统架构五、系统功能结构六、项目特色(1)多端融合(2)数据可视化(3)计算机视觉(目标检测) 七、系统界面设计&am…

源码断点分析Spring的占位符(Placeholder)是怎么工作的

项目中经常需要使用到占位符来满足多环境不同配置信息的需求&#xff0c;比如&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://www.springframe…

老师怎么发分班录取情况?这个快捷方式可以搞定

关于分班录取的发布方式&#xff0c;老师们可以参考下面的步骤来发布&#xff1a; 1. 班级通知&#xff1a;老师可以在学校的通知栏、公告栏或班级群里发布分班录取情况。在通知中&#xff0c;老师可以列出每个班级的学生名单&#xff0c;包括学生的姓名和分班结果。 2. 班级…

纽扣电池寿命和功率增强器

近日&#xff0c;基础半导体器件领域的高产能生产专家Nexperia&#xff08;安世半导体&#xff09;宣布推出NBM7100和NBM5100。这两款IC采用了具有突破意义的创新技术&#xff0c;是专为延长不可充电的典型纽扣锂电池寿命而设计的新型电池寿命增强器&#xff0c;相比于同类解决…

抖店商品详情API接口(关键词搜索商品列表API接口)

联盟商品和非联盟商品是抖店平台上的两种不同类型的商品。 联盟商品是指与抖店平台达成合作关系的商家提供的商品。这些商家通常是经过严格筛选和审核的合作伙伴&#xff0c;与抖店平台有合作协议&#xff0c;并享受一定的运营支持和优惠政策。联盟商品通常具有较高的品质和可…

【大数据】一些基本概念

一、数据库、数据仓库、数据湖 1.什么是数据库 (Database, DB) 数据库是指长期储存在计算机中的有组织的, 可共享的数据集合 就是存储数据的仓库 数据库有三个特点: 永久存储, 有组织, 可共享 数据库是一种结构化数据存储技术&#xff0c;用于存储和管理有组织的数据。数据库…

[HDLBits] Exams/m2014 q4a

Implement the following circuit: Note that this is a latch, so a Quartus warning about having inferred a latch is expected. module top_module (input d, input ena,output q);always(*) beginif(ena)qd;end endmodule

面试热题(合并K个升序链表)

给定一个链表数组&#xff0c;每个链表都已经按升序排列。 请将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 输入&#xff1a;lists [[1,4,5],[1,3,4],[2,6]] 输出&#xff1a;[1,1,2,3,4,4,5,6] 解释&#xff1a;链表数组如下&#xff1a; [1->4->5,1…

Java多款线程池,总有一款适合你。

线程池的选择 一&#xff1a;故事背景二&#xff1a;线程池原理2.1 ThreadPoolExecutor的构造方法的七个参数2.1.1 必须参数2.1.2 可选参数 2.2 ThreadPoolExecutor的策略2.3 线程池主要任务处理流程2.4 ThreadPoolExecutor 如何做到线程复用 三&#xff1a;四种常见线程池3.1 …

企业数字化转型与股利分配(2007-2021年)

参照李滟&#xff08;2023&#xff09;的做法&#xff0c;本团队对来自西南大学学报&#xff08;社会科学版&#xff09;《企业数字化转型与股利分配》一文中的基准回归部分进行复刻。 企业数字化转型已成为我国经济增长的新引擎和新动力。为探究数字化转型对企业财务决策的影…

Spring 依赖注入和自动装配

DI&#xff08;依赖注入&#xff09; DI&#xff1a;Dependency Injection 共有三种方式 构造器注入 在前面IOC容器创建对象的方式中已经提到&#xff0c;无参构造器和有参构造器都可以。 Set方式注入&#xff08;重点&#xff09; 依赖注入&#xff1a;本质是Set注入 依赖…

【Linux】高级IO

目录 IO的基本概念 钓鱼五人组 五种IO模型 高级IO重要概念 同步通信 VS 异步通信 阻塞 VS 非阻塞 其他高级IO 阻塞IO 非阻塞IO IO的基本概念 什么是IO&#xff1f; I/O&#xff08;input/output&#xff09;也就是输入和输出&#xff0c;在著名的冯诺依曼体系结构当中…

LinuxC编程——进程间通信(二)(信号、共享内存)

目录 一、信号1.1 概念1.2 信号的响应方式⭐⭐⭐1.3 几种常见的信号1.4 函数练习 二、共享内存2.1 共享内存的特点2.2 共享内存创建步骤⭐⭐2.3 共享内存创建所需函数 信号主要用来通知进程异步事件的发生。最初信号设计的目的是为了处理错误&#xff0c;它们也用来作为最基本的…

【EI/SCOPUS检索】第二届能源与动力工程国际学术会议(EPE 2023)

第二届能源与动力工程国际学术会议&#xff08;EPE 2023&#xff09; 2023 2nd International Conference on Energy and Power Engineering 能源是人类社会发展的重要推动力量。如何安全、清洁、高效地存储、转化和利用能源&#xff0c;实现人类可持续发展&#xff0c;一直…

比例方向阀控制多功能放大器

适用于控制无电位置反馈的三位四通比例方向阀&#xff0c;两路独立工作的比例放大器&#xff0c;可组合成并联工作方式&#xff0c;0到10V输入接口&#xff0c;可切换为0(4)到20mA输入&#xff0c;工作电压24VDC&#xff0c;允许工作温度范围0~45℃&#xff0c;放大器只有在断电…

spring security实践-全套代码

贴一套完整代码 电脑文件都被加密了&#xff0c;无法上传git&#xff0c;留一套在此&#xff0c;日后方便。 整个学习过程参考的spring security 1. 项目目录结构 2.初始化数据库 CREATE TABLE sys_user (id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 主键,user_name VAR…

你确定你的 REST API 真的符合 REST 规范?

RESTful API 的存在是 web 开发历史上的一个里程碑。在本文中&#xff0c;我将和你探讨几种节省 REST API 开发时间的方法&#xff0c;并给出相关的 Node.js 示例。 什么是 RESTful API 首先&#xff0c;想问一个问题&#xff0c;你的项目里真的有真正的 RESTful API 吗&…

【构造】CF1734 E

Problem - 1734E - Codeforces 题意&#xff1a; 思路&#xff1a; Code&#xff1a; #include <bits/stdc.h>#define int long longusing i64 long long;constexpr int N 1e3 10; constexpr int mod 1e9 7;int n; int a[N], ans[N][N];void solve() {std::cin &g…

动力节点零基础Java学习教程,从入门到进阶,轻松掌握Java开发技能

Java是一门应用非常广泛的编程语言&#xff0c;对于零基础自学Java来说&#xff0c;Java的学习过程可能会有一些困难&#xff0c;但只要掌握了相关的基础知识和技能&#xff0c;不断地实践和总结&#xff0c;就能真正掌握Java编程。 动力节点老杜的Java经典之作&#xff0c;哔站…