自定义视图及其性能

Custom Views and Performance

Android 平台自带了很多标准控件,但是你总会发现有无法满足你的需求的时候,这时候你可以使用自定义控件.自定义控件是很容易的,困难的是怎么让自定义控件的性能表现良好.这里将会介绍一些会导致自定义控件表现变差的原因.

  • 在没有改变的时候仍然调用了 onDraw()
  • 耗费时间和资源绘制根本不会再界面上展示的像素.比如被遮挡住的部分
  • 我们还可以在 onDraw 中花很长的时间

首先介绍在没有改变的时候仍然执行了绘制流程,要记住,所有的绘制都始于 View.invalidate() . 第一个原则是自定义控件不要调用 invalidate 除非你必须这么做.如果没有东西被改变了,那就不需要重新绘制.第二个原则是传入一个块内容给 invalidate.这会帮助系统决定哪些内容需要被重绘以及什么时候调用 onDraw.如下:

大致流程是这样的,首先它会判断块内容是否被修改了,如果被修改了,那么就判断这个内容是否在屏幕上,如果在屏幕上,再判断这个内容是否可见,如果可见,才进行重绘.

可见 onDraw 是非常重要的,你的视图是流畅,性能优异的还是差劲的它占了很大的作用.

我们写一个不太理想的 onDraw 是非常容易,其中一个方式就是过度绘制.比如你绘制了一些根本就看不到的内容,这是一个无用功.

那我们如何处理那些看不到的内容呢?我们可以通过设置clip rectangle来达到这个目的.这个裁剪的目的就是使得范围外的内容不会去触碰和绘制,保证他们不会消耗任何东西.调用这个功能的方法是 Canvas.clipRect().当你调用这个方法的时候会保证 GPU 只处理这个方块内的内容.这个效果会持续到下一次调用 Canvas.clipRect().这个在低端的 GPU 上效果明显,但是在高端的 GPU 上的效果就没那么明显了.甚至在一些硬件条件下,可能你花费在 CPU 计算这个裁剪的内容的时间,比你在 GPU 绘制上节省的时间还多.这意味着我们还有一个需要优化的部分就是 CPU 消耗,这个消耗基本上都在 onDraw 上.我们有以下几个建议:

  1. 不要绘制任何你没必要绘制的东西.可以通过调用 Canvas.quickReject 来定义那些元素并不在屏幕上.如果它返回 true 那么不要绘制这个元素.如果一个元素有一部分仍然在屏幕内容,它依然会返回 false,只有完全不在屏幕上的才会返回 true.
  2. 不要使用没有硬件加速的绘制.硬件加速意味着这些操作发生在 GPU 上.如果不是硬件加速的话,它意味着需要 CPU 来处理绘,然后他要把这个结果发送给 GPU 来和剩余的视图部分做组合.对比硬件加速来说,这简直就是让人发指的慢.如果你使用的方法并没有硬件加速,那么考虑是不是有其他的方式来绘制.
  3. 不要再 onDraw 方法中分配内存,以及在 onDraw 中调用的方法.分配会消耗两种东西,首先是直接消耗了分配和初始化对象的性能,然后在垃圾回收的时候还有一次消耗.这两种中的每一种都可能会造成丢帧的现象.

也许这些建议看起来都很不起眼,但是记住,onDraw 在一秒内会调用 60 次左右.而且不像其他的代码,它必须在 UI 线程上执行.你绘制一次屏幕只有 16 毫秒的时间.

You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×