布局优化原因
如果布局嵌套过深,或者界面元素复杂等原因导致布局渲染性能不佳,可能会导致应用卡顿
UI层级查看工具
Android Studio -> Tools -> Layout Inspector
image-20211207214505023.png
优化 UI 层级方法
- 使用 include 标签复用布局
- 使用 merge 标签减少布局层级
- 使用 ViewStub 标签延迟 inflater 非必须布局
- 尽量使用 ConstraintLayout 使视图层次结构扁平化
include
include 是为了解决重复定义相同布局的问题,将多次使用的布局内容独立成一个 xml 文件,然后在需要使用的地方通过 include 标签引入即可
例如:将标题栏布局独立成一个 xml 文件,再通过 include 标签引入
title.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/title_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back"
android:textAllCaps="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title Text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/title_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Edit"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<include
android:id="@+id/common_title_root"
layout="@layout/title" />
</androidx.constraintlayout.widget.ConstraintLayout>
注意点
当 include 标签和被引入的根布局,同时设置了 id 属性的时候,以 include 标签的 id 为准。如上面的例子,如果使用 findViewById(R.id.title_root) 将返回 null
merge
使用工具 Layout Inspector 查看上面例子的 UI 层级结构,会发现,多了一层 ConstraintLayout,如下图:
image-20211207221843517.png
这是 title.xml 文件的根布局,这一层布局嵌套是不必要的,merge 就用于解决这一层不必要的布局嵌套,将 title.xml 最外层的 ConstraintLayout 布局换用成 merge 标签,表示当要 include title.xml 这个布局时,会将 merge 标签内包含的内容直接填充到 include 的位置,因此不会额外添加布局结构。修改后的 title.xml 如下:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back"
android:textAllCaps="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title Text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/title_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Edit"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</merge>
使用工具 Layout Inspector 查看修改后的 UI 层级结构,会发现少了一层 ConstraintLayout
image-20211207222727153.png
ViewStub
是延迟加载的一种方式,它通过 android:inflatedId 属性指向一个布局,当 ViewStub 被设置为可见或者 ViewStub.inflate() 被调用的时候,inflatedId 属性指向的布局就会被实例化为 View, 并且按照 ViewStub 的布局属性添加到 ViewStub 的父 View 中
修改上面例子中的 activity_main.xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/show_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="show the title view"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ViewStub
android:id="@+id/stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="@+id/title_root"
android:layout="@layout/title"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java 改为点击按钮才加载 title.xml 布局
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
show_title.setOnClickListener {
var titleRoot = stub.inflate()
}
}
}
注意点
ViewStub 的 android:layout 不能指向一个 merge 标签包裹的布局文件,不然会报以下错误
Process: com.example.androidstudy, PID: 7999
android.view.InflateException: Binary XML file line #3: <merge /> can be used only with a valid ViewGroup root and attachToRoot=true
Caused by: android.view.InflateException: <merge /> can be used only with a valid ViewGroup root and attachToRoot=true
因此要将 title.xml 文件的 merge 改为 ConstraintLayout ,或者其他 ViewGroup
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/title_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--其他内容不改动-->
</androidx.constraintlayout.widget.ConstraintLayout>
执行代码,先不点击按钮执行 stub.inflate() ,使用工具 Layout Inspector 查看 UI 层级结构,如下:
image-20211207230013871.png
点击按钮,执行 ViewStub .inflate() 方法后,使用工具 Layout Inspector 查看 UI 层级结构,发现 stub 换成了 title.xml 文件中的布局
image-20211207230252032.png
ViewStub 的 inflate() 方法只能执行一次,如果多次执行,会报以下错误
Process: com.example.androidstudy, PID: 8545
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.ViewStub.inflate()' on a null object reference








网友评论