应用UI卡顿常见原因
1. 布局Layout 复杂,无法在16ms内渲染完成,布局层次不合理,布局存在过度绘制
2. 同一时间动画执行的次数过多,导致CPU或GPU负载过重
3. 冗余资源及逻辑等导致加载和执行缓慢
4. 过度绘制
应用UI卡顿分析
1. Hierarchy Viewer
Hierarchy Viewer 是 Android Device Monitor 中内置的一种工具,可让您测量布局层次结构中每个视图的布局速度。它可以帮助您查找由视图层次结构导致的性能瓶颈。
可以通过以下数据进行优化布局
渲染出该布局所需的时间
Measure:0.107 ms 测量
Layout:0.000 ms 布局
Draw:1.650 ms 绘制
- 绿色:表示视图的渲染速度至少比一半的其他视图快。
- 黄色:表示视图的渲染速度至少比一半的其他视图快。
- 红色:表示视图是渲染速度最慢的那一半视图之一。
如果应用的运行速度出乎意料地慢,则红色节点可能有问题。
以下是对红色圆点的解读
- 查找叶节点中的红色圆点或仅包含少数子级的视图组。可能会找到问题所在。应用的运行速度可能并不缓慢,或者在设备上的运行速度并不慢,需要注意这个圆点为何显示为红色。Systrace
或 Traceview 可以提供更多信息。- 如果您有一个包含许多子级的视图组和一个红色测量阶段,请查看相应子级以了解它们的执行情况。
- 带有黄色甚或红色圆点的视图在设备上的执行速度可能并不慢。这正是实际数字的用武之地。Systrace 或 Traceview 可以提供更多信息。
- 如果层次结构的根视图具有红色测量阶段、红色布局阶段和黄色绘制阶段,那这就是一个比较典型的情况,因为它是所有其他视图的父级,并且只有在子级完成之后其布局才会完成。
- 如果具有 20 个以上视图的树中的某个叶节点包含红色绘制阶段,则表示存在问题。请检查 onDraw() 方法中是否有不应存在的代码。
2. Lint
可以来搜索可能的视图层次结构优化机会。
- 使用复合可绘制对象 - 包含 ImageView 和 TextView 的 LinearLayout
作为复合可绘制对象可得到更加高效的处理。
- 合并根框架 - 如果 FrameLayout
是一个布局的根,并且未提供背景或内边距等信息,则可以将其替换为稍微高效一些的 merge 标记。 - 无用的叶项 -
没有子级或没有背景的布局通常可以移除(因为它不可见),以使布局层次结构更加扁平高效。 - 无用的父级 - 如果一个布局含有子级但没有同级、不是
ScrollView 或根布局且没有背景,则可以将其移除或将其子级直接移动到父级,以使布局层次结构更加扁平高效。 - 深层布局 -
嵌套过多的布局会降低性能。考虑使用 RelativeLayout 或 GridLayout 等比较扁平的布局来提高性能。默认的深度上限为 10。 - 移除多余的嵌套布局-
3. Layout Inspector
Layout Inspector 可用来分析View树层级
4. 通过标记重复使用布局
尽管 Android 通过各种微件来提供可重复使用的小型互动元素,但可能还需要重复使用需要特殊布局的大型组件。为了高效地重复使用完整的布局,可以使用 <include/> 和 <merge/>
标记在当前布局中嵌入其他布局。
5. 视图加载延迟
通过仅需要时加载视图来减少内存使用量并加快渲染速度。
- 定义ViewStub
ViewStub 是一种没有任何维度的轻量型视图,它不会绘制任何内容或参与布局。因此,扩充和离开视图层次结构的成本比较低。每个 ViewStub 只需包含 android:layout 属性即可指定要扩充的布局。
以下ViewStub 适用于半透明进度条叠加层,只有当新的项目导入应用时,它才会显示。
<ViewStub
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
- 加载ViewStub 布局
findViewById(R.id.stub_import).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
6. 解决过度绘制
- 移除布局中不需要的背景
- 使视图层级结构扁平化
- 降低透明度