鸿蒙性能优化之卡顿优化 原创
一、简介
各位代码侠、调试特种兵,今天咱们要挑战的是程序员界的“哥德巴赫猜想”——鸿蒙卡顿优化!诸位可知,李白要是用上卡顿的手机,怕是写不出“朝辞白帝彩云间”——刚打开导航应用就白屏,他老人家早迷路在三峡了!再看《孙子兵法》有云:“兵贵神速”,咱们程序员也得牢记:“码贵流畅”——毕竟用户等待加载时长的耐心,比张飞绣花还稀缺啊!送诸位一副对联共勉:
上联:鸿蒙在手岂容卡顿作妖
下联:代码如飞且看帧率登顶
横批:流畅到上头
接下来咱们就开启这场“卡顿围剿战”,让用户体验丝滑到能溜冰!
二、卡顿原理
3、1 帧率
帧率指的是一秒内播放的图像帧数,它是衡量流畅度的重要指标。60fps就是一秒内播放60帧图像,90fps就是一秒内播放90帧图像。帧率越高,视频或者动效就越流畅。
3、2 图形渲染流程
鸿蒙的图形系统是一个典型的流水线模式,以90Hz刷新率为例,每个Vsync周期是11.1ms。这个11.1毫秒是怎么来的?1秒等于1000毫秒,90赫兹就意味着在1000毫秒内刷新90次,那刷新一次需要多长?1000 * 90 = 11.1,刷新一次需要11.1毫秒。如果是60Hz,每个Vsync的周期是16.7ms;如果是120Hz,则每个Vsync的周期是8.3ms。经常玩游戏的都想要120赫兹,120赫兹每帧需要8.3毫秒内完成,每帧的速度变非常快,自然就越流畅。
如下图所示,在整个渲染流程中,首先是由应用侧响应消费者的屏幕点击等输入事件,由应用侧处理完成后再提交给Render Service,由Render Service协调GPU等资源处理后,再将最终的图像统一送到屏幕上进行显示。
如果每一帧都能在Vsync周期内完成渲染,按照这个流程渲染就非常的流程。“纵使计划缜密,也可能遭遇图穷匕见般的意外变数。”就如同荆轲刺秦,最终失败。如果上一帧无法在Vsync周期内完成渲染,下一帧就无法正常渲染,这样就发生了丢帧现象。用户看到的就是上一帧画面,页面就没有刷新,给人的感觉就是卡顿。
应用侧和渲染服务侧都有可能出现卡顿,鸿蒙将应用侧的卡顿命名为AppDeadlineMissed,大家记住AppDeadlineMissed,后面需要用到,将渲染服务侧的卡顿命名为RenderDeadlineMissed,这个大家也记住。一般而言,前者可能是应用逻辑处理代码不够高效导致的,后者可能是界面结构过于复杂或者GPU负载过大等原因导致的。
如下图所示,应用侧发生卡顿,AppDeadlineMissed期望在第一个周期执行完成,但是却在第二个周期才执行完成。
如下图所示,渲染服务侧发生卡顿,RenderDeadlineMissed期望在第二个周期执行完成,但是却在第三个周期才执行完成。
三、使用Profiler检测卡顿
当发生卡顿,可以使用Profiler检测卡顿。如下代码,构建一个列表,在列表滚动时执行耗时操作,将代码部署到真机,使用Profiler检测,看看Profiler能不能定位到耗时代码处。
如下图所示,按照图中步骤操作。
继续按照下图操作
经过上图中的步骤,Profiler就会分析卡顿,分析完成就会得到下图,从下图可以知道是应用侧发生卡顿,丢帧率为87.1%。
现在我们已经知道发生了卡顿,但是还没有找到卡顿代码。按照下图操作,Profiler就能帮我们定位卡顿代码。
四、卡顿优化
下面给出一些常见卡顿优化方案
4、1 能不用自定义组件就不要用自定义组件,尽量用@Builder方法
如果使用自定义组件,系统会在节点树上创建一个自定义节点,在渲染阶段也创建相应的渲染节点。如果在列表里面使用自定义组件,列表的每个子项都是自定义组件,那就会成倍的增加节点树的自定义节点。是不是意味着不能使用自定义组件呢?当然不是,如果组件简单,使用@Builder方法;如果组件复杂,还是使用自定义组件。对于列表来说,如果列表仅仅是用来展示,没有额外的编辑功能,建议还是使用@Builder方法;如果列表复杂,还是需要使用自定义组件。
4、2 列表使用LazyForEach,指定缓存数量,使用@Reusable复用组件
4、3 使用相对布局,减少布局嵌套
布局过于复杂,会导致渲染服务侧发生卡顿。
4、4 耗时操作放到子线程,建议网络请求也放到子线程
大家在进行网络请求的时候,是使用子线程还是使用异步?异步还是在主线程中执行,只不过是延后执行。应用启动的时候,一般需要请求很多接口,如果网络请求都使用异步,大大加重了主线程的负担,引发卡顿。使用子线程请求网络,必然涉及跨线程传输数据,需要使用@Sendable注解。关于多线程,可以查看并发相关的文档。
4、5 不要在生命周期、高频调用的函数内执行耗时操作
耗时操作放到子线程。
4、6 避免调用耗时接口,getInspectorByKey、getInspectorTree等都属于耗时接口。
五、线上卡顿检测方案
应用发布后,可能会有反馈卡顿,如果能复现卡顿,那就可以使用Profiler检测卡顿。大部分情况下,很难复现线上的卡顿,因为很难构造出线上卡顿的场景。如何检测线上卡顿?
鸿蒙提供了HiAppEvent来检测主线程超时事件以及卡死事件。其实鸿蒙提供了完整性能监控方案,HiAppEvent不仅能够检测卡顿、卡死,还能检测到崩溃、资源泄漏、启动耗时、丢帧、功耗、踩内存、CPU高负载等等。想实现线上性能监控,直接使用HiAppEvent。我基于HiAppEvent写了一个线上性能监控框架。如果你公司想自建性能优化平台,那我这个框架可以作为抛砖引玉,甚至可以完全满足你的要求。
六、总结
到此为止,大家应当掌握了线上线下的卡顿检测。
诸位道友,今日这场“鸿蒙卡顿围剿战”,我们算是围剿成功了。卡顿退散,流畅永驻。
可可爱爱牛牛地文~~哈哈哈哈