美文网首页Android开发面试
Android中布局的优化

Android中布局的优化

作者: 笔墨Android | 来源:发表于2018-04-18 01:22 被阅读164次

我的简书地址

本文涉及到的知识点

  • 简单的说明以下布局优化的重要性
  • 一些布局使用的注意事项
  • include、merge与ViewStub的使用
  • ConstraintLayout的使用

1.布局优化的重要性

在日常开发中对于布局我们很少注重性能,主要注重的就是相应的展示问题。可能由于界面的复杂程度,使得界面嵌套的层级过多,这样也就导致了绘制页面的卡顿现象。增加了GPU渲染的复杂程度。这里引用一张图片来说明相应的问题。

GPU过度绘制参考图

怎么查看呢?手机设置->开发者选项->调试GPU过度渲染 打开之后你就能看到你的APP到底有没有过度绘制了。如果你看见的是一片红,那么恭喜你...你必须考虑相应的优化了!说了这么多,其实最重要的就是减少层级、减少相应的过度绘制,就能有效的对布局进行相应的优化。所以在Android做一些简单的布局优化还是有必要的。。。

2.一些布局使用的注意事项

这里先提出个问题,大家想一下?如果项目中有这样一个需求,竖直排列两行每行两个元素,大家怎么去实现呢?相信有的人会使用相对布局,有的人会使用线性布局,那么问题就来了,如果你使用线性布局的话,就会存在布局嵌套的问题,就平白的多了一层布局嵌套,平时开发的时候这样的问题很多,如果你多加注意的话,你会发现很多这样的问题。

这里我主要想说的是,如果在平时开发布局的时候,如果在布局不是很复杂的情况下尽量使用相对布局,少用线性布局。但是大家要注意一点,如果布局复杂的话,或者层级较深的情况下,最好还是使用线性布局。这里不知道大家注意没有,在Android Studio2.+版本的时候,所有默认的布局都是线性布局,为什么呢?我就不在继续深入讲解了,感兴趣的同学可以看看尹star
的->Android中RelativeLayout和LinearLayout性能分析
主要是Measure在测量的时候产生的性能消耗!所以这个问题主要看你布局是否比较复杂。。。其实在现在的版本中,google推荐我们使用的是ConstraintLayout(这个我会在后面详细的讲解)

3.include、merge与ViewStub的使用

说到布局优化问题,很难不提及include、merge与ViewStub的使用,但是这些都有相对的局限性的,下面我们就来一一讲解:

3.1 include的使用和注意事项

这个东西相信大家都不陌生,它能帮我们解决布局复用的问题,只要include导入一个布局就可以了。像这样:

<include layout="@layout/XXX"/>

XXX代表引入的布局。是不是很简单,那么我问大家几个问题?

  • 如果在include标签中我设置相应的layoutxxx的属性,会对原来的布局有什么影响?
  • 如果在include标签中我设置了id,会对原来的布局有什么影响?

这些问题,相信细心的人应该会有体会的,但是对于有些人来说,或许很陌生。所以这里有必要说明一下:

  • 当你在include中设置layoutxxx属性的时候,会覆盖相应导入根布局的layoutxxx属性,怎么理解呢?也就是说如果你导入的布局是这样的
<?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">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#223344"
        android:gravity="center"
        android:text="导入的布局"
        android:textColor="@android:color/white"
        android:textSize="20sp" />

</LinearLayout>

这里看好,LinearLayout的宽和高是占用父窗体。如果你要是这么写

    <include layout="@layout/test_view" />

的话,会显示全屏的,就像这个样子


没有设置layoutxxx的属性

但是如果你要是写成这个样子就不一样了

    <include
        layout="@layout/test_view"
        android:layout_width="200dp"
        android:layout_height="200dp" />

会变成这个样子


设置了layoutxxx的属性

这里要特别注意一下。。。

  • 当你在include中设置id的时候,会覆盖相应导入根布局的id属性,也就是说你只能使用include中的id属性获取根view了!

3.2 merge的使用和注意事项

对于新手来说,这个标签应该很少使用,至少我是这样的,其实我呆了这么多公司,也很少有人去用这个,可能我呆的都是小公司吧!哈哈。。。不闲扯了,其实这个标签主要是针对include导入的标签的根布局来说的,可以减少一个层级的嵌套!

先来说一下这个怎么看啊!!!不说这个的都是扯淡。。。在Android Studio3.+版本上按照下图获取!

查看视图树的工具

中间会弹出一个对话框,然后你就点确定,就能查看相应的视图树了。。。

  • 当你没有使用merge标签的时候,布局是这个样子的!
<?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">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#223344"
        android:gravity="center"
        android:text="导入的布局"
        android:textColor="@android:color/white"
        android:textSize="20sp" />

</LinearLayout>

这个时候你查看一下视图树你会发现会出现下面这个样子。

未使用merge标签的视图层级

我已经用红框画出来了,中间有一层LinearLayout作为根布局,但是如果你把上面的LinearLayout换成merge标签就不会有中间这层LinearLayout了。这个就不贴图了,不信的你可以试试。。。

还有一个问题需要注意:
这里有必要说明一下,如果你要给merge标签设置一些属性怎么办?其实是这样的,你可以根据include的父控件进行属性的设置,如果父控件是LinearLayout你就可以设置weidge或者相应LinearLayout的特有属性...这也充分说明了为什么include可以使用layoutxxx属性覆盖根布局的layoutxxx属性。

3.3 ViewStub的使用和注意事项

其实关于这个ViewStub这个标签,就相当于延时加载,但是有很多局限性,打个比方说吧!相应在平时开发的时候,都会根据状态进行一些控件的显示和隐藏吧,一般的处理都是View的setVisibility();但是这里如果你改变一次之后还能进行改变的话,那么就不能使用ViewStub这个标签。因为ViewStub对控件只有一次的改变,其实ViewStub在布局加载的时候已经加载出来了,只是宽和高都是0罢了,当你inflate()的时候,再去加载这个整体的View,达到了延迟加载的目的!

基本的写法就是这样,也是导入一个layout

    <ViewStub
        android:id="@+id/vs_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/test_view" />

什么时候你想加载了,就调用View inflate = mVs.inflate();方法就能让这个View显示出来,但是一定要注意,这个方法只能使用一次,切记!切记!切记!重要的事情说三遍,当这个View加载出来的时候,你就可以像对待其他View对待它了,如果你要对这个View做一些特有控件的操作,最好强转一下。。。

基本上上面这三个View优化的标签我总结的就这么多,有什么不对的还请指出,我会立即改正的!!!

4. ConstraintLayout的使用

关于这个控件,其实google早在很早的时候就让我们去尝试着使用了,但是在1.0.2那个版本的时候(记不太清楚了)才作为根布局使用的。

A ConstraintLayout is a ViewGroup which allows you to position and size widgets in a flexible way.
Note: ConstraintLayout is available as a support library that you can use on Android systems starting with API level 9 (Gingerbread). As such, we are planning on enriching its API and capabilities over time. This documentation will reflect those changes.

这里面引用了google的解释,大概的意思是

ConstraintLayout继承ViewGroup允许您以灵活的方式定位和调整小部件的大小。
ConstraintLayout可用作支持库,您可以从API级别9(姜饼)开始在Android系统上使用该支持库。因此,我们计划在一段时间内丰富其API和功能。本文档将反映这些更改。

主要是约束内部控件位置的布局,里面包含关于相对位置的属性:

  • layout_constraintLeft_toLeftOf 当前控件的左侧和目标控件的左侧对齐
  • layout_constraintLeft_toRightOf 当前控件的左侧和目标控件的右侧对齐
  • layout_constraintRight_toLeftOf
  • layout_constraintRight_toRightOf
  • layout_constraintTop_toTopOf
  • layout_constraintTop_toBottomOf
  • layout_constraintBottom_toTopOf
  • layout_constraintBottom_toBottomOf
  • layout_constraintStart_toEndOf
  • layout_constraintStart_toStartOf
  • layout_constraintEnd_toStartOf
  • layout_constraintEnd_toEndOf

其实属性很多,估计让你记你也记不住,所以总结一下:

这里所有的都可以这么去理解,layout_xxxA_toxxxB 理解为,当前控件的A侧和目标控件的B侧对齐,你可能还是不理解,拿第一个举例说明下,就是当前控件的左侧和目标控件的左侧对齐,标记了两个,其他的以此类推。这里注意里面设置的参数是目标控件的id/父容器只有这两种可能!
如果你有两个控件,左侧的以父控件对齐,另一个控件以左侧的控件对齐,这时候如果右侧以父控件对齐的话,这个控件会在右侧剩下的空间居中(像下面这样),但是如果你要是不设置右侧的属性的话,那么两个会挨着!(是那个属性拆散了它们!哈哈)

  • layout_constraintHorizontal_bias 水平偏差百分比
  • layout_constraintVertical_bias 竖直偏差的百分比

这两个属性是针对于上面这个产生偏差的(只能设置以为小数,最大是1),其实我试过,只要你左右或者上下都有约束的时候,这个相应的属性才生效,否则是无效的(如:一个控件左右都有约束,那么设置layout_constraintHorizontal_bias才会生效,否则是不会生效的,竖直方向的同理)

  • android:layout_marginStart
  • android:layout_marginEnd
  • android:layout_marginLeft
  • android:layout_marginTop
  • android:layout_marginRight
  • android:layout_marginBottom

如果你设置了相应的margin_xxx属性,那么主要是产生了相应的边距,和其他的控件都一样,这里就不再多做解释了.

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

这里说明一个问题,当你有一个View处于GONE的情况,其他View还以来这个View来进行布局,那么就需要设置上面的goneMarginXXX来设置相应的Margin(PS:这个只有在你依赖的那个约束为GONE的时候才会生效的属性)

  • android:minWidth 设置布局的最小宽度
  • android:minHeight 设置布局的最小高度
  • android:maxWidth 设置布局的最大宽度
  • android:maxHeight 设置布局的最大高度

这几个属性没有什么好说的了!

  • layout_constraintDimensionRatio 设置宽高比

这个属性很有意思:设置相应的宽高比,但是我试了,至少要有三面有约束,否则不起作用,并且宽度和高度都应该设置成"0",参数值可以是"1:1"或者"h,1:1"也可以是"w,1:1"其中h代表限制高度,w代表限制宽度.这里的比例不管你前面是什么,后面的比值都是"宽度:高度"

  • layout_constraintHorizontal_weight
  • layout_constraintVertical_weight

这两个属性相当于LinearLayout的weight属性和LinearLayout的属性设置是一样的

  • layout_constraintHorizontal_chainStyle
  • layout_constraintVertical_chainStyle
    • CHAIN_SPREAD 默认样式(如果某些小部件设置为MATCH_CONSTRAINT,则它们将拆分可用空间)
    • CHAIN_SPREAD_INSIDE 但链条的终点不会被分散
    • CHAIN_PACKED 链条的元素将被打包在一起。
样式说明

这里我用的时候踩了一个大坑,这里所谓的链式,你必须确保从左至右或者从上至下多有的约束都连着,这里的连着是都有相应的约束:
如view a 和view b在竖直方向上形成锁链:a的属性设置为 top_toTopOf = “parent” bottom_toTopOf = “b” b的属性设置为top_toBottomOf=“a” bottom_toBottom = “parent"切记!切记!切记!都要连上....重要的事情说三遍,否则你是看不见效果的.效果就是上面这张图的效果!

这里使用了这个布局,就能减少布局的嵌套,也使得绘制的时候能减少GPU的负担,这样就能达到布局优化的目的了!!!

上面这些......基本上就是我在项目中优化布局时候所做的一些优化,有什么不妥的地方还请指正!


2018年04月18日补充
其实ConstraintLayout还有一个基线的定义,什么意思呢?就是当你布局没有参考点的时候,你可以设置一个相应的基线,然后其他的内容,都以这个基线为参考!像下面这样

<android.support.constraint.Guideline
        android:id="@+id/guideline1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5" />

这里有几个属性说明一下:

  • orientation 代表方向性的
  • layout_constraintGuide_percent 代表在父控件中的百分比

这样一个基线就完成了,完成之后其他的参考和上面的写法就都一样了。


欢迎关注我的公众号

相关文章

网友评论

    本文标题:Android中布局的优化

    本文链接:https://www.haomeiwen.com/subject/kijpkftx.html