紫色区域:系统接受与处理用户手势操作的耗时
蓝色区域:开发者转换用户操作为屏幕显示内容的耗时
黄色区域:屏幕展示内容的耗时
来源:《Explore UI animation hitches and the render loop》
如此,想要丝滑就必须做到以下两点:
- 善用多线程编程,尽可能少在主线程上做更新 UI 以外的事情。
- 尽可能让 GPU 绘制简单的界面,减少 GPU 耗时。
2.2.2 善用多线程编程,尽可能少在主线程上做更新 UI 以外的事情。
NT 内核架构打好基础
QQ 9 所采用的 NT Kernel(NT:New Technology,此处向 Windows NT 内核致敬),基于尽可能发挥多核 CPU 能效的理念而诞生,如下图所示,最大程度将业务处理逻辑从负责 UI 展示的主线程中剥离,且使用异步调用代替线程锁,提升效率的同时降低死锁的可能。
NT Kernel 多线程模型
此外,NT Kernel 采用 C 实现 IM 软件的核心基础能力,使其能跨平台使用,保证各平台的性能体验一致,用户交互界面则采用各平台原生语言实现。让用户感受强劲性能的同时保证了各平台特有的体验。
NT Kernel 支持多平台架构图
全量刷新改增量刷新
在全新 NT 内核的加持下,耗时业务逻辑都已经挪到子线程,主线程仅剩刷新 UI 的相关工作。那刷新 UI 这个事儿还有进一步优化的空间吗?答案是肯定的,14 年陈的手机 QQ 在屏幕上更新一条新消息,会将当前展示的消息全部刷新一遍,即"全量刷新"机制。滚动时无法刷新消息、资源跳变等坏体验,都是该机制导致的。
为什么滚动时无法刷新消息?并非无法刷新,而是不能刷新。多余的刷新操作很容易使得 UI 更新无法在 16.67ms 内完成,进而诱发卡顿。
为什么会出现资源跳变?全量刷新会触使屏幕上的所有节点回收、重用,并且这种重用还是无序的。如下图所示,全量刷新后节点位置会随机发生改变,例如:尾号1b400(左图第2个)的节点刷新前用于展示2,刷新则展示7(右图第7个)。
对比左右两张图的节点内存地址可见,全量刷新后会出现随机变化,并无规律可言。
无论是静态或是动态图片,都存在磁盘 I/O、解码等耗时操作,一般都会采用异步加载,避免主线程的卡顿。再叠加这种随机重用的特性,也就造成了"资源跳变"的表现。
根据不同的重用情况会有以下三种表现:
- 恰好是上次所用的节点或者内容恰好相同:相同内容赋值,没有任何变化。
- 没有相关动/静图:内容从无到有,符合预期。
- 有相关动/静图,但与当前 Model 的内容不一致:出现闪烁。如图下图所示。