聚媒体应用卡顿分析
前言
下文中提到的耗时都是大于16ms的耗时,比较低的耗时没有列出。
1.卡顿调查
使用原生设置的Profile GPU Rendering GPU渲染模式分析
工具,粗略查看丢帧情况,看哪些界面丢帧严重。
绿色线是16.7ms的界面刷新线。
1.1 应用启动
可以看出当聚媒体启动的时候,会有一段事件丢帧特别严重,如下图。
1.2 界面滑动
可以看出当界面滑动的时候,资源加载也会出现比较严重的丢帧情况。
1.3 资源缓存
当界面来回跳转的时候,部分界面会存在没有缓存,或者缓存数据不够的情况,也有丢帧情况。
此类场景需要兼顾考虑内存和丢帧的折中选择。
2. Systrace调查丢帧时系统情况
可以看出在滑动的时候,加载的一秒多时间内,有很多丢帧的情况。
查看线程情况,UI线程处于sleeping状态。
可以看到Render线程在调用Drawframe()正在渲染一帧数据,然而可以看到此次渲染花了很长时间,接下来我们就需要看一下为什么那么耗时了。
3.主界面丢帧分析
3.1 启动引发的背景思考
启动activity总共耗时357ms,其中比较耗时的有两部分:
- 加载主题图片(55ms)w
- 加载布局资源(171ms)
优化建议:
1.去掉重复背景
1 | // common/src/main/res/values/styles.xml |
优化后,该页背景加载优化耗时25.86ms, 优化47%。
2.小播放器背景加载
关于背景的加载,源代码中是加载的png图片,我们来看一下加载png、加载webp和加载xml的耗时对比。
- 使用png加载
- 使用webp加载
- 使用xml加载
使用png图片加载背景耗时最长,webp次之,xml耗时最少。但是经过我多轮测试,png和webp两种方式加载图片耗时优化不是很稳定,有时候webp耗时会少一点,有时候会少比较多。但是xml和以上两种耗时比较稳定,使用xml当背景加载耗时会少20%左右。
因此,背景图加载建议如下:
- 如果采用纯色作为背景,图像比较简单的情况下,建议使用xml作为背景图来加载。
- 虽然webp图片比png图片加载耗时没有明确稳定的优化,但是webp图片体积很小,对于小图片的加载建议都使用webp图片。以
小播放器背景
图片为例,原png图479Kb,webp图265Kb。
小结:
1.从第一点可以看出背景图重复会直接成倍数增加加载耗时,而且会导致UI卡顿。因此自行检查重复背景图情况。目前检查到有嫌疑背景重叠的布局有如下,如果不重复可以忽略:
1 | program/src/main/res/layout/mediax_fragment_dialog_program_select.xml |
上面列出的布局请重点看一下布局的背景是否可以延用外部的背景,尽量避免重绘。
2.控件选择加载了图片就取消背景颜色,能用xml来填充背景的尽量用xml来绘制。
3.2 加载第一帧耗时分析
从图中可以看到启动主界面Choreographer绘制第一帧耗时637ms,其中测量耗时530ms,占了绝大多数的时间。自检一下自定义view中onMeasure是否有耗时操作。如果确实是空间比较多耗时可以暂时不优化。但是从下图可以看出加载布局只消耗了150ms, 其他370ms需要媒体FO定位哪里耗时了。
3.3 加载RecycleView布局
在启动阶段加载RecycleView耗时492ms, 其中onMeasure()耗时465ms,创建item和绑定View耗时300ms左右,请FO看此处是否还有优化空间,如果没有可以暂时不优化。
3.4 滑动
图中放大可以看到在主界面滑动到最底部的过程中,几乎没有丢帧。原因应该是在加载主界面的时候,将所有数据全部加载出来了,导致在滑动的时候基本不用加载数据,所以没有丢帧。
建议:从上面两个小结看,加载RecycleView界面和数据比较耗时,因此是否可以考虑将上面部分数据的加载实现懒加载,用户看不见的界面数据不加载,或者等启动完成之后再加载。我看主界面RecycleView的下面有两行半是隐藏的,可以将下半部分未显示的布局和数据延迟加载?
3.5 布局优化
3.5.1 冗余view
建议:此处没有内容多余的view是否可以去掉?
3.5.2 冗余布局
建议:此处只有一个view,是否可以取消掉该ConstraintLayout?
4.酷我音乐界面丢帧分析
4.1 进入酷我音乐界面
4.1.1 复盘启动酷我音乐界面
调到酷我界面,从Trace文件中可以看到一共分为5个部分加载整个fragment的,分别耗时如下:
- 第一部分:耗时68ms,测量耗时33ms, 绘制耗时26ms。此部分主要耗时在加载各种titile。
- 第二部分:耗时118ms,测量耗时99ms, 绘制耗时16ms。此部分主要耗时在加载
翻唱``网络
这个RecycleView。 - 第三部分:耗时471ms,测量耗时140ms,布局耗时318ms, 此部分主要耗时在加载
音乐歌单
这个fagment。 - 第四部分:耗时197ms,布局耗时186ms, 此部分主要耗时在加载
音乐榜单
这个fragment。 - 第五部分:耗时352ms,布局耗时340ms,此部分主要耗时在加载
音乐电台
这个fragment
以上多个阶段耗时点来看,该界面主要存在懒加载问题。
建议:
使用ViewPager2实现懒加载。此处由于我不清楚该工程内部数据加载逻辑,请FO适配一下数据加载部分的到各fragment的逻辑。
1 | // mediax\app\src\main\res\layout\fragment_music_qq.xml |
1 | // mediax\app\src\main\java\com\iflytek\autofly\mediax\ui\page\QQMusicFragment.java |
优化后的启动时间:
从图中可以看到使用ViewPager2,将setOffscreenPageLimit()为1之后,只会加载一个界面的内容,耗时44ms。因此从该界面的大方向来说,可以优化掉音乐榜单``音乐电台
这两个fragment的加载耗时,此处可以优化550ms左右。
4.1.2 界面布局优化
4.1.2.1 内嵌ViewPager优化
该界面从大方向优化之后,针对音乐歌单
,音乐榜单
,音乐电台
这三个Fragment, 在布局方面还有优化空间。见如下分析。
在音乐歌单
界面还内嵌了两个ViewPager,优化方向参照4.1.1小节使用ViewPager2懒加载布局,此处有不少tab, 启动耗时在471ms左右,应该还有很大优化空间空间。
4.1.2.2 空间使用合理性
建议:
- 此处需要考虑一个界面是否使用ViewPager是否合理?
- 此处需要考虑一下界面是否确有刷新功能需求?
4.2 滑动RecycleView加载
滑动音乐歌单
界面,可以看出滑动两次,界面几乎没有丢帧,说明数据早已加载,此处我们重点思考的方向是是否数据缓存过多,导致启动该界面变慢。
建议:由于当前项目音乐歌单
界面用户一次性可见的item默认是10个item, 滑动过程中会有15个item,因此是否可以设置RecycleView加载item的个数,将加载item内容分散到各个滑动环节,减少首次加载过多item引起的耗时。
4.3 滑动RecycleView回收复用
上图的操作步骤:在音乐歌单
界面向下滑动三次,然后向上滑动两次。从该图可以看出向上滑动几乎没有丢帧,说明RecycleView默认缓存了以上几次滑动的所有数据。
建议:我们知道缓存bitmap对象一方面很吃内存资源,另一方面缓存过多item也会影响首次加载耗时。此处的优化建议如上一项,合理利用RecycleView的回收复用机制,均衡一下缓存item的量。
5.喜马拉雅丢帧分析
5.1 启动
从上图中可以看到喜马拉雅界面还是和酷我界面存在同样的问题,喜马拉雅有分类节目``在线节目
两个fragment,问题是在启动的时候,两个fragment的布局和数据都加载了,导致启动该界面加载分类节目
界面耗时689ms,加载在线节目
耗时396ms。
建议:
使用ViewPager2实现懒加载,只加载一个界面的内容。
5.2 RecycleView缓存
优化建议见4.2小节,合理控制RecycleView缓存的item数目。
6.整体性能参数分析
说明:
测试场景:测试同学正常测试各个功能。
以下监控的性能数据是测试2750个采集周期,每个采集周期10s,7.64小时的数据。
内存图横坐标是采集周期,单位:个;纵坐标是内存占用,单位:M
CPU图横坐标是采集周期,单位:个;纵坐标是CPU占用,单位:%
View图横坐标是采集周期,单位:个;纵坐标是当次采集界面中view的个数,单位:个
6.1 Mediax 内存占用分析
从内存方面来看:
- MediaX应用内存占用,最高内存385M,平均内存295M
- 在监控周期内存在明显内存抖动!
- 在监控周期内存在内存泄露!
6.2 Mediax CPU占用分析
从CPU方面来看:
- 最大CPU占用46%
- 平均CPU占用4.4%
6.3 Mediax View占用分析
从mediax应用加载View个数来看:
- 最多View个数:1308个
- 平均View个数:485个
6.4 整体性能参数小结
从内存和View图可以看出Mediax应用存在大量图片加载和频繁mirror GC的情况。此处数据也应证了第3-5章分析的RecycleView过度加载View的分析。
7.优化方向总结
- 使用ViewPager2懒加载Fragment,不用到的Fragment不主动加载。
- 合理使用RecycleView的回收复用机制,控制Item预加载个数。
- 合理使用布局控件,合理使用ConstraintLayout,减少不必要的布局嵌套。
- 有图片的控件的View不要设置
android:background
选项,否则导致界面重叠,重绘造成界面卡顿。