进行Android应用开发时,界面布局也会对应用程序的性能产生比较大的影响,如果布局写得糟糕的话,那么程序加载UI的速度就会非常慢,从而造成不好的用户体验。因此,写出更高效、更优雅的布局是非常重要的。那么本篇文章我们就来学习一下,如何通过优化布局来提高应用程序的性能。
首先第一点:重用布局文件,减少不必要的代码。
有些时候我们可能需要反复利用某个已经写好的布局,如果你重复写这部分代码一方面是没有任何意义,另一方面会提高维护的难度。而Android当然也已经充分考虑到了布局重用的重要性,于是提供了include和merge这两个非常有用的标签:
include
include 标签可以允许在一个布局当中引入另外一个布局,那么比如说我们程序的所有界面都有一个公共的部分,这个时候最好的做法就是将这个公共的部分提取到一个独立的布局文件当中,然后在每个界面的布局文件当中通过使用include来引用这个公共的布局。这样既提高了我们的工作效率,也会给程序更好的可维护性和更好的性能。
例如APP中每个界面都有一个头部(包括两个按钮,标题)时,加入每个界面我们都写上同样的布局,这会加大我们的工作量,同时进行的也是一些没有什么意义的重复性工作,如果需要改动头部时,可维护性也是极差。这个时候就可以将头部抽离出来,写成一个独立的头部XML文件,然后通过<include>标签引入到每一个布局文件中:头部文件如下所示
当其他界面需要用到这个头部时,我们要做的非常简单,比如activity_main2.xml中要用到只需要这样写,如下所示:
标签当中可以指定一个layout属性,我们在这个layout属性中填写需要引入的布局名就可以了。而且使用这种引入的方式,以后如果titlebar的界面有所变更,我们只需要修改titlebar_layout.xml这一个文件就可以了,而不是所有界面一个个地去修改。到这里不知道你有没有发现问题?仔细看看上方的图片哟!你会发现 布局文件中的 “您好”不见了,并没有在界面中呈现出来,为什么呢?你再往回看看头部文件就知道了。
出现这个问题是原因是因为titlebar_layout的最外层布局是一个宽高都是match_parent的RelativeLayout,它会将整个布局都填充满,因而我们原本的布局也就看不见了。那既然问题的原因清楚了,相信你立刻就想到应该怎么修改了,将RelativeLayout的layout_height属性修改成wrap_content不就可以了嘛。没错,这样修改当然是没问题的,不过这种修改方式会让所有引用titlebar_layout的界面都受到影响,而如何你只希望让activity_main2.xml这一个界面受影响的话,那么可以使用覆写属性的方式。
在标签当中,我们是可以覆写所有layout属性的,即include中指定的layout属性将会覆盖掉titlebar_layout中指定的layout属性,可以看到这样修改后,界面显示就正常啦。
除了layout_height之外,我们还可以覆写任何一个layout属性,如layout_gravity、layout_margin等,而非layout属性则无法在标签当中进行覆写。另外需要注意的是,如果我们想要在标签当中覆写layout属性,必须要将layout_width和layout_height这两个属性也进行覆写,否则覆写效果将不会生效。
第二点:使用merge标签减少布局嵌套。
merge
<merge>在标签中的控件自身没有布局属性,默认会继承父控件的布局属性。它的主要作用是为了防止在引用布局文件时产生多余的布局嵌套。大家都知道,Android去解析和展示一个布局是需要消耗时间的,布局嵌套的越多,那么解析起来就越耗时,性能也就越差,因此我们在编写布局文件时应该让嵌套的层数越少越好。
上方所说的include标签有好处,但也会有不足,就是可能会让布局的嵌套层级变得更复杂更多。比如我们写一个布局,如下所示:
然后将这个布局使用include标签引入到Activity中去。
看上去是不是感觉没有什么问题?是滴,看着确实没问题,但实际上已经存在了多余的嵌套了。
很容易看到,最外层首先是一个FrameLayout,不知道为什么最外层是FrameLayout的朋友可以去查看一下(系统自动添加的)。然后FrameLayout中包含的是一个LinearLayout,这个就是我们最外层的布局(activity_main3.xml)。接下来的部分就有问题了,在最外层的LinearLayout当中包含了两个元素,一个是EditText,另一个又是一个LinearLayout,然后在这个内部的LinearLayout当中才包含了两个按钮。
其实,这个内部的LinearLayout就是一个多余的布局嵌套,实际上并不需要这样一层,让两个按钮直接包含在外部的LinearLayout当中就可以了。而这个多余的布局嵌套其实就是由于布局引入所导致的,因为我们在引入的布局文件中也定义了一个LinearLayout。此时使用merge标签来优化,修改another.xml中的代码,如下所示:
此时的层级为:
其实这里我们只是将根布局换成merge标签,这就表示当有任何一个地方通过include引入这个布局时,会将merge标签内包含的内容直接填充到include的位置,而且不会再添加任何额外的布局结构,有效的减少了布局的嵌套。
第三点:合理使用style文件,定义各个控件的通用属性,减少重复代码。
比如文字的属性设置、布局属性设置等:
然后直接使用就ok了。
第四点:使用ViewStub来完成那些只需要在特定情况下显示的布局。
项目中有时候会有这样一种需求,当满足某某某条件的时候,就会显示某一个东西(布局),不满足时则将其隐藏。看到这种需求可能马上就会想到使用属性INVISIBLE或者GONE进行隐藏,然后当用户需要使用这些元素的时候再把它们置成VISIBLE显示出来。这种方式确实可以实现我们想要的效果,虽然简单但是这种方式的性能就很一般了,使用这种方式虽然隐藏了布局,但是它们实际上是存在布局当中的,它们的属性也都是存在的,在解析布局的时候同样会将它们解析出来,系统在加载布局的时候这一部分还是会将其绘制出来,同样花费绘制时间,而我们却不需要,这就一定程度上影响了我们的性能。怎么解决呢?
Android为此给我们提供了一种非常轻量级的控件——懒加载布局ViewStub。ViewStub虽说也是View的一种,但是它没有大小,没有绘制功能,也不参与布局,资源消耗非常低,将它放置在布局当中基本可以认为是完全不会影响性能的。使用方式如下:
在布局文件中使用ViewStub来加载需要隐藏的布局:
然后在需要显示的时候,如下调用
ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);
if (null != viewStub) {
//主要是这一句显示更多布局
View view = viewStub.inflate();
//布局文件中的控件
EditText name1 = (EditText) view.findViewById(R.id.et_name1);
}
这样就实现效果了。另外需要提醒大家注意的一点是:
ViewStub所加载的布局是不可以使用<merge>标签的,因此这有可能导致加载出来的布局存在着多余的嵌套结构,这种情况下我们需要合理取舍,而对于那些隐藏的布局文件结构相当复杂的情况,使用ViewStub还是一种相当不错的选择的,即使增加了一层无用的布局结构,仍然还是利大于弊。
第五点:合理使用分割线布局
我们在写布局的时候,有时候需要写分割线来进行上下的隔离,我们通常会用<view />组件来绘制出分割线,如下所示:
其实我们可以使用 LinearLayoutCompat(v7包中的) 组件来实现线性布局元素之间的分割线,从而减少了使用View来实现分割线效果。
LinearLayoutCompat其实就是LinerLayout组件,只是为了兼容低版本,所以你必须引用 v7包下面的LinearLayoutCompat。 LinearLayoutCompat除了拥有LinerLayout原本的属性之外,主要通过如下几种属性来实现 间隔线效果:
app:divider=”@drawable/line” 给分隔线设置颜色,这里你需要在drawable中去定义shape资源,否则将没有效果。看下面
app:dividerPadding=”20dp” 给分隔线设置距离左右边距的距离。
app:showDividers=”middle|beginning|end” 分隔线显示的位置,有四种参数值:middle指在 每个item之间,beginning 指在最顶端显示分隔线,end 指在最底端显示分隔线,none则代表不显示间隔线。
组件距离分割线的距离在组件中设置就好了。
注意 这三个属性需要使用 xmlns:app=”http://schemas.android.com/apk/res-auto” 命名空间。
下面我们来看看效果:
到这我们对布局的优化就已经差不多了,还有一点就是我们可以合理的减少LinearLayout,更多的使用RelativeLayout来进行界面布局,这样可以减少许多不必要的层级。
最后感谢大家能看到这,希望能带给大家帮助!我们下次再见!
参考文档:http://blog.csdn.net/guolin_blog/article/details/43376527
参考文档:http://blog.csdn.net/feiduclear_up/article/details/46670433