布局优化
1.布局检测方法:
1.1手机开发者模式自带的检测方式
操作路径:设置-更多设置-开发者选项-调试GPU过度绘制-显示过度绘制区域。
打开后,界面呈现多种色彩,分别是原色、浅紫色、浅绿色、浅红色、深红色。
对应嵌套层级为:无嵌套、1层嵌套、2层嵌套、3层嵌套、4层以及以上嵌套。
1.2Android Studio自带的Layout Inspector工具
操作方式:Tools -> Layout Inspector -> Choose Progress -> 进程名
点击OK后会执行布局分析,然后在工程目录下captures文件夹中生成对应的.li文件,就是布局分析的结果。
选中后展示布局分析详情,分别是三部分:View tree、Load Overlay、Propreties Table。
View tree中展示的是整体布局的树形结构。
Load Overlay中展示的是分块后的布局。
Propreties Table展示的是所选布局的属性表。
通过分析布局树形结构,可以很直观的看出嵌套层级,从而可以进行布局嵌套优化。
1.3Lint布局优化
操作方式:Analyze ->Inspect Code
执行完毕:Android -> Lint -> Performance下查看优化建议
1.4 systrace工具分析绘制性能
systrace工具位置在于sdk路径\platform-tools\systrace下面。
systrace依赖于python环境,同时目前只支持python2.0,因此要执行systrace命令需要先按照python环境。
systrace命令格式:
python systrace.py [options] [category1] [category2] ... [categoryN]
options
options | 解释 |
---|---|
-o <FILE> | 输出的目标文件 |
-t N, –time=N | 执行时间,默认5s |
-b N, –buf-size=N | buffer大小(单位kB),用于限制trace总大小,默认无上限 |
-k <KFUNCS>,–ktrace=<KFUNCS> | 追踪kernel函数,用逗号分隔 |
-a <APP_NAME>,–app=<APP_NAME> | 追踪应用包名,用逗号分隔 |
–from-file=<FROM_FILE> | 从文件中创建互动的systrace |
-e <DEVICE_SERIAL>,–serial=<DEVICE_SERIAL> | 指定设备 |
-l, –list-categories | 列举可用的tags |
category:
category 可取值:
category | 解释 |
---|---|
gfx | Graphics |
input | Input |
view | View System |
webview | WebView |
wm | Window Manager |
am | Activity Manager |
sm | Sync Manager |
audio | Audio |
video | Video |
camera | Camera |
hal | Hardware Modules |
app | Application |
res | Resource Loading |
dalvik | Dalvik VM |
rs | RenderScript |
bionic | Bionic C Library |
power | Power Management |
sched | CPU Scheduling |
irq | IRQ Events |
freq | CPU Frequency |
idle | CPU Idle |
disk | Disk I/O |
mmc | eMMC commands |
load | CPU Load |
sync | Synchronization |
workq | Kernel Workqueues |
memreclaim | Kernel Memory Reclaim |
regulators | Voltage and Current Regulators |
例子:
python systrace.py -o test.html -t 5 -b 37678 view gfx input
systrace抓取5秒的View System Graphics Input信息到test.html文件中。使用浏览器打开test.html就会展示抓取的信息。其中我们主要关注右手边Alerts栏目,这个栏目可以理解为需要优化的点。
文件中左边栏目Frames,对应的帧信息,每一个Frame对应每一帧。使用绿、黄、红三颜色来区分它们在绘制时的性能。绿色正常,黄色掉帧,红色严重掉帧。
点击每一个F,红黄两种都有对应的Alert信息,信息包含绘制的总时间,与问题的描述。
每一帧之间有不同颜色的块对应不同的操作切片。切片中Wall Duration代表执行的时间。常规情况屏幕FPS是60帧,一帧执行的总时间在1000/60 = 16.66ms,超过这个时机基本上就是有问题,因此需要额外关注。
2布局优化
2.1减少布局嵌套
布局过度绘制的原因主要是布局嵌套层级嵌套严重,主要优化的方案有:
2.1.1减少不必要的背景
一些布局的背景展示时候会被完全覆盖掉,这个时候的布局背景是多余的,如果不删除的话就会导致过度绘制。
去除window背景
默认情况下我们使用theme的时候,都会包含windowBackground属性,如下:
<item name="android:windowBackground">@color/background_material_light</item>
而如果根部局设置背景后,window的背景就是多余的,如果不删除就会导致过度绘制。因此我们要删除window背景:
<item name="android:windowBackground">null</item>
去除控件中不必要的背景
父布局中有颜色,子布局也有颜色,这样就会导致过度绘制,因此如果非必要减少一层背景颜色。
2.1.2.布局扁平化 减少布局嵌套
过度重绘的根源在于布局嵌套,因此减少布局嵌套可以有效的减少布局绘制。复杂布局时,采用RelativeLayout或者ConstraintLayout替代LinearLayout减少布局嵌套。
LinearLayout不支持复杂动效,因此要创建复杂布局的时候,会采用多层嵌套的方式完成布局。而RelativeLayout和ConstraintLayout天生支持复杂布局。因此使用RelativeLayout和ConstraintLayout不需要进行布局嵌套,因此减少了布局层级。
使用merge减少布局嵌套
include引入布局文件,merge标签减少布局层级。当xml文件以merge为根元素时,通过include引入,这样xml中的布局会引入到布局中,同时不会增加布局嵌套层级。
布局title_merge_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:gravity="center"
android:textSize="18dp"
android:text="@string/title"
android:layout_width="match_parent"
android:layout_height="80dp" />
</merge>
使用include引入:
<include layout="@layout/title_merge_layout"/>
TextView直接引用到include的父布局中,没有新增嵌套。
2.2布局重用include
将公用布局放入到一个xml文件中,通过include引入布局,这样达到布局重用的效果。
布局title_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:gravity="center"
android:textSize="18dp"
android:text="@string/title"
android:layout_width="match_parent"
android:layout_height="80dp" />
</LinearLayout>
引用:
<include layout="@layout/title_layout"/>
2.3减少第一次布局加载的时间
使用ViewStub延迟布局加载,是第一次加载的时候不会一次性加载所有的布局,从而提升界面渲染速度。
布局引用,layout属性对应延迟加载的布局
<ViewStub
android:id="@+id/viewStub"
android:layout="@layout/title_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
代码中使用:
ViewStub viewStub = (ViewStub)findViewById(R.id.viewStub);
viewStub.inflate();
这样布局就加载出来了。
自定义View中的注意点:
- 1.onDraw中不要创建临时变量,因为onDraw会被调用多次,大量的临时变量会导致内存抖动,造成频繁的GC,阻塞UI线程,导致内存卡顿。
- 2.onDraw中不能进行复杂的UI绘制(绘制时长要小于16.6ms),因此需要额外主要。
- 3.绘制层叠图片时,层叠图片会导致布局过度渲染,因此需要调用Canvas中的clipRect()方法能够设置一个裁剪矩形,只在这个矩形区域内的内容才能够绘制出来。这样就不会有层级嵌套了。