Android作为移动设备,无论是内存还是CPU性能都逊色于PC设备,因此,我们在进行移动端应用开发时要格外注意性能优化的问题。本文主要讲述布局优化。文中大部分内容出自官方文档。
布局优化的思想很简单,就是尽量减少布局文件的层级,进而减少Android绘制时的工作量。
布局是一个安卓应用中用户体验有重要影响的因素。如果我们的应用设计了一个很糟糕的布局,将会耗费大量本就有限的内存,进而导致界面卡顿。所以我们应当知道如何改善布局,Android SDK也提供了一些工具帮助我们检查我们的布局是否合理。
布局优化的小技巧
删除布局中无用的控件和层级,并有选择的使用性能比较低的ViewGroup。
比如RelativeLayout。如果布局中既可以使用LinearLayout也可以使用RelativeLayout,那么就采用LinearLayout,这是因为比如RelativeLayout的功能比较复杂,需要花费更多的时间绘制。当然要根据实际情况进行选择,不能为了使用LinearLayout而设计嵌套很多层的布局。嵌套同样会降低性能。
配合使用< include>标签和< merge/>标签来减少布局的层级。
我们都知道使用< include>标签可以将一个指定的布局文件加载到当前的布局文件中。而我们如果配合使用< include>标签和< merge/>标签就可以达到减少布局层级的目的。比如对于如下布局layout_include.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button_01" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button_02" />
</LinearLayout>
我们只需在其他的布局文件里使用include标签就可以将上面的布局加载进来,如activity_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<include layout="@layout/merge_include" />
</LinearLayout>
不过这样做的话就有一些问题,activity_view.xml中的LinearLayout是垂直方向的,使用include标签加载进来的layout_include.xml布局中LinearLayout也是垂直方向的,因此layout_include.xml布局中垂直的LinearLayout是多余的,我们需要配合merge标签来消除这个多余的层级。只需要将layout_include.xml布局代码改写为如下所示:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button_01" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button_02" />
</merge>
这样系统就会忽略merge结点直接将两个button加载进去。
使用< ViewStub>标签,按需加载布局文件
ViewStub继承了View,它非常轻量级且宽/高都是0,因此它本身不参与任何的布局和绘制过程。ViewStub的意义在于按需加载所需的布局文件,在实际开发中,有很多布局文件在正常情况下并不会显示,比如网络异常时的界面,这个时候就没有必要在整个界面初始化的时候将其加载进来,通过ViewStub就可以做到在使用的时候再加载,提高了程序初始化时的性能。ViewStub标签的使用方法如下:
<ViewStub
android:id="@+id/view_stub"
android:layout="@layout/layout_include"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
其中layout属性对应的就是要加载的布局文件,在需要加载ViewStub中布局时,可以按照以下两种方式进行:
((ViewStub) findViewById(R.id.view_stub)).setVisibility(View.VISIBLE);
或者
View view = ((ViewStub) findViewById(R.id.view_stub)).inflate();
Hierarchy Viewer工具
Android SDK提供了一个叫Hierarchy Viewer的工具。这个工具可以帮助我们在应用运行时分析这个应用的某个布局。进而发现影响布局性能的问题所在。
我主要想说一下这个软件的使用方法:
首先可以在sdk目录下的tools文件夹里找到这个工具,名称是hierarchyviewer.bat,(android studio中应该也可以开启,不过我没找到-_-|),开启之后会发现我们已连接设备的正在运行的进程的一个列表,选择要进行检测的进程。然后会看到大概如图所示的界面:
可以看到有三块黑色的视图,最左面是布局的树形结构,右上为整个树形结构的预览图,右下是布局的轮廓,并且当我们在左边结构图中点击某一控件时,该控件会在右下方高亮显示。
当然,Hierarchy Viewer工具最强大功能在于它能够显示控件的渲染时间,具体操作为,选中某一根结点,点击上方工具栏中名为Profile Node的按钮。效果如图:
可以看到,控件上多了个带有颜色圆点,这些圆点分别代表:
- 用于测量的时间(messaure过程)
- 用于布局的时间(layout过程)
- 用于绘制的时间(draw过程)
每个圆点都有三种颜色:
- 绿色 代表该View的渲染速度至少要快于一半以上的其他参与测试的节点。例如,一个在布局位置上的绿色的圆点代表它的布局速度要快于50%以上的其他节点;
- 黄色 代表该View慢于50%以上的其他节点;
- 红色 代表该View的渲染速度比其他所有参与测试的节点都慢。
同时当我们选中某一控件时,会给出messaure过程、layout过程、draw过程所花费的时间,通过这些功能,我们就能够确定影响布局性能的罪魁祸首。接下来就是有针对性的进行优化。