如何优化Android layout(UI)性能

在Android layout中的各种问题一直是让人很头疼。其中,我们只要稍微不留神,自己设计的layout在性能上的表现总会不尽人意。

悲剧回顾:

记得之前有一个项目,前期的layout设计几乎到处都是里三层外三层的各种嵌套。这样的布局实现效果与美工的效果图虽然相差无几,但到了后期,令人难以接受的悲剧发生了——一些配置较低的手机只要运行在layout嵌套较深的界面上,总会出现卡顿现象,若有输入控件,激活输入法时,也会引起程序crash……

悲剧之由来:

我们得始终坚信:有果必有因。

1. 初学时养成的潜意识:不考虑性能,先看效果。大家可能是这样学习的,想快点掌握其实现方法,性能或优化等方面的问题,留着以后再考虑。可是,何时才是“以后”呢?

2. 没有深入理解各种layout运用:怎么方便就怎么来,例如使用LinearLayout进行多层嵌套即可轻松实现复杂的布局。

3. 没太留意用户体验感受:随着时间推移,手机配置越来越高,人们已经很难从感知上去判别layout的加载速度会带来什么样的体验。有时候,即使能感觉到有一点点的有问题,也会轻易放过自己:没关系。

4. 有意识,但不熟悉优化:有时候知道会有问题,但不知道如何判断其优劣,不清楚如何下手,缺少思路与方法等。

Layout优化大致思路:

1. 尽可能消耗较少的系统资源:包括时间,内存,电量等。

2. 尽可能流畅,不给人卡顿,加载慢,等待时间过长,干等无操作的尴尬体验等。

如何对症下药?

我们大概清楚上述的因果后,就得对具体案例进行对症下药,加深理解,进而举一反三。这回我们不能为所欲为了!

那么如何优化呢?下面是一个简单的例子,演示优化步骤及思路:

1. 优化前的一个3层级的layout:
nested_layout.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:id= "@+id/LinearLayout1"
     android:layout_width= "match_parent"
     android:layout_height= "match_parent"
     android:orientation= "vertical"
     android:paddingBottom= "@dimen/activity_vertical_margin"
     android:paddingLeft= "@dimen/activity_horizontal_margin"
     android:paddingRight= "@dimen/activity_horizontal_margin"
     android:paddingTop= "@dimen/activity_vertical_margin" >
 
     <LinearLayout
         android:layout_width= "match_parent"
         android:layout_height= "wrap_content"
         android:gravity= "center" >
 
         <TextView
             android:id= "@+id/account"
             android:layout_width= "wrap_content"
             android:layout_height= "60dp"
             android:gravity= "center_vertical"
             android:text= "账号:" />
 
         <EditText
             android:id= "@+id/accountInput"
             android:layout_width= "200dp"
             android:layout_height= "60dp"
             android:gravity= "center_vertical"
             android:hint= "请输入账号" />
     </LinearLayout>
 
     <LinearLayout
         android:layout_width= "match_parent"
         android:layout_height= "60dp"
         android:gravity= "center" >
 
         <TextView
             android:id= "@+id/pwd"
             android:layout_width= "wrap_content"
             android:layout_height= "60dp"
             android:gravity= "center_vertical"
             android:text= "密码:" />
 
         <EditText
             android:id= "@+id/pwdInput"
             android:layout_width= "200dp"
             android:layout_height= "60dp"
             android:gravity= "center_vertical"
             android:hint= "请输入6位以上的密码" />
     </LinearLayout>
 
</LinearLayout>

其实,在手机上运行这个layout,我们的感官并不能觉察到有什么不妥或不好的体验。所以,我们得通过第三方工具Hierarchy View查看其性能参数:

从上图很直观地看到:这是一个4层级的layout;在id为content的节点上读取其性能数据:
Measure:0.562ms
Layout:0.287ms
Draw:2.212ms

同时,也计算了一下setContentView(R.layout.nested_layout)的时间:42ms

logcat
1
06 -16 15: 21: 35.869: D/MainActivity( 4739 ): setContentView(R.layout.nested_layout), takeTime: 42 ms

计算代码如下:

MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static final String TAG = "MainActivity" ;
 
private long start = 0 ;
 
private long takeTime = 0 ;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
     super .onCreate(savedInstanceState);
 
     start = System.currentTimeMillis();
 
     setContentView(R.layout.nested_layout);
 
     takeTime = System.currentTimeMillis() - start;
 
     Log.d(TAG, "setContentView(R.layout.nested_layout), takeTime:" + takeTime + "ms" );
 
}

就是这么一个简单的UI布局,上面的性能指示器就有3个为红色,暂且(在没有对比之前)认为效果并不是很好。
具体分析:
1. 这里使用了3个容器(LinearLayout),都是用于控制子元素的显示方向;
2. 想想上面的优化思路,尽可能减少时间,内存的开销:在实现同样效果的情况下,容器越多,加载实例化容器,计算,布局,绘制的操作相应地会消耗更多的时间与内存。
3. 如果我们使用较少的容器实现一样的效果,这不就是优化性能了吗?
4. 我们的RelativeLayout不就可以做得到吗?

2. 采用RelateLayout优化后的layout
optimized_layout.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:id= "@+id/LinearLayout1"
     android:layout_width= "match_parent"
     android:layout_height= "match_parent"
     android:orientation= "vertical"
     android:paddingBottom= "@dimen/activity_vertical_margin"
     android:paddingLeft= "@dimen/activity_horizontal_margin"
     android:paddingRight= "@dimen/activity_horizontal_margin"
     android:paddingTop= "@dimen/activity_vertical_margin" >
 
     <RelativeLayout
         android:layout_width= "match_parent"
         android:layout_height= "wrap_content"
         android:gravity= "center" >
 
         <TextView
             android:id= "@+id/account"
             android:layout_width= "wrap_content"
             android:layout_height= "60dp"
             android:layout_alignParentLeft= "true"
             android:gravity= "center_vertical"
             android:text= "账号:" />
 
         <EditText
             android:id= "@+id/accountInput"
             android:layout_width= "200dp"
             android:layout_height= "60dp"
             android:layout_toRightOf= "@id/account"
             android:gravity= "center_vertical"
             android:hint= "请输入账号" />
 
         <TextView
             android:id= "@+id/pwd"
             android:layout_width= "wrap_content"
             android:layout_height= "60dp"
             android:layout_below= "@id/account"
             android:gravity= "center_vertical"
             android:text= "密码:" />
 
         <EditText
             android:id= "@+id/pwdInput"
             android:layout_width= "200dp"
             android:layout_height= "60dp"
             android:layout_below= "@id/accountInput"
             android:layout_toRightOf= "@id/pwd"
             android:gravity= "center_vertical"
             android:hint= "请输入6位以上的密码" />
     </RelativeLayout>
 
</LinearLayout>

同样使用工具查看:

很明显,我们减少了一个容器,其中的2个LinearLayout被一个RelateLayout代替,性能指示器也没有出现红色。在同样的节点处性能参数如下:
Measure:0.443ms
Layout:0.060ms
Draw:1947ms

同样,计算setContentView(R.layout.optimized_layout)花费的时间:36ms

各指标都比原来提高了。

事情还没完,是不是总觉得夹在FrameLayout与RelateLayout之间的LinearLayout有点多余呢?我RelateLayout干嘛要经过你LinearLayout呢,如果真的非要经过你,你能说说你在这里的有用之处吗?

3. 去除没必要层级:

再请来一个大神对第2步的layout进行检查与评判——Lint:


从上图红圈中的提示内容可知:id为LinearLayout1的容器是没有必要存在的。所以这次的优化得去掉这没必要的层级。

optimized_removed_useless_linearlayout.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android"
  android:layout_width= "match_parent"
  android:layout_height= "wrap_content"
  android:gravity= "center"
  android:paddingBottom= "@dimen/activity_vertical_margin"
  android:paddingLeft= "@dimen/activity_horizontal_margin"
  android:paddingRight= "@dimen/activity_horizontal_margin"
  android:paddingTop= "@dimen/activity_vertical_margin" >
 
<TextView
  android:id= "@+id/account"
  android:layout_width= "wrap_content"
  android:layout_height= "60dp"
  android:layout_alignParentLeft= "true"
  android:gravity= "center_vertical"
  android:text= "账号:" />
 
<EditText
  android:id= "@+id/accountInput"
  android:layout_width= "200dp"
  android:layout_height= "60dp"
  android:layout_toRightOf= "@id/account"
  android:gravity= "center_vertical"
  android:hint= "请输入账号" />
 
<TextView
  android:id= "@+id/pwd"
  android:layout_width= "wrap_content"
  android:layout_height= "60dp"
  android:layout_below= "@id/account"
  android:gravity= "center_vertical"
  android:text= "密码:" />
 
<EditText
  android:id= "@+id/pwdInput"
  android:layout_width= "200dp"
  android:layout_height= "60dp"
  android:layout_below= "@id/accountInput"
  android:layout_toRightOf= "@id/pwd"
  android:gravity= "center_vertical"
  android:hint= "请输入6位以上的密码" />
 
</RelativeLayout>

再看层级图:

清楚地看到,性能指示器一片绿,相比于优化前:我们原来需要解掉3件“衣服”,现在只需要解掉一件就可以看到你想要的,你说这速度能不快吗?到此,前面的暂且可以去掉了!

小结:

1. 性能指示器,优化layout的参考方向。

2. 有效利用Lint工具,进行优化,他不仅仅应用于layout的优化,还包括code的优化,总之其功能非常强大!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值