1. 请详细描述一下 Android 中 View 的绘制流程从measure到draw的具体步骤和关键方法三大步骤measure测量大小 →layout确定位置→draw绘制内容measure测量大小父 View 调用measure(int widthSpec, int heightSpec)内部调用onMeasure(widthSpec, heightSpec)测量自身及遍历子 View确定大小最终调用setMeasuredDimension设置测量宽高layout确定位置父 View 调用layout(l, t, r, b)内部调用onLayout确定自身及遍历子 View 确定位置draw绘制视图内容。绘制背景drawBackground。保存画布图层可选。绘制自身内容onDraw。绘制子 ViewdispatchDraw。绘制滚动条、装饰等。2. 请具体说下measure过程中View 的 MeasureSpec 是怎样生成的吗它和父容器的 MeasureSpec 以及 View 自身的 LayoutParams 有什么关系MeasureSpec一个 32 位 int 值高 2 位表示模式UNSPECIFIED、EXACTLY、AT_MOST低 30 位表示大小。EXACTLY精确大小match_partent/固定值AT_MOST最大不超过父容器大小wrap_contentUNSPECIFIED父 View 不限制生成规则子 View 的 MeasureSpec 由父容器的 MeasureSpec 和子 View 的 LayoutParams 共同决定。父容器调用getChildMeasureSpec(parentSpec, padding, childLayoutParams)生成。具体规则表格简化父容器为EXACTLY子布局固定尺寸 → 子为EXACTLY 固定值。子布局wrap_content→ 子为AT_MOST 父大小。子布局match_parent→ 子为EXACTLY 父大小。父容器为AT_MOST子布局固定尺寸 → 子为EXACTLY 固定值。子布局wrap_content→ 子为AT_MOST 父大小。子布局match_parent→ 子为AT_MOST 父大小。父容器为UNSPECIFIED少见子一般为UNSPECIFIED大小不限。总结子布局为固定尺寸时不论父容器是 EXACTLY/AT_MOST —— 子为EXACTLY 固定值子布局为wrap_content不论父容器是 EXACTLY/AT_MOST —— 子为AT_MOST 父大小子布局为match_parent—— 父容器模式 父大小3. 能举例说明不同情况下子 View 的 MeasureSpec 的生成规则吗示例父容器宽 400px模式EXACTLY固定大小。子 LayoutParams生成规则子 MeasureSpecwidth 200dp固定固定尺寸EXACTLY 200width match_parent填满父容器EXACTLY 400width wrap_content不超出父容器AT_MOST 400示例父容器宽 400px模式AT_MOST如 ScrollView 内的 View。子 LayoutParams生成规则子 MeasureSpecwidth 200dp固定固定尺寸EXACTLY 200width match_parent不超过父容器AT_MOST 400width wrap_content不超过父容器AT_MOST 4004. 谈一谈自定义 View 和自定义 ViewGroup类型关注点关键方法例子自定义 View自身绘制和交互onMeasure,onDraw,onTouchEvent圆形进度条、开关按钮自定义 ViewGroup测量和布局子ViewonMeasure,onLayout, 可能dispatchTouchEvent流式布局、自定义九宫格注意ViewGroup 需遍历子 View 并调用measureChild和child.layout。5. Android 事件分发机制中MotionEvent 从 Activity 传递到具体 View 的完整流程是怎样的涉及哪些关键方法完整流程Activity → PhoneWindow → DecorViewViewGroup→ View关键方法dispatchTouchEvent分发事件返回 true 表示消费。onInterceptTouchEvent仅 ViewGroup 有返回 true 则拦截不再向下传递。onTouchEvent处理事件返回 true 表示消费。流程细节记忆dispatch分派intercept拦截touch处理Activity → ViewGroup → View。6. 解释一下滑动冲突定义父 View 和 子 View 滑动方向一致争夺 Touch 事件导致滑动卡顿、方向错乱、滑动失效常见场景ScrollView 嵌套 RecyclerView、ViewPager 嵌套 RecyclerView 等。解决原则外部拦截父 View 在onInterceptTouchEvent中根据滑动距离、方向按需决定是否拦截。内部拦截子 View 通过requestDisallowInterceptTouchEvent(true)请求父 View 不拦截。判断逻辑判断滑动方向水平/垂直或滑动距离。记忆外部拦截改父 View 的拦截方法内部拦截用requestDisallow。7. 为什么 ViewPager 嵌套 ViewPager内部的 ViewPager 滚动没有被拦截原因被外层的 ViewPager 拦截了解决原则外部拦截父 View 在onInterceptTouchEvent中根据滑动距离、方向按需决定是否拦截。内部拦截子 View 通过requestDisallowInterceptTouchEvent(true)请求父 View 不拦截。记忆内层可滚动外层不拦事件自归其主。8.OnTouchListener.onTouch方法 和onTouchEvent有什么优先级关系优先级OnTouchListener.onTouch高于onTouchEvent。规则View.dispatchTouchEvent中若OnTouchListener不为 null 且onTouch返回 true则不再调用onTouchEvent否则才调用onTouchEvent。注意onTouch返回 true 表示消费事件后续事件不会再传递。记忆Listener先于onTouchEvent返回 true 则拦截。9. 屏幕刷新机制软件 vs 硬件绘制、双缓冲、撕裂问题、黄油计划软件绘制纯 CPU 逐帧绘制效率低容易掉帧。硬件绘制GPU 加速分担 CPU 绘制压力利用 OpenGL / Vulkan高效平滑。双缓冲使用两个帧缓冲区Front Buffer 前台缓冲区 / Back Buffer 后台缓冲区GPU 在 Back Buffer 绘制完成后再交换到 Front Buffer 显示避免 “撕裂”。撕裂问题Tearing屏幕是逐行扫描刷新的如果 APP 随时写入新画面会导致旧画面和新画面同时展示出现断裂层。可以采用**「双缓冲分离绘制和显示」 「 垂直同步Vsync统一刷新时机」**解决。黄油计划Project ButterAndroid 4.1 引入主要改进Vsync 同步系统每 16.6ms 发出 Vsync 信号统一刷新时机三缓冲在双缓冲基础上增加一个缓冲区解决 CPU/GPU 耗时不均衡导致的卡顿提升流畅度**Choreographer [ˌkɔːriˈɑːɡrəfər] **接收 Vsync 信号统一驱动全局 UI 刷新记忆口诀软件 CPU 硬件 GPU双缓冲防撕裂黄油计划 Vsync 三缓冲 统一绘制调度。10. UI 刷新机制Vsync、Choreographer、requestLayout/invalidateVsync垂直同步信号系统每隔 16.6ms 发出信号通知 CPU/GPU 进行帧绘制。统一绘制时机、解决画面撕裂、保证画面流畅、限制刷新频率Choreographer绘制调度核心接收 Vsync 信号统一驱动全局 UI 刷新requestLayout触发onMeasure→onLayout→ 不会主动走onDraw用于大小/位置改变、需要重新测量布局场景invalidate只触发onDraw不重新测量、不重新布局用于局部刷新、内容变化、无尺寸变更记忆Vsync 信号由 Choreographer 分发requestLayout 重测量invalidate 重绘制。11.invalidate()与postInvalidate()区别invalidate()必须在UI 线程中调用直接触发重绘onDraw。postInvalidate()可在子线程中调用内部通过 Handler 发送消息到 UI 线程间接触发重绘。使用场景在子线程中需要更新 UI 时使用postInvalidate()主线程中用invalidate()。记忆主线程 invalidate子线程 postInvalidate。12. 同步屏障SyncBarrier在 MessageQueue 中的作用用于 Choreographer 的 UI 刷新作用拦截普通消息优先处理异步消息。插入同步屏障后next()会跳过所有同步消息只返回异步消息。用途Choreographer 利用同步屏障保证 UI 绘制异步消息在下一帧开始时立即执行不被其他同步消息阻塞。创建/移除MessageQueue.postSyncBarrier()返回 tokenremoveSyncBarrier(token)移除。记忆同步屏障阻同步只让异步先行保证 UI 刷新及时。13 插值器 (Interpolator) 与估值器 (TypeEvaluator)在属性动画中插值器决定动画的变化速率速度模型而估值器决定动画的具体数值变化二者协同工作以实现丰富的动画效果插值器 Interpolator作用控制动画变化节奏、速度曲线处理「时间进度」把 0~1 的时间比例转换成变速进度常见线性、加速、减速、先加速后减速、弹性插值器核心改节奏不改数值规则。估值器 TypeEvaluator作用根据进度计算具体属性数值。处理「数值计算」接收起点、终点、当前进度算出中间实时值系统自带Int、Float、Argb 估值器复杂自定义对象需要自己实现。核心算具体值决定动画最终变化结果。总结插值器控制快慢节奏估值器计算真实数值先插值修正时间进度再由估值器算出对应属性值。144. View 几种位移方式scrollTo/By、属性动画、LayoutParams、TranslateAnimation的区别方式原理效果注意scrollTo/By移动 View 的内容不改变位置改变画布偏移滑动内容如 TextView 文字滚动不影响点击区域属性动画 ObjectAnimator改变translationX/Y移动 View 位置点击区域同步API 11推荐LayoutParams动态修改边距调用requestLayout移动 View会触发重新布局开销较大TranslateAnimation补间动画只移动绘制位置视觉移动点击区域原位置易造成点击错位不推荐记忆scroll 移内容属性动画移实体LayoutParams 重布局补间动画假移动。15 LayoutInflater 获取 View 的原理LayoutInflater的工作是将 XML 布局文件描述的用户界面通过解析和反射实例化inflate成内存中的View对象树。它的完整工作流程涵盖了 XML 解析、View 创建和属性应用等多个阶段解析传入的 XML 布局文件获取资源 ID通过XmlPullParser 流式解析 XML逐行读取标签、属性、布局参数根据标签名如 TextView、LinearLayout通过反射找到对应 View 类并实例化读取 XML 中所有属性赋值给 View 的 LayoutParams、样式、参数若为 ViewGroup递归遍历子标签重复上述流程逐个添加子 View最终生成完整 View 树并根据 root、attachToRoot 参数决定是否绑定到父容器、是否生成布局参数关键要点XML 解析 反射创建 View 递归加载子控件。16. Activity、Window、View 三者关系PhoneWindow、DecorViewActivity控制器负责生命周期和事件处理内部持有 Window 实例PhoneWindow。WindowPhoneWindow窗口视图的顶层容器承载整个页面布局。setContentView时创建 DecorViewFrameLayout。DecorView顶级 View包含标题栏和内容区域android.R.id.content。关系Activity → PhoneWindow → DecorView → 用户设置的根布局。记忆Activity 控制 WindowWindow 内含 DecorViewDecorView 装布局。17. Window 与 WindowManager 的理解View 的载体、系统窗口管理Window窗口如 Activity、Dialog、Toast抽象概念实际实现为 PhoneWindow视图的顶层容器WindowManager通过 WindowManagerService - WMS 管理窗口如 Window 的创建、添加、移除、层级管理、屏幕适配通过addView、updateViewLayout、removeView操作通过 IBinder 跨进程与 WindowManagerService - WMS系统服务通信Window 是 View 的容器WindowManager 负责管理窗口18. 有了解过 WindowInsets 吗它有哪些应用定义WindowInsets 是用来描述系统 UI 占用区域的对象包含状态栏、导航栏、刘海、软键盘等。用于沉浸式适配、安全区域避让、异形屏和折叠屏适配、软键盘处理替代旧的fitsSystemWindows动态灵活可动画应用沉浸式布局setSystemUiVisibilityfitSystemWindows或WindowInsets监听。适配刘海屏WindowInsets.getDisplayCutout()。监听键盘弹出ViewCompat.setOnApplyWindowInsetsListener调整布局。动态调整 View 的 padding / margin 以避免被系统栏遮挡。记忆WindowInsets 管理系统栏/键盘区域沉浸式、适配刘海、键盘监听。19. 获取 View 宽高的方法post、ViewTreeObserver、onWindowFocusChangedview.post(Runnable)Runnable 在layout之后执行此时 View 已绘制完成通过 Handler 投递 Runnable优点写法简单开销小适用快速简单获取宽高ViewTreeObserver添加OnGlobalLayoutListener布局完成后回调。回调后及时移除监听防止重复回调、内存泄漏适用需要实时监听布局变化、动态获取onWindowFocusChangedActivity/Fragment 窗口获取焦点时回调View 已绘制完成。页面多次焦点切换会重新触发适用页面初始化一次性获取全局 View 尺寸其他在onResume或onLayout中获取也可但post最方便。都用于解决onCreate方法中直接获取getWidth/Height为 0 的问题。20. ConstraintLayout 特点与优势特点基于约束的布局通过相对定位实现扁平化视图层级避免嵌套。优势减少布局嵌套提升性能。支持百分比、比例、链式约束、辅助线Guideline等灵活布局。可视化编辑器友好拖拽生成约束。内置动画TransitionManager支持约束变化。记忆约束扁平化性能好灵活强。21. SurfaceView 与 TextureView 使用场景视频播放、动画、Camera 预览对比SurfaceViewTextureView独立窗口是独立 Surface位于 Window 下层否作为普通 View 在 View 树中绘制移动/缩放/动画不支持独立窗口无法随 View 变换支持可进行变换、透明度动画性能高双缓冲适合实时刷新稍低需与 UI 线程同步适用场景视频播放、Camera 预览、游戏频繁更新需要动画、圆角、缩放等视频或 Camera 预览SurfaceView独立的 Surface独立窗口/独立绘制图层脱离主线程、独立子线程绘制绘制性能高、功耗低、刷新快但无法做常规形变、动画、高斯模糊场景视频播放、Camera 预览、游戏、实时弹幕、直播推流TextureView共享 View 绘制图层跟随 View 树渲染支持平移、缩放、旋转、动画、滤镜、透明度、嵌套场景需要动画形变的视频、悬浮播放、页面嵌套视频、特效视频预览记忆SurfaceView 性能高但不动TextureView 灵活可变幻。22. StaticLayout 的用法和应用场景定义StaticLayout 继承自 Layout是 Android 中用于对静态文本即内容不会变化的文本进行复杂布局的工具类。核心作用可实现文本自动换行与多行排版精准计算行高、行数、文本宽高边界服务于自定义 View 文本绘制与精准测量。构建方式推荐使用StaticLayout.Builder类通过链式调用设置对齐、省略等可选属性最后调用build()方法创建实例应用场景自定义 View 绘制多行文本替代自己分行富文本 / 图文混排支持 Span、图片、缩进聊天气泡、评论区、阅读类分页需要精确文本尺寸性能优化文本不变时一次创建多次绘制TextView/EditText 底层实现系统控件内部在用特点只适合静态文本内容不频繁变更频繁改文字推荐DynamicLayout。23. RecyclerView 优化预取、布局缓存、复用池、setHasFixedSize 等缓存四级缓存充分利用减少 Inflate 与绑定耗时局部刷新 使用 notifyItem 系列不刷新全列表。异步差分刷新 使用 DiffUtil 替代全局刷新减少 UI 刷新开销。预取机制PrefetchRecyclerView 在滑动时提前加载下一个 item 的布局减少卡顿LinearLayoutManager默认开启setHasFixedSize(true)固定宽高避免requestLayout重新测量布局优化 item 布局扁平化、减少嵌套、减少过度绘制使用 ConstraintLayout。记忆固定大小、预取、池共享、DiffUtil 精刷。24. RecyclerView 缓存机制四级缓存名称作用mChangedScrap与 RecyclerView 分离的 ViewHolder 列表mAttachedScrap未与 RecylerView 分离的 ViewHolder 列表mCachedViewsViewHolder 缓存列表mViewCacheExtension自定义缓存列表mRecyclerPoolViewHolder 缓存池mChangedScrap与mAttachedScrap是用来做屏幕内ViewHolder复用不需要重新onCreateViewHolder和onBindViewHoldermCachedView是用来缓存最近移出屏幕的ViewHolder包括数据和position信息。复用时必须是是相同位置的ViewHolder应用场景是在那些来回滑动的列表中往回滑动时能直接复用ViewHolder的数据不用onBindeViewHoldermViewCacheExtension自定义缓存这个的创建和缓存完全由开发者自己控制系统未在这里添加数据RecycledViewPoolViewHolder缓存池当mCacheView满后或者adapter被更换将mCacheView中移出的ViewHolder放到缓存池中同时把ViewHolder的数据清除掉所以复用的时候需要onBindeViewHolder流程getViewHolderForPosition依次从 scrap → cache → pool → 创建。记忆四级缓存附加、缓存、扩展、池层层找找不到才创建。25. RecyclerView.Adapter 刷新方式notifyItemXXX 局部刷新 vs notifyDataSetChangednotifyItemXXX如notifyItemInserted、notifyItemChanged局部刷新不触发整个列表重绘有动画性能高。notifyDataSetChanged全局刷新重新绑定所有可见 item无动画性能低会闪烁。推荐用DiffUtil自动计算差异并调用notifyItemXXX。记忆局部精刷有动画全局重绘无性能。