Android 布局优化全解析:include、merge、ViewStub 实战与最佳实践(图文版)

一、为什么要做布局优化?

Android 布局性能直接决定了应用的首屏加载速度与流畅度。

复杂的布局层级会导致:

  • measure / layout / draw 次数增加

  • 界面绘制变慢、掉帧卡顿

  • View 创建与内存占用上升

所以我们要通过:

✅ include

✅ merge

✅ ViewStub

实现布局结构优化。


二、三大优化手段关系图

下图展示了三者的区别和作用:

复制代码
┌───────────────────────────────┐
│         布局优化手段          │
├──────────┬───────────┬──────────┤
│ include  │ merge     │ ViewStub │
├──────────┼───────────┼──────────┤
│ 重用布局 │ 减少层级  │ 延迟加载 │
│ Header、Footer │ RecyclerView Item │ 空页、错误页 │
└──────────┴───────────┴──────────┘

📈 性能影响从小到大:

include < merge < ViewStub(延迟加载最优)


三、<include> ------ 复用布局的利器

🧱 典型结构图

复制代码
activity_main.xml
│
├── include -> header_layout.xml
│       ├── ImageView (返回键)
│       └── TextView (标题)
│
└── 内容区域

✅ 使用示例

XML 复制代码
<!-- header_layout.xml -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:background="@color/black">

    <ImageView
        android:id="@+id/iv_back"
        android:src="@drawable/ic_back"
        android:layout_width="24dp"
        android:layout_height="24dp"/>

    <TextView
        android:id="@+id/tv_title"
        android:text="标题"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:layout_marginStart="16dp"/>
</LinearLayout>
XML 复制代码
<!-- activity_main.xml -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/header_layout"
             android:id="@+id/include_header"/>

    <TextView
        android:text="内容区域"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

⚠️ 注意事项

  1. includeid 仅作用于引用处,子布局 id 不会被替代。

  2. 外层可重新定义 layout_widthlayout_height


四、<merge> ------ 减少多余布局层级

🧩 对比结构图

错误示例:

复制代码
LinearLayout (外层)
└── include -> LinearLayout (item_user.xml)
        ├── ImageView
        └── TextView

正确示例:

复制代码
LinearLayout (外层)
├── ImageView
└── TextView

✅ 实现示例

XML 复制代码
<!-- item_user.xml -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <ImageView
        android:id="@+id/avatar"
        android:layout_width="40dp"
        android:layout_height="40dp"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"/>
</merge>
XML 复制代码
<!-- 使用 -->
<LinearLayout
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <include layout="@layout/item_user"/>
</LinearLayout>

⚠️ 注意事项

  • <merge> 不能独立使用(必须 include 或动态 inflate)。

  • 无法直接访问根布局(它被合并进父布局)。


五、<ViewStub> ------ 按需延迟加载隐藏布局

🕓 原理示意图

复制代码
初始状态:
FrameLayout
├── MainContent
└── ViewStub (占位,不占资源)

当触发 inflate():
FrameLayout
├── MainContent
└── ErrorLayout (由 ViewStub 替换生成)

✅ 示例代码

XML 复制代码
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

    <ViewStub
        android:id="@+id/view_stub_error"
        android:inflatedId="@+id/layout_error"
        android:layout="@layout/layout_error"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>
Kotlin 复制代码
val viewStub = findViewById<ViewStub>(R.id.view_stub_error)
val errorView = viewStub.inflate()
errorView.findViewById<TextView>(R.id.tv_error).text = "加载失败,请重试"

⚠️ 注意事项

  • inflate() 只能调用一次。

  • 绑定 ViewBindingDataBinding 时需在 inflate() 之后执行。

  • 适合错误页、空数据页、引导页等不常显示的布局


六、三者对比表

特性 include merge ViewStub
作用 复用布局 减少嵌套 延迟加载
是否创建 View 合并入父布局 延迟加载时创建
性能优化级别 最高
常见场景 Header/Footer RecyclerView item 空页、错误页、引导页
注意事项 属性覆盖 无根节点 inflate 一次性

七、性能可视化示意图

下图表示布局层级优化前后的渲染层次:

复制代码
未优化:
FrameLayout
 └── LinearLayout
      └── LinearLayout
           └── TextView

优化后 (merge):
FrameLayout
 └── LinearLayout
      └── TextView

结果:

  • measure/layout 次数减少约 20--30%

  • 渲染时间缩短,首屏更快


八、实战:错误页延迟加载优化

XML 复制代码
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

    <ViewStub
        android:id="@+id/stub_error"
        android:layout="@layout/layout_error"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>
Kotlin 复制代码
class MainActivity : AppCompatActivity() {
    private var errorView: View? = null

    fun showError() {
        if (errorView == null) {
            errorView = findViewById<ViewStub>(R.id.stub_error).inflate()
        }
        errorView?.visibility = View.VISIBLE
    }

    fun hideError() {
        errorView?.visibility = View.GONE
    }
}

九、总结:何时用哪一个?

目的 推荐方式 原因
复用相同布局 include 简单可靠
避免重复父布局 merge 减少层级
延迟加载不常用布局 ViewStub 节省内存与渲染时间

🔚 写在最后

布局优化不是炫技,而是「让 UI 加载更快」的基础功。

掌握 includemergeViewStub 的组合拳,

你可以让应用启动速度提升、UI 更流畅。

相关推荐
2301_8002561112 小时前
关系数据库小测练习笔记(1)
1024程序员节
金融小师妹1 天前
基于多源政策信号解析与量化因子的“12月降息预期降温”重构及黄金敏感性分析
人工智能·深度学习·1024程序员节
GIS数据转换器1 天前
基于GIS的智慧旅游调度指挥平台
运维·人工智能·物联网·无人机·旅游·1024程序员节
南方的狮子先生2 天前
【C++】C++文件读写
java·开发语言·数据结构·c++·算法·1024程序员节
Neil今天也要学习2 天前
永磁同步电机无速度算法--基于三阶LESO的反电动势观测器
算法·1024程序员节
开开心心_Every2 天前
专业视频修复软件,简单操作效果好
学习·elasticsearch·pdf·excel·音视频·memcache·1024程序员节
liu****3 天前
16.udp_socket(三)
linux·开发语言·数据结构·c++·1024程序员节
草莓熊Lotso3 天前
《算法闯关指南:优选算法--位运算》--38.消失的两个数字
服务器·c++·算法·1024程序员节
unable code4 天前
攻防世界-Misc-can_has_stdio?
网络安全·ctf·misc·1024程序员节
思茂信息4 天前
CST License(Flexnet)设置与问题处理方法
服务器·网络·单片机·3d·php·1024程序员节·cst