从谷歌Pixel5a泄露的渲染图可以看出,它和Pixel4a非常相似。它采用了6.2英寸的OLEDFHD平板打孔显示屏,支持90Hz的刷新率。机身尺寸为156.273.28.8mm显示器左右边框宽度控制的很好,但底部边框略宽,而屏幕开口直径较大。
谷歌Pixel5a的前置8MP单摄像头位于屏幕左上角,采用后置双摄像头模块。Pixel5a的摄像头配置将与Pixel4a相同,一个12MP主传感器,另一个16MP超广角镜头。凸起的相机模块将包括闪光灯和相位检测自动对焦传感器。谷歌Pixel5a的其他功能包括立体声扬声器,3.5毫米耳机插孔,以及后置指纹解锁。
谷歌Pixel5a手机的电源/锁定键位于音量上下按钮上方的右侧。与手机其他部分相比,电源/锁键的颜色有所不同。谷歌Pixel5a手机背面可以看到谷歌的logo。谷歌Pixel5a手机定位中端,价格可能和谷歌Pixel 4a一模一样,发布时定价349美元。
手机渲染的意思
我从事Android开发行业已经有一段时间了。随着时间的推移,感觉自己的技术并没有很大的进步,平时也不注重学习。我刚刚完成我的工作任务,所以我将很难提高自己。现在面对激烈的竞争环境和技术的不断更新,我很想学习,不断提高自己的技能,于是我开始记录自己的学习笔记,技术总结,感受等。今年年初。今天给大家分享一些Android渲染机制的相关问题,相信对自己和大家都会大有裨益。
大多数用户认为性能问题(如卡顿)的主要来源是渲染性能。从设计师的角度来说,他们希望App能有更多的动画、图片等时尚元素,达到流畅的用户体验。
而Android系统可能无法及时完成那些复杂的界面渲染操作。
Android每16ms发出一次VSYNC信号,触发UI渲染。如果每一次渲染成功,都可以达到所需的60fps的流畅画面。为了达到60fps,意味着程序的大部分操作必须在16ms内完成。
如果你的一个操作用了24ms,系统在得到VSYNC信号时无法正常渲染,所以出现丢帧。然后用户会在32ms内看到相同的帧;大部分手机的屏幕刷新频率是60hz。如果没有办法在1000/60=16.67ms内完成这一帧的任务,这一帧就丢了。丢帧越多,用户感受到的卡顿情况越严重。
一个安卓应用是否流畅,或者有没有卡机掉帧的现象,和60fps、16ms有关;那么这两种价值观是怎么来的呢?为什么要以这两个值为标准呢?
12fps(每秒帧数)
由于人眼特殊的生理结构,如果观看画面的帧率高于每秒10-12fps左右,就会被认为是相干的。早期默片的帧率在16-24fps之间。虽然帧率足以让人感受到运动,但往往被认为是快速的幻灯片放映。20世纪20年代中后期,无声电影的帧率提高到20-26fps。
随着1926年有声电影的问世,人们的耳朵对音频的变化更加敏感,削弱了人们对电影帧率的关注。因为很多无声电影都是20-26fps播放,所以选择24fps的中间值作为有声电影的帧率。之后,24fps成为35mm音频电影的标准。
早期的高动态视频游戏,如果帧率低于每秒30fps,会显得不连贯。这是因为没有降低流畅度的动态模糊。(注:如需了解动态模糊技术,可在此咨询)
实际体验中,60fps比30fps体验更好。
一般来说,大脑处理视频的极限
所以一般来说,帧率越高,体验越好。
首先,我们来分析一下UI停滞的常见原因:
在UI线程中执行稍微耗时的操作
布局过于复杂,无法在16毫秒内完成渲染。
同时执行太多动画,导致CPU或GPU过载。
视图过渡绘制,同一帧中的一个像素重复绘制。
视图频繁触发测量和布局,导致测量和布局的累计耗时过多,整个视图频繁重新渲染。
内存频繁触发过量的GC(内存频繁在同一个帧中创建),暂时阻塞渲染操作。
冗余的资源和逻辑导致加载和执行缓慢。
综上所述,我们感受到的大部分卡顿问题都是因为渲染性能的原因。Android系统每16ms发出一次VSYNC信号(垂直同步,场同步,垂直同步),触发UI的渲染。
如果每次渲染成功,流畅画面所需的60fps就可以实现。为了达到60fps,这意味着程序的大部分操作必须在16ms内完成(1000/60=16.67ms)。如果你的一个操作需要24ms,系统在得到VSYNC信号时无法正常渲染,所以出现丢帧现象;然后用户会在32ms内看到相同的帧,造成卡纸。
Android需要将XML布局文件转换成GPU可以识别和绘制的对象;这个操作是在DisplayList的帮助下完成的。DisplayList保存所有将交给GPU在屏幕上绘制的数据信息;当一个视图需要第一次被渲染时,显示列表将被创建。当视图要显示在屏幕上时,我们将执行GPU的绘图指令来渲染它。
如果您修改了视图中的一些可见组件,以前的显示列表将无法继续使用。我们需要返回并重新创建一个显示列表,重新执行渲染指令并将其更新到屏幕上。
布局过于复杂,层次嵌套过深,导致画图操作耗时,增加内存消耗;我们的目标是扁平化。
使用更高效的布局方法,如线性布局和框架布局。
如果能使用LinearLayout和FrameLayout,就不要使用RelativeLayout,因为RelativeLayout控件相对复杂,测绘也需要耗费时间。如果使用相对布局来降低级别,则使用相对布局;
这里不得不提一下include和merge标签。
Include可以提高布局的可重用性,优化布局的层次结构,使布局清晰。但实际上include并没有降低布局的层次,所以include必须和merge一起使用才能降低布局的层次。
利用懒惰控件ViewStub实现布局的动态加载
ViewStub可以按需加载。这个标签最大的好处就是只有在你需要的时候才会加载。使用它不会影响UI初始化的性能;通常,当我们在特定条件下需要使用一个布局时,它会被gone或invisible隐藏。
事实上,虽然这种方式隐藏了布局,但在显示界面时,布局是实例化的。使用ViewStub可以避免内存浪费,加快渲染速度。其实ViewStub是宽度和高度都为0的视图,默认不可见。只有通过调用setVisibility函数或者Inflate函数才会加载待加载的目标布局,从而达到延迟加载的效果。要加载的布局由android:layout属性设置。
使用ConstraintLayout布局 ConstraintLayout可以有效解决嵌套布局过多的问题。
ConstraintLayout使用约束来指定每个控件的位置和关系。有点类似于RelativeLayout,但远比RelativeLayout强大(抄袭隔壁IOS的约束布局);简单布局容易处理,复杂布局约束布局工作良好,提高性能从布局开始。
需要文档的同学可以给我一个好评和支持。
如何获取信息:我发送“高级”私信免费获取。
技术是无止境的。你需要对自己提交的每一行代码,使用的每一个工具负责,不断探索其背后的原理,这样你的技术才能升华到更高的层次。
Android架构师还有很长的路要走,我想鼓励你。
PS:有问题请指正。欢迎喜欢你的评论。你可以在评论区留下你的建议和感受。