性能优化之布局文件优化

作者:华清远见讲师

随着android手机的迅速发展以及技术的更新,市场对应用的性能提出了更高的要求,android图形界面是用户最直接的感受渠道,因此做好UI界面的设计日益重要。而其实相同的布局效果可以有不同的实现方式。糟糕的布局会使程序加载UI的速度非常慢,从而降低了用户体验满意度,同时也对程序的性能产生比较大的影响,因此优化布局是提高性能的一种重要途径,以下从三方面讲述布局的三重优化。

第一重优化:布局中样式的抽取

布局文件中,系统给我们提供了很多控件的属性,我们可以方便的使用,但有时在同一个布局中甚至不同的布局中会重复出现同一个控件并且其属性设置相似,这时如果我们重复的单个定义相同控件的属性会使布局代码显得庞大冗杂,减低了布局文件的可读性同时开发的效率和程序性能也会受很大的影响,这就需要我们将相同控件的相同属性抽取出来做成样式模板。

举例1:

同一个布局或不同布局文件中常常会用到控件显示文字比如TextView,Button等,而这时候对于控件的大小及显示的文字的大小和颜色等要求又是相同的,这时我们就可以将这些相同的属性抽取出来。如下图布局是一个简单的LinearLayout布局中的三个控件中间一个Button,两边各一个TextView,看代码不难发现他们的尺寸,背景,和字体大小颜色都是相同的,这时我们则可以抽取出来。


将控件相同的样式抽取到values文件夹下的style.xml文件中如下图红色圈住部分:


抽取之后,布局文件中我们只需引入此样式即可,如果其他控件有个别属性不同,则只需在布局文件中重写此属性,系统会自动将布局文件中的属性覆盖抽取出的style属性,如下图:

此时布局则大大简化,效果则完全相同,如下图:


第二重优化:布局文件复用

布局文件的复用思想和样式抽取的思想是相同的,都是将相同的东西抽取出来以达到可以重复利用的目的。当然Android也已经充分考虑到了布局重用的重要性,于是提供了和这两个非常有用的标签,让我们更方便的实现代码复用。

1.include

标签可以允许在一个布局当中引入另外一个布局,那么比如说我们程序的所有界面都有一个公共的部分,这个时候最好的做法就是将这个公共的部分提取到一个独立的布局文件当中,然后在每个界面的布局文件当中来引用这个公共的布局。

举例2:我们应该都知道,目前几乎所有的软件都会有一个头布局,头布局中可以包含界面的标题、返回按钮、以及其它一些操作功能等。那这样的一个头布局,有些软件是使用ActionBar来实现的,但是由于ActionBar的灵活性不太好,因而也有很多软件会选择自己去编写实现。那如果自己去实现的话,由于这个头布局是在所有界面都要使用的,显然我们不可能在每个界面当中都去写一遍这个头布局的代码,因此这种情况下使用标签就非常合适了。这里为了给大家演示一下,我就编写一个非常简单的头布局,在res/layout文件夹中新建titlebar.xml作为头布局,代码如下所示:

titlebar.xml中的布局非常简单,外层RelativeLayout里面只有两个Button和一个TextView,左边Button用于实现返回功能,右边的Button用于实现完成功能,中间的TextView则可以用于显示当前界面的标题。我们可以来预览一下titlebar的样子,如下图所示:

titlebar的布局写完,接下来就可以对布局文件进行复用了,无论任何界面需要加入titlebar这个功能,只需要在布局文件中引入titlebar.xml就可以了。比如我们的程序当中有一个activity_main.xml文件,现在想要引入titlebar,布局文件只需要这样写:

这样就非常简单,一行include语句就搞定了,而无需重复写titlebar里的布局。标签当中可以指定一个layout属性,我们在这个layout属性中填写需要引入的布局名就可以了。而且使用这种引入的方式,以后如果titlebar的界面有所变更,我们只需要修改titlebar.xml这一个文件就可以了,而不是所有界面一个个地去修改。但需要注意的是虽然titlebar是成功引入了,但是我们activity_main.xml中本来的界面全部都不见了!出现这个问题的原因是因为titlebar的最外层布局是一个宽高都是match_parent的RelativeLayout,它会将整个布局都填充满,因而我们原本的布局也就看不见了。那既然问题的原因清楚了,相信你立刻就想到应该怎么修改了,将RelativeLayout的layout_height属性修改成wrap_content不就可以了嘛。没错,这样修改当然是没问题的,不过这种修改方式会让所有引用titlebar的界面都受到影响,而如何你只希望让activity_main.xml这一个界面受影响的话,那么可以使用覆写属性的方式。

在标签当中,我们是可以覆写所有layout属性的,即include中指定的layout属性将会覆盖掉titlebar中指定的layout属性。因此,这里我们希望将titlebar的高度设置成wrap_content,就可以这样写:

这时重新运行一下则是可以正常显示titlebar之外的其他内容的。


除了layout_height之外,我们还可以覆写titlebar中的任何一个layout属性,如layout_gravity、layout_margin等,而非layout属性则无法在标签当中进行覆写。另外需要注意的是,如果我们想要在标签当中覆写layout属性,必须要将layout_width和layout_height这两个属性也进行覆写,否则覆写效果将不会生效。

2.<merge>

标签是作为标签的一种辅助扩展来使用的,他的主要作用是为了防止在引用布局文件时产生多余的布局嵌套。Android去解析和展示一个布局是需要消耗时间的,布局嵌套越多解析起来越是耗时,性能也就越差,因此我们在编写布局文件时应该让嵌套的层数越少越好。

有优点,但是它也存在着一个不好的地方,就是可能会导致产生多余的布局嵌套。这里还是通过举例的方式跟大家说明一下,比如说我们需要编写一个确定取消按钮的公共布局,这样任何一个界面需要确定和取消功能时就不用再单独编写了,新建ok_cancel_layout.xml,代码如下所示:

可以看到,这个界面也是非常简单,外层是一个水平方向LinearLayout,LinearLayout中包含了两个按钮,一个用于实现确定功能,一个用于实现取消功能。现在我们可以来预览一下这个界面,如下图所示:


然后我们有一个profile.xml的界面需要编辑一些内容,那么这里就可以将ok_cancel_layout这个布局引入到profile.xml界面当中,如下所示:


运行效果如图:


这个看上去并没有什么不对,可是在你毫无察觉的情况下,目profile.xml这个界面当中其实已经存在着多余的布局嵌套了!感觉还没写几行代码呢,怎么这就已经有多余的布局嵌套了?我们可以通过View Hierarchy工具来查看一下,如下图所示:

可以看到,最外层首先是一个FrameLayout,然后FrameLayout中包含的是一个LinearLayout,这个就是我们在profile.xml中定义的最外层布局。接下来的部分就有问题了,在最外层的LinearLayout当中包含了两个元素,一个是EditText,另一个又是一个LinearLayout,然后在这个内部的LinearLayout当中才包含了确定和取消这两个按钮。这个内部的LinearLayout就是一个多余的布局嵌套,实际上并不需要这样一层,让两个按钮直接包含在外部的LinearLayout当中就可以了。而这个多余的布局嵌套其实就是由于布局引入所导致的,因为我们在ok_cancel_layout.xml中也定义了一个LinearLayout。那么应该怎样优化掉这个问题呢?当然就是使用标签来完成了,修改ok_cancel_layout.xml中的代码,如下所示:

可以看到,这里我们将ok_cancel_layout最外层的LinearLayout布局删除掉,换用了标签,这就表示当有任何一个地方去include这个布局时,会将标签内包含的内容直接填充到include的位置,不会再添加任何额外的布局结构。好的,的用法就是这么简单,现在重新运行一下程序,你会看到界面没有任何改变,然后我们再通过View Hierarchy工具来查看一下当前的View结构,如下图所示:

第三重优化:仅在需要时才加载布局

有的时候我们会遇到这样的场景,就是某个布局当中的元素非常多,但并不是所有元素都一起显示出来的,而是普通情况下只显示部分常用的元素,而那些不常用的元素只有在用户进行特定操作的情况下才会显示出来。

这里举个大家都非常熟悉的例子,我们在添加联系人的时候其实可以编辑的字段真的非常多,姓名、电话、email、传真、住址、昵称等等等等,但其实基本上大家最常用的就是填一个姓名,填一个电话而已。那么将这么多繁杂的字段都一起显示在界面上其实并不是一种很好的做法,因为大多数人都是用不到这些字段的。比较聪明的做法就是把最常用的姓名和电话显示在界面上,然后给用户提供一个添加更多字段的选项,当用户真的有需要去添加其它信息的时候,我们才将另外的元素显示到界面上。

说到实现这样一个功能,我相信大多数人的第一反应就是将不常用的元素使用INVISIBLE或者GONE进行隐藏,然后当用户需要使用这些元素的时候再把它们置成VISIBLE显示出来。使用这种方式肯定可以实现功能的,但是性能方面就表现得一般了,因为即使是将元素进行隐藏,它们其实还是在布局当中的,每个元素还拥有着自己的宽、高、背景等等属性,解析布局的时候也会将这些隐藏的元素一一解析出来。

那么我们如何才能让这些不常用的元素仅在需要时才去加载呢?Android为此提供了一种非常轻量级的控件,ViewStub。ViewStub虽说也是View的一种,但是它没有大小,没有绘制功能,也不参与布局,资源消耗非常低,将它放置在布局当中基本可以认为是完全不会影响性能的。

下面我们就来学习一下如何使用ViewStub来完成仅在需要时才去加载布局的功能,目前profile.xml中只有一个EditText用于编辑信息,那么比如说我们还有另外三个不太常用的EditText,就可以将它们定义在另外一个布局文件当中。新建profile_extra.xml文件,代码如下所示:

运行效果如图:


目前profile_extra.xml是一个独立的布局,和profile.xml这个布局文件是完全没有关系的。接下来我们修改profile.xml文件中的代码,如下所示:

可以看到LinearLayout布局中我们新增了一个More Button,这个按钮就是用于去加载那些不常用的元素的,然后在Button的下面定义了一个ViewStub。在ViewStub控件中,我们先是通过id属性给它指定了一个唯一标识,又通过layout属性将profile_extra布局传入进来,接着给ViewStub指定了一个宽高。注意,虽然ViewStub是不占用任何空间的,但是每个布局都必须要指定layout_width和layout_height属性,否则运行就会报错。

接着修改ProfileActivity中的代码,在Activity中添加More Button的点击事件,并在点击事件中进行如下逻辑处理:

当点击More Button之后我们首先会调用findViewById()方法将ViewStub的实例获取到,拿到ViewStub的实例之后就很简单了,调用inflate()方法或者setVisibility(View.VISIBLE)都可以将隐藏的布局给加载出来,而加载的这个布局就是刚才在XML当中配置的profile_extra布局。

调用inflate()方法之后会将加载出来的布局进行返回,之后我们就可以对这个布局进行任意的操作了,再次隐藏显示,或者获取子元素的实例等。注意这里我对ViewStub的实例进行了一个非空判断,这是因为ViewStub在XML中定义的id只在一开始有效,一旦ViewStub中指定的布局加载之后,这个id也就失败了,那么此时findViewById()得到的值也会是空。

运行结果如图所示:

可以看到,界面上只有一个More按钮,ViewStub是完全不占用任何空间的。然后点击一下More按钮,新的界面如下所示:


运行结果正常,profile_extra.xml中定义的布局已经加载出来了,而且显示的位置正是ViewStub控件定义的位置,说明我们已经成功是实现了ViewStub的功能。但是需要注意的是ViewStub所加载的布局不能使用标签,也就是说包含ViewStub控件的布局在进行复用时会导致加载出来的布局存在着多余的嵌套结构,但是对于含有较多隐藏子布局的布局文件来说,使用ViewStub还是一种相当不错的选择的,即使增加了一层无用的布局结构,仍然还是利大于弊,具体如何去选择就要具体情况具体分析了。对于性能的优化需要考虑很多的方面,这里只是简单的介绍了性能优化中的布局优化,作为一个开发者还需要有的放矢的选择和权衡各种方法对应用性能的影响,从而开发出性能优越,客户满意度高的应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于性能优化,Android开发中可以考虑以下几个方面: 1. 减少内存占用:确保在应用中使用的资源和对象被及时释放,避免内存泄漏。可以使用虚拟机提供的工具进行内存分析,如Android Profiler或MAT(Memory Analyzer Tool)。 2. 减少网络请求:减少网络请求的次数,尽量将多个请求合并为一个,或使用缓存来减少网络传输。 3. 使用异步操作:将耗时操作放在后台线程上执行,避免阻塞主线程。可以使用AsyncTask、Thread或Kotlin协程等机制来实现异步操作。 4. 优化布局和绘制:避免过度绘制,减少不必要的布局层次。可以使用视图优化工具,如Hierarchy Viewer来分析布局层次和绘制性能。 5. 图像和动画优化:对于图片资源,可以使用适当的压缩算法来减小文件大小。对于动画,可以使用硬件加速来提高性能。 6. 数据库和存储优化:合理使用数据库操作,如批量插入、事务操作等。对于大量数据的存储,可以考虑使用SQLite数据库或其他合适的存储方式。 7. 代码优化:避免不必要的循环、条件判断等。使用性能更好的数据结构和算法。及时释放资源,避免频繁的对象创建和销毁。 8. 使用优化工具:Android提供了一些性能优化的工具,如ProGuard(代码压缩与混淆工具)、Lint(代码质量检查工具)等,可以使用这些工具来帮助优化应用性能。 总之,性能优化是一个综合考虑多方面因素的过程,需要根据具体的应用场景和需求进行分析和优化

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值