View视图设计开发应该是移动客户端必须掌握的技术技巧,关于android客户端中View视图都会有哪些方面的面试问答呢?下面我展开介绍一下我自己常用的几个方面的面试问题。
请你介绍一下android系统View渲染过程
一般情况得到的答案大概如下,View的绘制过程先是onMeasure,然后是onLayout,最后是onDraw,然后就结束了。如果大家想在面试过程针对这个问题加点分,可以补充一下一些细节。
- 每个过程的具体职责是什么?
- Activity的视图层级结构是怎么样的?
- View绘制触发源头是在哪里?
- View和ViewGroup绘制流程具体的区别是怎么样的?
通常启动一个Activity的时候,我们会通过setContentView进行加载layout文件/view视图实例,并被添加到ContentView中(具体可以描述一下PhoneWindow,DecorView,xxxView等系统布局层级结构),View视图绘制会从ViewRoot的performTraversals方法开始,其中performMeasure方法执行的是测量流程,performLayout方法执行的是布局流程,performDraw方法执行的是绘制流程。
接下来就开始介绍每个流程具体。
在执行performMeasure过程中,具体的测量操作会分发给View来执行,针对ViewGroup会通过遍历调用子View的measure方法进行测量,最终通过回调onMeasure回调完成测量过程。如果我们需要自定义View,可以通过重写onMeasure方法,调用View的setMeasureDimension方法设置View的尺寸。
View的测量完毕后的就是执行performLayout布局流程,同样是交由View来实现,如果是ViewGroup会重写View的layout方法实现所有View控件布局流程,最终通过onLayout方法来实现View的布局,默认情况下ViewGroup和View中的onLayout方法是空实现的,并且在ViewGroup中onLayout方法是一个抽象方法,子类继承ViewGroup时,必须要实现这个方法。
最后执行performDraw绘制流程,最终调用每个View的draw方法,通过实现onDraw方式实现具体的View内容绘制。
至此是我想到的比较得分的面试回答。再进一步的得分点可以结合补充引导自己熟悉的/阅读过源码的View例子进行介绍每个过程,同时夹带一下自己在实现某个自定义View所踩过的坑以及应对手段。如果希望能够再深入一点,我个人建议如下:
- android屏幕刷新渲染流程?双缓冲机制以及弊端?
- layout文件解析加载过程是怎样的?
View的过度绘制问题以及如何解决办法?
我收到面试者回复较多的答案是因为View视图层级过高引起的过度绘制。这个回复不准确,只能说View视图层级过高会有可能引起过度绘制,这里不存在必然的因果关系。过度绘制其实是针对像素值,在单次绘制过程中,对某个像素值多次渲染,如果超过4x次,就会过度绘制。那么View层级堆叠过高就会多次绘制了吗?不是的,这个可以回过头阅读draw方法源码找到答案。之后我会继续追问下面几个问题:
- 如果背景设置透明色Color.Transparency和设置null,会有什么区别?
- 单层View会不会引起过度绘制?请举个例子,什么情况下会单层View也会引起过度绘制?
- SurfaceView会不会引起过度绘制?TextureView会不会引起过度绘制?
- Gone掉的View会不会引起过度绘制?INVISIBLE的View会不会引起过度绘制?
针对View的性能优化手段都有哪些?
基本上回复不会超过以下范围:应用include、merge标签进行layout复用;使用ViewStub进行View懒加载;应用ConstraintLayout优化布局降低层级(可以追问layoutmanager和recyclepool等相关内容);
基本上讲也没有什么大问题,如果能从多角度思考并讲述,那必然是加分,下面我举几个例子:
从线程角度看,那是cpu占用,是卡顿,还可以有
- 避免UI耗时操作,保证刷新频率
- 使用异步线程加载资源
- 降低View渲染刷新频率
- 尽量固定View尺寸;使用layout性能高的容器;
从资源占用角度看,那是缓存,指向内存,还可以有
- 适配分辨率,主要是bitmap位图
- 避免在渲染流程创建销毁实例对象,避免内存抖动
从View生命周期看,那是创建/缓冲/复用,还可以有
- AsyncLayoutInflater方案?
- X2C方案?
- Jetpack Compose方案?
- 列表ViewHolder机制?
- WebView预加载?
从代码风格上看,就是编码习惯,还可以有
- 去除不必要的background设置
- 减少使用margin、padding,使用space替代;
- 减少使用fade渐变
- 减少使用布局动画
- 去除不必要的scrollbar
- 使用渲染效率高的容器
请你介绍一下android系统View事件分发机制
这个问题请参考View渲染机制进行。我个人比较习惯追问下面一些应用细节问题。
- 如何扩大一倍View的事件响应区域?如果是缩小一倍呢?注意down事件响应情况。
- View的拖拽过程几个阶段的事件处理,长按、拖拽、放下,分别是谁负责消费事件。
- 协调者布局CoordinatorLayout如何处理View滑动事件冲突的?
- 触摸事件里,getX、getY和rawX、rawY有什么区别?
- 能不能通过触摸事件,监听具体是触摸在哪个View的区域内?
请你设计一个五角星头像的View
综合考察自定义View掌握,也能考察编码思考过程,以及实现细节。一般自定义View绘制会采用下面三种方法实现
- 通过drawPath、clipPath实现五角星形状,然后把头像绘制渲染上去
- 通过PorterDuff.Mode进行五角星形状mask图片与头像图片融合绘制渲染
- 通过Shader方式实现五角星头像绘制渲染
如果想继续深入追问,那么可以继续
- 如果要前景五件星形状转动,背景头像方向不动,这个动画效果怎么实现?
- 上面三种方式都有什么优缺点?你常用是哪个方式?为什么?
结论
在面试过程中很多问题都没有标准答案,也许就是你回答激发出来的兴趣点。在面试过程,根本都还是考察候选人是否有相关知识,知识掌握程度如何,是知道一点?还是实践应用过?还是完全掌握?除开考察专业技能知识点之外,还会考察个人问题的理解反应,表述问题的条理逻辑,解决问题的思维方法。面试就是双向选择过程,也是知识整理查缺补漏的过程,也许还能了解行业技术栈情况的过程,把自己知道的,日常的状态充分表现出来就可以。