日常优化-界面卡顿检查分析
最近越来越无法忍受我的应用KeepassA的转场动画卡顿问题,因此查看了官方的指南,看到有系统跟踪概览这东西,一番研究,总算是搞明白如何使用这东西分析UI卡顿。
一、抓取报告
进入cpu检测模块,录制一段时间的cpu事件,便可以抓取报告
二、处理卡顿
点击主线程
可以看到在main这个线程中每一个方法的调用时间。
在这里可以看到,inflate 布局和 inflate menu 会消耗大量的时间。
2.1 加载布局优化
一般大家在写页面时都是通过xml写布局,通过setContentView、或LayoutInflater.from(context).inflate方法将xml布局加载到内存中。
但是会有一些缺点:
- 读取xml很耗时
- 递归解析xml较耗时
- 反射生成对象的耗时是new的3倍以上
因此可以从以下几个方面进行优化
asynclayoutinflater
来进行异步加载runtimeOnly group: 'androidx.asynclayoutinflater', name: 'asynclayoutinflater', version: '1.0.0'
使用方式
new AsyncLayoutInflate(this).inflate(setLayoutId(), null,
(view, resid, parent) -> {
// 做一些操作
}
});缺点:使用这种方式,会导致转场动画无效
使用[X2C](iReaderAndroid/X2C: Increase layout loading speed 200% (github.com))框架进行优化
减少布局层次
将非必要的复杂布局放在IdelHandler中
使用ViewStub延迟加载一些非必须的布局
2.2 合理使用IdelHandler
继续查看报告
发现onResume中,看到Activity和Fragment中都有一个耗时14ms的方法,检查该方法,发现其是一个启动定时器的保存一个字符串到SharedPreferences
的功能。
override fun onResume() { |
对于这个,有两个方案可以参考:
1、将该方法放在线程中执行
2、如果必须要在主线程中执行,可以将该方法放在IdelHandler中执行,顾名思义IdelHandler是一个消息队列中消息执行完成才会执行的Handler,在Android中,Activity是在ActivityThread中的Handler创建和启动的,当主线程中的所有消息都执行完成后,也就意味着Activity已经完全启动。因此可以考虑将一些必要的操作放在这里面执行,以便加快界面进入的速度。
由于我的Activity中有两个Fragment,这样一来启动的时候,将能减少15 * 3的时间消耗,相对于3帧时间。
2.3 滚动列表优化
有些场景下,我们可能不能避免的需要大量inflateLayout
布局,比如Recyclerview
中,由于需要大量inflate 子布局,因此会消耗很多主线程的时间。
为了能保证进入页面的流畅性,可以考虑先加载少部分必要的View,然后同时启动等待动画和Recyclerview
的加载流程,以达到视觉上流畅的效果
在infalte布局的过程中,解析xml 很耗时,因此itemView
需要尽可能的减少布局层次。
优化后的效果
感觉效果比之前好了不少