Android布局优化

布局优化

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()方法能够设置一个裁剪矩形,只在这个矩形区域内的内容才能够绘制出来。这样就不会有层级嵌套了。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容