likes
comments
collection
share

面试串讲009-布局层级太多怎么优化?

作者站长头像
站长
· 阅读数 15

问题:

布局层级太多怎么优化?

回答:

View整体布局是通过深度优先的方式来进行组织的,整体形似一颗树,所以优化布局层级主要通过三个方向来实施:

  • 降低布局深度:使用merge标签或者布局层级优化等手段来减少View树的深度;
  • 布局懒加载:使用ViewStub,AsyncLayoutInflater等布局加载手段,来确保只有当需要该布局时,该布局才会被创建,优化布局加载速度;
  • 布局重用:通过include等标签重用界面布局,减少GPU重复工作

解析:

<merge/>

<merge/>标签通常用于将其包裹的内容直接添加到父布局以达到降低布局深度的目的,一个普通的layout布局文件及其结构如下图所示:

面试串讲009-布局层级太多怎么优化?

当将该布局文件的根标签修改为<merge/>标签后,得到的布局结构如下图所示:

面试串讲009-布局层级太多怎么优化?

可以看出<merge/>标签内子元素的父布局均变更为顶上的FrameLayout,进而使得布局深度减1.

结合以上例子,我们可以得出 <merge/>标签的主要工作原理是将本应在<merge/>标签节点的Layout与该节点的父布局进行重用,以达到优化布局深度的目的,对<merge/>标签内包含的其他布局结构而言并不能起到优化深度的作用

使用<merge/>标签有以下注意事项:

  • 布局文件中<merge/>标签只能作为根标签;
  • 使用LayoutInflater加载<merge/>标签为根的布局文件时,必须设置attachToRoot为true,以确保重用父布局;
  • <merge/>标签携带的参数没有实际意义
  • <merge/>标签并不是真实存在的View或者ViewGroup,其相当于一种标记,用来表示其所包裹的内容应被添加到其上级布局,真实存在的ViewGroup是引用<merge/>标签布局的上一级布局

<ViewStub/>

<ViewStub/>标签通常用于声明布局中可以被延时加载的部分,在首次布局文件加载时处于占位状态,当调用inflate或者setVisible时才会完成加载动作,一个普通的使用<ViewStub/>布局文件及其结构如下图所示:

面试串讲009-布局层级太多怎么优化?

当执行ViewStub.inflate之后,得到的布局结构如下图所示:

面试串讲009-布局层级太多怎么优化?

可以看出ViewStub区域被其对应的布局结构替换掉了。

结合上述例子,我们可以得出使用<ViewStub/>标签可以管理在页面首次初始化时不需要加载的布局,提升渲染速度,等到需要这部分UI时再进行加载

<include/>

<include/>标签可以将一些公共布局文件在多处重复引用,以便提升布局效率,例如各个页面都有的状态栏,当使用自定义布局实现后,则可以使用<include/>标签进行重复引用。

<include/>标签使用示例代码如下:

 <?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 ​
     <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content">
 ​
         <include
             android:id="@+id/view_stub"
             layout="@layout/test"/>
 ​
         <com.poseidon.looperobserver.customview.CustomView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
             android:id="@+id/custom_view"
             android:text="move me!" />
 ​
     </LinearLayout>
 ​
 </merge>

使用<include/>标签得到的布局结构如下图所示:

面试串讲009-布局层级太多怎么优化?

可以看出从布局结构来讲并无明显差异,在初次加载就会直接构建在View树上。