Android 布局优化:掌握 <include> 与 <merge> 的实战技巧

引言

在 Android 开发中,布局文件是 UI 设计的核心载体,但随着项目复杂度增加,布局冗余、嵌套层级过深等问题会导致性能下降。本文将通过 代码级实战示例,详细解析如何利用 <include><merge> 标签优化布局,并对比其他常用技术(如 ViewStub、自定义组件)的适用场景,助你打造高性能 UI。


一、<include> 标签:代码复用的利器

1. 基础用法与代码示例

场景:多个页面共享同一个标题栏。
实现步骤

  1. 创建公共标题栏布局 layout_common_header.xml

    <!-- layout_common_header.xml -->
    <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="56dp"android:orientation="horizontal"><ImageViewandroid:id="@+id/iv_back"android:layout_width="24dp"android:layout_height="24dp"android:src="@drawable/ic_back"/><TextViewandroid:id="@+id/tv_title"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:textSize="18sp"/>
    </LinearLayout>
    
  2. 在目标布局中通过 <include> 复用:

    <!-- activity_main.xml -->
    <LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><include layout="@layout/layout_common_header"/><!-- 其他内容 -->
    </LinearLayout>
    

2. 高级技巧:动态覆盖布局参数

需求:在复用标题栏时,调整高度和边距。
实现:直接在 <include> 标签中覆盖参数:

<includelayout="@layout/layout_common_header"android:layout_width="match_parent"android:layout_height="64dp"android:layout_marginBottom="8dp"/>

3. 对比:<include> vs 自定义 View 组件

维度<include>自定义 View
复杂度简单,仅 XML 布局复用高,需处理测量、绘制逻辑
灵活性适合静态布局复用适合动态交互或复杂 UI 逻辑
性能开销较高(若逻辑复杂)
典型场景标题栏、按钮组、表单控件图表、自定义动画、复杂组合控件

二、<merge> 标签:层级优化的秘密武器

1. 核心作用与代码实战

场景:一个包含两个按钮的布局被多次复用,且外层容器与父布局类型相同(如 LinearLayout)。

传统实现(冗余嵌套)

<!-- layout_buttons.xml -->
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><Button android:id="@+id/btn_ok"/><Button android:id="@+id/btn_cancel"/>
</LinearLayout>

优化实现(使用 <merge>

<!-- layout_buttons_merged.xml -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"><Buttonandroid:id="@+id/btn_ok"android:layout_width="wrap_content"android:layout_height="48dp"/><Buttonandroid:id="@+id/btn_cancel"android:layout_width="wrap_content"android:layout_height="48dp"/>
</merge>

外层布局调用

<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><includelayout="@layout/layout_buttons_merged"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"/>
</LinearLayout>

优化效果:减少一层 LinearLayout,降低视图层级。

2. 必须注意的细节

  • 布局参数传递<merge> 标签的子元素必须通过 <include>android:layout_* 属性设置参数。
  • 父容器类型匹配<merge> 的子元素最终会直接添加到父容器中,因此其布局参数必须与父容器兼容。

三、组合拳:<include> + <merge> 实战案例

1. 场景:表单页面优化

原始布局(冗余代码):

<!-- activity_form.xml -->
<LinearLayout><LinearLayout><TextView android:text="用户名"/><EditText/></LinearLayout><LinearLayout><TextView android:text="密码"/><EditText/></LinearLayout>
</LinearLayout>

优化步骤

  1. 创建复用布局 layout_form_item.xml(使用 <merge>):

    <merge xmlns:android="http://schemas.android.com/apk/res/android"><TextViewandroid:id="@+id/tv_label"android:layout_width="wrap_content"android:layout_height="wrap_content"/><EditTextandroid:id="@+id/et_input"android:layout_width="match_parent"android:layout_height="48dp"/>
    </merge>
    
  2. 重构主布局:

    <LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><includelayout="@layout/layout_form_item"android:layout_margin="16dp"><!-- 动态设置 TextView 文本 --><TextViewandroid:id="@+id/tv_label"android:text="用户名"/></include><includelayout="@layout/layout_form_item"android:layout_margin="16dp"><TextViewandroid:id="@+id/tv_label"android:text="密码"/></include>
    </LinearLayout>
    

优化效果

  • 代码量减少 50%
  • 层级从 3 层降为 2 层

四、与其他技术的对比与选型

1. <include> vs ViewStub

特性<include>ViewStub
加载时机立即加载延迟加载(调用 inflate() 时)
内存占用较高(始终存在)低(按需加载)
适用场景高频使用的可见布局低频使用或条件显示的布局(如错误页)

ViewStub 示例

<ViewStubandroid:id="@+id/stub_network_error"android:layout="@layout/layout_network_error"android:layout_width="match_parent"android:layout_height="wrap_content"/>

2. <merge> vs Fragment

维度<merge>Fragment
复用粒度UI 布局片段带逻辑的完整 UI 模块
生命周期完整生命周期管理
性能开销较高(需维护 FragmentManager)
典型场景静态布局复用模块化页面(如底部导航栏)

五、关键步骤总结

1. 使用 <include> 的步骤

  1. 识别重复布局:找出多个页面中重复的 UI 模块。
  2. 提取公共布局:将重复部分抽取到独立 XML 文件。
  3. 替换为 <include>:在原布局中使用 <include> 标签引用。
  4. 动态调整参数:通过 android:layout_* 覆盖布局参数。

2. 使用 <merge> 的步骤

  1. 识别冗余容器:查找因复用导致的重复父容器。
  2. 替换根标签为 <merge>:将被复用布局的根标签改为 <merge>
  3. 调整父容器参数:通过 <include>android:layout_* 传递参数。
  4. 验证层级优化:使用 Layout Inspector 检查视图层级。

六、注意事项与最佳实践

  1. 避免过度设计:简单布局(如单个 TextView)无需使用 <include>
  2. 统一命名规范:被复用的布局文件建议以 layout_common_ 前缀命名。
  3. 性能监控:通过 Android Studio 的 Profile GPU Rendering 工具检测布局渲染时间。
  4. ID 管理:被 <include> 的布局根元素建议不设置 ID,避免冲突。

七、总结与效果验证

优化效果对比(示例)

指标优化前优化后
布局层级5 层3 层
测量时间(ms)12.38.1
代码行数200 行120 行

核心收获

  • 减少嵌套:合理使用 <merge> 可显著降低视图层级。
  • 提升可维护性:通过 <include> 实现模块化布局,修改一处即可全局生效。
  • 灵活组合:结合 ViewStub 实现按需加载,进一步优化性能。

工具推荐

  • Layout Inspector
  • Android Profiler

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/86193.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【storage】

文章目录 1、RAM and ROM2、DRAM and SRAM2、Flash Memory&#xff08;闪存&#xff09;4、DDR and SPI NOR Flash5、eMMC6、SPI NOR vs SPI NAND vs eMMC vs SD附录——prototype and demo board附录——U盘、SD卡、TF卡、SSD参考 1、RAM and ROM RAM&#xff08;Random Acce…

Python异步编程-协程

1、引言 在使用多个爬虫脚本进行数据爬取和调用大语言模型返回结果的场景中&#xff0c;涉及到大量的网络IO操作。协程能够让网络IO操作并发执行&#xff0c;极大地提升程序的运行效率。在智能体相关的开源项目中&#xff0c;我们也可以经常看到协程的身影。 2、协程 协程&a…

大语言模型提示词(LLM Prompt)工程系统性学习指南:从理论基础到实战应用的完整体系

文章目录 前言&#xff1a;为什么提示词工程成为AI时代的核心技能一、提示词的本质探源&#xff1a;认知科学与逻辑学的理论基础1.1 认知科学视角下的提示词本质信息处理理论的深层机制图式理论的实际应用认知负荷理论的优化策略 1.2 逻辑学框架下的提示词架构形式逻辑的三段论…

Android音频开发:Speex固定帧与变长帧编解码深度解析

引言 在Android音频开发领域&#xff0c;Speex作为一种开源的语音编解码器&#xff0c;因其优秀的窄带语音压缩能力被广泛应用。在实际开发中&#xff0c;帧处理策略的选择直接影响着音频传输质量、带宽占用和系统资源消耗。本文将深入探讨Speex编解码中固定帧与变长帧的实现差…

Docke启动Ktransformers部署Qwen3MOE模型实战与性能测试

docker运行Ktransformers部署Qwen3MOE模型实战及 性能测试 最开始拉取ktransformers:v0.3.1-AVX512版本&#xff0c;发现无论如何都启动不了大模型&#xff0c;后来发现是cpu不支持avx512指令集。 由于本地cpu不支持amx指令集&#xff0c;因此下载avx2版本镜像&#xff1a; …

算术操作符与类型转换:从基础到精通

目录 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符&#xff1a;、-、*、/、% 赋值操作符&#xff1a;和复合赋值 单⽬操作符&#xff1a;、--、、- 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 在先前的文…

飞腾D2000,麒麟系统V10,docker,ubuntu1804,小白入门喂饭级教程

#下载docker Index of linux/static/stable/ 根据电脑的CPU类型选择&#xff1a; Intel和AMD选x86_64飞腾D2000选aarch64 #选择较新的版本 #在包含下载的docker-XX.X.X.tgz的文件夹中右键->打开终端 # 解压安装包&#xff08;根据实际下载的文件&#xff09; tar -zxvf …

启程:为何选择PHP?

一、写在前面&#xff1a;小公司的生存逻辑与我的困惑 我是一名在小型软件开发公司工作的Java全栈开发者。我们这类团队的现实很直白&#xff1a;接不到“大单子”&#xff0c;日常围绕各类中小项目——企业官网、内部管理系统、定制化小程序——展开。客户预算有限、交付周期…

学习使用YOLO的predict函数使用

YOLO的 result.py #2025.1.3 """ https://docs.ultralytics.com/zh/modes/predict/#inference-arguments 对yolo 目标检测、实例分割、关键点检测结果进行说明https://docs.ultralytics.com/reference/engine/results/#ultralytics.engine.results.Masks.xy 对…

Node.js: express 使用 Open SSL

OpenSSL是一个开源的核心加密工具包&#xff0c;提供行业标准的加密&#xff0c;证书管理和安全通信功能。包含完整的 SSL/TLS 协议实现&#xff0c;被广泛应用于构建互联网安全基础设施。 在 express 中使用 openssl 通常是为了实现 HTTPS 通信&#xff0c;通过 SSL/TLS 加密来…

AI赋能的浏览器自动化:Playwright MCP安装配置与实操案例

以下是对Playwright MCP的简单介绍&#xff1a; Playwright MCP 是一个基于 Playwright 的 MCP 工具&#xff0c;提供浏览器自动化功能不要求视觉模型支持&#xff0c;普通的文本大语言模型就可以通过结构化数据与网页交互支持多种浏览器操作&#xff0c;包括截图、点击、拖动…

【Matlab】连接SQL Server 全过程

文章目录 一、下载与安装1.1 SQL Server1.2 SSMS1.3 OLE DB 驱动程序 二、数据库配置2.1 SSMS2.2 SQL Server里面设置2.3 设置防火墙2.4 设置ODBC数据源 三、matlab 链接测试 一、下载与安装 微软的&#xff0c;所以直接去微软官方下载即可。 1.1 SQL Server 下载最免费的Ex…

Java编程中常见的条件链与继承陷阱

格式错误的if-else条件链 典型结构与常见错误模式 在Java编程中,if-else条件链是一种常见的多条件处理模式,其标准结构如下: if (condition1) {// 处理逻辑1 } else if (condition2) {// 处理逻辑2 } else

scss(sass)中 的使用说明

在 SCSS&#xff08;Sass&#xff09;中&#xff0c;& 符号是一个父选择器引用&#xff0c;它代表当前嵌套规则的外层选择器。主要用途如下&#xff1a; 1. 连接伪类/伪元素 scss 复制 下载 .button {background: blue;&:hover { // 相当于 .button:hoverbackgrou…

C++ 信息学奥赛总复习题答案解析

第一章 答案解析 填空题 .cpp 知识点&#xff1a;C 源文件的命名规范 main () 知识点&#xff1a;C 程序的入口函数 // &#xff0c;/* */ 知识点&#xff1a;C 注释的两种形式 int a; 知识点&#xff1a;变量声明的语法 cout 知识点&#xff1a;输出语句的关键字 判断题…

Jenkins持续集成CI,持续部署CD,Allure报告集成以及发送电子 邮件

文章目录 一、Jenkins 的简介二、Jenkins的安装三、Jenkins 文件夹的作用四、Jenkins 的应用新建 job配置 jobjenkins 集成 Allure 报告。jenkins 集成 HTML 的报告 五、Jenkins 发送电子邮件1&#xff09;安装插件&#xff1a;Email Extension2&#xff09;开启 POP3/SMTP 服务…

算术图片验证码(四则运算)+selenium

一、表达式解析 这里假设已经识别出来表达式&#xff0c;如何识别验证码图片里的表达式&#xff0c;放在下面讲。涉及到的正则表达式的解析放在本篇文章最后面。 import re # 表达式解析&#xff08;支持小数的 -*/ 和中文运算符&#xff09; def parse_math_expression(text)…

使用 Laravel 中的自定义存根简化工作

在开发与外部服务、API 或复杂功能交互的应用程序时&#xff0c;测试几乎总是很困难。简化测试的一种方法是使用存根类。以下是我通常使用它们的方法。 福利简介 存根是接口或类的伪实现&#xff0c;用于模拟真实服务的行为。它们允许您&#xff1a; 无需调用外部服务即可测试…

将 tensorflow keras 训练数据集转换为 Yolo 训练数据集

以 https://www.kaggle.com/datasets/vipoooool/new-plant-diseases-dataset 为例 1. 图像分类数据集文件结构 (例如用于 yolov11n-cls.pt 训练) import os import csv import random from PIL import Image from sklearn.model_selection import train_test_split import s…

排序算法-归并排序与快速排序

归并排序与快速排序 快速排序是利用的递归思想&#xff1a;选取一个基准数&#xff0c;把小于基准数的放左边 大于的放右边直到整个序列有序 。快排分割函数 O(lognn), 空间 :没有额外开辟新的数组但是递归树调用函数会占用栈内存 O(logn) 。 归并排序&#xff1a;在递归返回的…