布局优化
这一次我们来说说有关布局优化的问题。布局是非常重要的,写的不好会很影响性能的。布局优化的思路其实很简单,基本上就是减少布局文件的嵌套与减少不必要的绘制。这个问题很容易理解,布局中的层级减少了,就意味着Android系统的绘制时的工作量减少了,那么性能自然就会上来。下面我们就聊一聊布局如何优化。
选择合适的布局
在能满足布局要求的情况下尽量使用消耗性能较低的ViewGroup,比如:如果一个布局既可以使用LinearLayout来布局也可以使用RelativeLayout来布局,这时我们该选择什么呢?首先我们知道越复杂的功能实现起来也越复杂,在源码中也可以看到,RelativeLayout比LinearLayout发杂的多(内部需要考虑水平方向和竖直方向上的依赖,造成两次遍历)。由此我们就能想到,在这种情况下,我们就选择LinearLayout。FrameLayout和LinearLayout一样都是一种简单高效的ViewGroup。但很多时候我们单纯的通过一个LinearLayout或者FrameLayout是无法实现一个布局效果的,需要通过嵌套的方式来完成。这种情况下,不建议使用嵌套,这样很耗费程序的性能,建议使用RelativeLayout或者约束布局来完成。
使用include标签来共享布局
我们在开发时经常遇到好多页面都有相同的布局,这时我们每一个页面都要写一个吗?回答时no,要是都写得话就造成了代码的重复。我们可以将共用的布局抽离出来,独立写成一个XML文件,然后在需要它的页面中使用include标签把它引进来,这样不仅减少了代码量,而且修改起来也非常方便,不需要去每个页面中一个一个的去修改了,只需要修个这一个文件就可以了。使用:
<include layout="@layout/title"/>
< include>标签只支持android:layout_开头的属性,比如android:layout_width,android:layout_height,其他属性暂不支持,但是有一个特例:id属性,如果< include>制定了这个id属性,同时被包含的布局文件的跟布局页包含了id数据,这时会以< include>中的id属性为准。另外需要注意的是:当< include>标签中制定了android:layout_*这样的属性,那么必须要有android:layout_width属性和android:layout_height属性,否则android:layout_*属性是无法生效的。
使用ViewStub标签来实现布局的延迟加载
ViewStub是一种不可视并且大小为0的视图,因此他本身不参与任何的布局和绘制过程,他可以延迟到运行时才填充布局资源。他一般用在:当满足某些条件时某些UI才会展示,在进入一个页面时一般不会展示的情况下,比如网络错误页面,当发生网络错误时我们才展示,正常的情况下我们是不展示的。这时如果我们不使用ViewStub标签,而是直接将网络错误的布局隐藏,这种做法肯定是不好的,它虽然不显示出来,但是它会被inflate并占用资源。如果我们使用ViewStub标签就可以在它需要展示的时候再去填充布局。用法如下
<ViewStub
android:id="@+id/net_error_stub"
android:inflatedId="@+id/net_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/net_error" />
其中android:inflatedId的值就是我们在Java代码中调用ViewStub的inflate()或者setVisibility()方法时返回的ID,这个ID就是被填充的View的ID。
merge标签的使用
< merge>标签和< include> 标签一起使用可以减少布局的层级嵌套。由于Activity的ContentView的最外层的布局是FrameLayout,因此,当一个独立的布局文件的最外层是FrameLayout,且这个布局不需要设置android:background或者android:padding等属性时,可以使用< merge>标签来代替< FrameLayout>标签,从而减少一层多余的Framelayout布局。使用一般限定在(使用相同的布局文件)
布局中背景颜色的设置要慎重
如果我们在嵌套的布局中每一层嵌套中都设置背景色,这会造成过度绘制,本来底层布局已经设置过颜色了,你在上层布局中又设置了一边同样的颜色,这时造成的直接结果就是GPU需要渲染这个颜色两边,从而造成了不必要的资源的浪费,降低了应用的性能。
尽量使用CompoundDrawable
如果存在相邻的ImageView和TextView实现的效果,看看能不能将其合并成一个TextView,ImageView中的图片设置成TextView的如下属性之一:drawableTop,drawbaleLeft,drawableRight或者drawableBottom。两者之间的间隔使用drawablePadding来代替。
使用Lint检测
Android Lint不仅可以对代码进行检测,对布局同样能够检测,可以用它来检测布局中哪些地方可以优化
- AndroidLintUseCompoundDrawables:就是CompoundDrawable
- MergeRootFrame:就是merge标签减少布局层次
- TooManyViews:单个布局中存在太多的View,默认情况下,单个布局View的数量最多只能是80个,可以考虑复用布局,减少嵌套等。
- NestedWeights:android:layout_weight属性会使得View控件被测量两次,当一个LinearLayout拥有非0dp值的android:layout_weight属性,这时如果将他嵌套在另一个拥有非0dp值的android:layout_weight属性的LinearLayout,那么这时测量的次数将呈指数级别增加。
- Uselessleaf:一个布局如果既没有子View也没有设置背景,那么它将是不可见的,通常可以移除它。
最后:应用的性能体现在应用代码中的一点一滴