硬件加速
硬件加速是指利用设备的硬件资源来加速图形渲染和图像处理等操作,以提高应用程序的性能和用户体验。在Android系统中,硬件加速主要通过以下几种方式实现:
- GPU加速:Android系统利用设备的图形处理单元(GPU)来加速图形渲染。通过将图形操作交给GPU处理,可以大大提高图形渲染的速度和质量,减轻CPU的负担。
- 硬件加速绘图API:Android提供了一系列硬件加速的绘图API,如OpenGL ES、Vulkan等。这些API可以直接与GPU进行交互,实现高效的图形渲染和图像处理。
- 硬件加速的窗口管理:Android系统通过硬件加速的窗口管理机制,可以实现窗口的平滑移动、缩放和旋转等操作。这样可以提高窗口的响应速度和用户体验。
- 硬件加速的动画效果:Android系统提供了一系列硬件加速的动画效果,如属性动画、过渡动画等。这些动画效果可以利用GPU的计算能力,实现流畅的动画效果。
硬件加速可以通过利用设备的硬件资源来加速图形渲染和图像处理等操作,提高应用程序的性能和用户体验。
使用硬件加速优点:
- 「提高性能和响应速度」:利用GPU进行图形渲染和合成,硬件加速可以提高应用程序的绘制性能和响应速度。
- 「减轻CPU负担」:将图形操作交给GPU处理,可以减轻CPU的负担,使其能够更高效地处理其他任务。
- 「提高用户体验」:通过优化图形渲染和多媒体处理,硬件加速可以带来更加流畅、逼真的用户体验。
在Android里,硬件加速专指把View中绘制的计算工作交给GPU来处理,这个绘制的计算工作通常指的是把绘制方法中的那些Canvas.drawXXX()变成实际的像素操作。
加速原理
在硬件加速关闭的时候,Canvas绘制的工作方式是把要绘制的内容写进一个Bitmap,然后在之后的渲染过程中,这个Bitmap的像素内容被直接用于渲染到屏幕。这种绘制方式的主要计算工作在于把绘制操作转换为像素的过程(例如由一句 Canvas.drawCircle() 来获得一个具体的圆的像素信息),这个过程的计算是由CPU来完成的。大致就像这样:
图片
开启硬件加速后,Canvas的工作方式改变了,先把绘制的内容转为GPU的操作保存下来,然后交给GPU来完成显示工作。大致过程:
图片
从上图可以看出,开启硬件加速后,绘制的计算工作由CPU交给GPU,不过这怎么就能起到加速作用,让绘制变快了呢?硬件加速能够让绘制变快,主要有三个原因:
- 本来CPU的工作,分摊一部分给GPU,自然可以提高效率。
- 相对于CPU来说,GPU自身的设计本来就对于很多常见类型内容的计算(例如简单的圆形、方形)具有优势。
- 由于绘制流程的不同;硬件加速在界面内容发生重绘的时候绘制流程可以得到优化,避免一些重复操作,从而大幅提升绘制效率。
关闭硬件加速时,绘制内容会被CPU转为实际的像素直接渲染到屏幕,这个·[实际的像素]·是由Bitmap承载的,在界面的某个View由于内容发生改变而调用invalidate()方法时,如果没有开启硬件加速,为了正确计算Bitmap的像素,这个View的父View、父View的父View乃至一直向上知道最顶级的View,以及所有和它相交的View,都需要被调用invalidate()来重绘,一个View的改变使得大半个界面甚至整个界面重绘一遍,这个工作量是非常大的。
开启硬件加速时,绘制的内容会被转换成GPU的操作保存下来(承载的形式成为DisplayList,对应的类也叫作DisplayList)转交给GPU。由于所有绘制的内容都没有变成最终的像素,所以它们之间是相互独立的,那么在界面内容发生改变时,只需把发生了改变的View调用invalidate()方法以更新它所对应的GPU就好,至于它的父View和兄弟View,只需要保持原样,那么这个工作量就很小了。
正是由于上面的原因,硬件加速不仅是由于GPU的引入提高效率,而且因为绘制机制的改变,而极大的提高了界面内容改变时的刷新效率。
硬件加速不止有好处,也会受到GPU绘制方式的限制,Canvas有些方法在硬件加速开启时会失效或者无法正常工作,比如:开启硬件加速,clipPath()在API18及以上系统中才有效,具体的API限制和API版本的关系如下图:
图片
在开发Android应用时,需要考虑到设备的兼容性和性能差异,合理使用硬件加速功能。
硬件加速开启
- 在AndroidManifest.xml文件中的<application>标签下添加如下属性:
android:hardwareAccelerated="true"
这将启用应用程序的硬件加速功能。
- 在需要使用硬件加速的Activity的布局文件中,可以使用以下属性来启用硬件加速:
android:hardwareAccelerated="true"
或者在代码中使用以下方法来启用硬件加速:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- View绘制开启硬件加速:
//View开启硬件加速
view.setLayerType(LAYER_TYPE_HARDWARE, null);
view.setLayerType(LAYER_TYPE_SOFTWARE, null)方法的作用并不是关闭硬件加速,当它的参数为LAYER_TYPE_SOFTWARE的时候,可以顺便把硬件加速关掉而已;并且除了这个方法外,Android并没有提供专门的View级别的硬件加速开关,所以顺便成了一个开关硬件加速的方法。
setLayerType()方法的作用就是设置View Layer的类型。ViewLayer又称为离屏缓冲(off-screen Buffer),作用就是单独启用一块地方来绘制View,而不是使用绘制软件的Bitmap或者通过硬件加速的GPU,这块地方可能是一块单独的Bitmap,也可能是一块OpenGL的纹理(texture,OpenGL的纹理可以简单理解为图像的意思),具体取决于硬件加速是否开启。采取什么来绘制View不是关键,关键在于当设置了View Layer的时候,它的绘制会被缓存下来,而且缓存的是最终的绘制结果,而不是像硬件加速那样只是把GPU的操作保存下来再交给GPU去计算。通过这样更进一步的缓存方式,View的重绘效率进一步提高了:只要绘制的内容没变,那么不论是CPU绘制还是GPU绘制,都不用重新计算,只要用之前缓存的结果就可以了。
在进行移动、旋转等(无需调用 invalidate())的属性动画的时候开启Hardware Layer 将会极大地提升动画的效率,在动画过程中View本身并没有发生改变,只是位置或角度改变了,这种改变是可以由GPU通过简单计算就完成的,并不需要重绘整个View。所以在动画的过程中开启Hardware Layer,可以让本来就依靠硬件加速而变流畅了的动画变得更加流畅。实现方式大概是这样:
view.setLayerType(LAYER_TYPE_HARDWARE, null);
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
view.setLayerType(LAYER_TYPE_NONE, null);
}
});
animator.start();
在对translationX translationY rotation alpha等无需调用invalidate()的属性做动画的时候方法才适用,因为方法本身利用的就是当界面不发生时,缓存未更新所带来的时间的节省。「不适用于基于自定义属性绘制的动画。」
总结
硬件加速指使用GPU来完成绘制的计算工作,从工作分摊和绘制机制优化两个角度提升了绘制速度。
硬件加速可以使用setLayerType()来关闭硬件加速,但这个方法其实是用来设置View Layer的:
- 参数为LAYER_TYPE_SOFTWARE时,使用软件来绘制View Layer,绘制到一个Bitmap,并顺便关闭硬件加速;
- 参数为LAYER_TYPE_HARDWARE时,使用GPU来绘制View Layer,绘制到一个OpenGL texture(如果硬件加速关闭,那么行为和LAYER_TYPE_SOFTWARE一致);
- 参数为LAYER_TYPE_NONE时,关闭View Layer。
View Layer可以加速无invalidate()时的刷新效率,但对于需要调用invalidate()的刷新无法加速。绘制所消耗的实际时间是比不使用View Layer时要高的,所以要慎重使用。