启动速度与执行效率优化项目实战(三):卡顿分析

作者:闫回
链接:https://www.jianshu.com/p/13a13d5aac49

大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能,Android系统每隔大概16.6ms发出的VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。

我们通常都会提到60fps与16ms,可是知道为何会是以程序是否达到60fps来作为APP性能的衡量标准吗?这是因为人眼与大脑之间的写作无法感知超过60fps的画面更新。

12fps大概类似手动快速翻动的帧率,这明显是可以感知到不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果,24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的减少费用支出。但是低于30fps是无法顺畅表现绚丽的画面内容的,此时就需要用到60fps来达到想要的效果,当然超过60fps是没有必要的。

开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms=1000/60的时间来处理所有的任务。

如果某个操作花费时间是24ms,系统在得到VSYNV信号的时候就无法进行正常渲染,这样就发生了丢帧现象,那么用户在32ms内看到的会是同一帧画面。

有很多原因可以导致丢帧,一般主线程过多的UI绘制、大量的IO操作或是大量操作占用CPU,都会导致App界面卡顿。

更详细的描述请参考Android图形显示系统https://blog.csdn.net/a740169405/article/details/70548443

卡顿分析工具CPU Profile介绍

最基本的介绍参考官网https://developer.android.google.cn/studio/profile/cpu-profiler
实际的操作中如何使用呢,如果你发现你的某个操作有点卡顿,这时候你就可以使用这个工具进行查找原因,先点击cpu profile按钮,这时候有两种配置方式

img

选择记录配置.png

Sample Java Methods
对Java方法采样:在应用的Java代码执行期间,频繁捕获应用的调用堆栈,分析器会比较捕获的数据集,以推导与应用的Java代码执行有关的时间和资源使用信息。如果应用在捕获调用堆栈后进入一个方法并在下次捕获前退出该方法,分析器将不会记录该方法调用。如果您想要跟踪生命周期如此短的方法,应使用检测跟踪。
Trace Java Methods
跟踪 Java 方法:在运行时检测应用,以在每个方法调用开始和结束时记录一个时间戳。系统会收集并比较这
些时间戳,以生成方法跟踪数据,包括时间信息和 CPU 使用率。
可以根据自己的需要进行选择,然后我们点击Record进行记录,这时候我们进行手机上面的操作,当操作完成后点击 Stop recording,这时候就会生成对应的跟踪信息

img

跟踪信息

然后我们可以进行分析,逐步排查卡顿的原因。
还有一种方式可以生成对应的跟踪信息,在开始记录的位置使用startMethodTracingSampling(String tracePath, int bufferSize,int intervalUs)进行采样
,三个参数代表生成trace文件的位置,文件大小还有采样的时间间隔
或者startMethodTracing(String tracePath, int bufferSize, int flags)进行跟踪,
三个参数代表生成trace文件的位置,文件大小还有一个标志设置,bufferSize参数指定了trace文件的最大值。Trace信息可以使用很多空间,你的存储器可能是有限的,所以尝试去使用一个可接受的值(默认8M)。安卓现在只定义一个标志,Debug.TRACE_COUNT_ALLOCS.
设置了之后我们就可以在对应的位置找到trace文件,使用AS工具打开进行问题查找了。

布局优化

层级优化
使用Layout Inspector

img

Layout Inspector工具.png

然后选择需要查看的进程与Activity:

img

布局检查器.png

Layout Inspector主要用来分析布局的层级结构,减少不必要的层级,更加详细的介绍参考官网https://developer.android.google.cn/studio/debug/layout-inspector?hl=zh_cn

使用merge标签

merge标签是用来帮助在视图树中减少重复布局的,当某个layout布局被多次引用时,可以使用merge,减少嵌套
可参考文章https://blog.csdn.net/a740169405/article/details/50473909

使用ViewStub标签

当我们布局中存在一个View/ViewGroup,在某个特定时刻才需要它的展示时,可能会使用gone或者invisible,在需要显示时再设置visible可见。
viewStub是一个轻量级的view,它不可见,不用占用资源,只有设置viewstub为visible或者调用其inflater()方法时,其对应的布局文件才会被初始化。
可参考详细的文章https://blog.csdn.net/a740169405/article/details/50351013

过度渲染

过度渲染是指系统在渲染单个帧的过程中多次在屏幕上绘制某一个像素,例如,如果我们有若干界面卡片堆叠在一起,每张卡片都会遮盖其下面一张卡片的部分内容,但是,系统仍然需要绘制堆叠中的卡片被遮盖的部分。
GPU过度绘制检查
手机开发者选项中能够显示过度渲染检查功能,通过对界面进行彩色编码来帮我们识别过度绘制,开启步骤如下:
1.进入开发者选项
2.找到调试GPU过度绘制
3.在弹出的对话框中,选择显示过度绘制区域
Android 将按如下方式为界面元素着色,以确定过度绘制的次数:

img

参考过度绘制.png

更加详细的介绍参考官网https://developer.android.google.cn/topic/performance/rendering/inspect-gpu-rendering?hl=zh_cn

解决过度绘制问题

可以通过以下方法来减少过度绘制
1.移除布局中不需要的背景
默认情况下,布局没有背景,这表示布局本身不会直接渲染任何内容,但是当布局具有背景时,其有可能会导致过度绘制
移除不必要的背景可以快速提高渲染性能,不必要的背景可能永远不可见,因为它会被在该视图上绘制的任何其他内容完全覆盖,例如,当系统在父视图上绘制子视图时,可能会完全覆盖父视图的背景。
2.使视图层次结构扁平化
可以通过优化视图层次结构来减少重叠界面对象的数量,从而提高性能。
3.降低透明度
对于不透明的view,只需要渲染一次就可以显示出来,但是如果这个view设置了alpha值,则至少需要渲染两次,这是因为使用了alpha的view需要先知道混合view的下一层元素是什么,然后再结合上层的view进行混色处理。透明动画、淡入淡出和阴影等都涉及到某种透明度,这就会造成了过度绘制。可以通过减少要渲染的透明对象的数量,来改善这些情况下的过度绘制,例如,如需获得灰色文本,可以在TextView中绘制黑色文本,再为其设置半透明的透明度值,但是,简单地通过用灰色绘制文本也能获得同样的效果,而且能够大幅提升性能。

布局加载优化

LayoutInflater加载xml布局的过程会在主线程使用IO读取XML布局文件进行XML解析,再根据解析结果利用反射 创建布局中的View/ViewGroup对象。这个过程随着布局的复杂度上升,耗时自然也会随之增大。Android为我们 提供了 Asynclayoutinflater 把耗时的加载操作在异步线程中完成,最后把加载结果再回调给主线程。
dependencies {
implementation "androidx.asynclayoutinflater:asynclayoutinflater:1.0.0"
}
new AsyncLayoutInflater(this)
.inflate(R.layout.activity_main, null, new AsyncLayoutInflater.OnInflateFinishedListener() { @Override
public void onInflateFinished(@NonNull View view, int resid, @Nullable ViewGroup parent) {
setContentView(view);
//......
} });
1、使用异步 inflate,那么需要这个 layout 的 parent 的 generateLayoutParams 函数是线程安全的; 2、所有构建的 View 中必须不能创建 Handler 或者是调用 Looper.myLooper;(因为是在异步线程中加载的,异
步线程默认没有调用 Looper.prepare );
3、AsyncLayoutInflater 不支持设置 LayoutInflater.Factory 或者 LayoutInflater.Factory2; 4、不支持加载包含 Fragment 的 layout
5、如果 AsyncLayoutInflater 失败,那么会自动回退到UI线程来加载布局

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能,Android系统每隔大概16.6ms发出的VSYN...
    闫回阅读 976评论 0 7
  • 布局可以说是APP最重要的一项了,用户感知极强,无论你的代码写的如何,用户也不知道,用户只能看到和操作APP,更漂...
    进击的包籽阅读 786评论 0 8
  • 大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。Android系统每隔大概16.6ms发出VSYNC...
    zcwfeng阅读 511评论 0 2
  • 大多数用户感知到的卡顿等性能问题主要原因都是因为渲染性能。 Android 系统每隔大概16.6毫秒(1000ms...
    初夏的雪阅读 966评论 0 3
  • 推荐指数: 6.0 书籍主旨关键词:特权、焦点、注意力、语言联想、情景联想 观点: 1.统计学现在叫数据分析,社会...
    Jenaral阅读 5,716评论 0 5