Android 布局优化:利用 ViewStub 和 Merge 提升性能

提升界面渲染性能是一个至关重要的任务,尤其是在应用启动时,渲染界面需要快速且流畅。为了优化 UI 渲染速度,Android 提供了许多工具,其中 ViewStub 和 Merge 标签是非常有效的布局优化手段。通过合理使用这两者,可以延迟加载不必要的视图、减少布局的嵌套层级,从而加速应用的启动和运行。

提升界面渲染性能是一个至关重要的任务,尤其是在应用启动时,渲染界面需要快速且流畅。为了优化 UI 渲染速度,Android 提供了许多工具,其中 ViewStub 和 Merge 标签是非常有效的布局优化手段。通过合理使用这两者,可以延迟加载不必要的视图、减少布局的嵌套层级,从而加速应用的启动和运行。

ViewStub:惰性加载视图

ViewStub 是一种轻量级的视图元素,它不会在界面加载时立即被渲染,而是在需要时通过 inflate() 方法动态加载。这种机制能够显著减少初始界面的绘制时间,尤其是在某些复杂或不常使用的 UI 组件中。

适用场景

  • 惰性加载:只有在特定条件下才显示的 UI 组件,比如错误页面、空数据页面等。
  • 减少不必要的资源占用:ViewStub 默认不占用任何 UI 资源,避免了提前渲染不需要的视图。通过调用以下代码将其设为可见setVisibility(View.VISIBLE)inflate()

示例:在一个布局中使用 ViewStub 来延迟加载一个错误页面布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/showErrorButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显示错误页面"/>

    <!-- ViewStub 仅在需要时才加载 -->
    <ViewStub
        android:id="@+id/errorViewStub"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/error_layout"/>
</LinearLayout>

定义错误页面的 UI:

//error_layout.xml 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/red">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="错误页面"
        android:textColor="@android:color/white"/>
</LinearLayout>

在代码中动态加载 ViewStub:

//方式一
val viewStub = findViewById<View>(R.id.errorViewStub)
//方式二 
//val viewStub = findViewById<ViewStub>(R.id.errorViewStub)

val button = view.findViewById<Button>(R.id.showErrorButton)

button.setOnClickListener {
    //方式一
    viewStub.visibility = View.VISIBLE
    //方式二
    //if (viewStub.parent != null) viewStub.inflate()
}

通过这种方式,error_layout 只有在用户点击按钮时才会被加载,提高了初始界面的加载速度。

注意: ViewStub 一旦被膨胀(inflate),它就会从视图层次结构中移除,成为膨胀后的布局的根视图,所以inflate() 方法只能调用一次。如果多次调用 inflate(),会抛出 IllegalStateException 异常:
java.lang.IllegalStateException: ViewStub must have a non-null ViewGroup viewParent

减少布局层级

<merge>是一种优化布局层级的工具,它的作用是避免在使用时创建多余的根视图。通过使用,我们可以减少视图层级,提高 UI 渲染性能,特别是在布局嵌套较深时。

适用场景

  • • 去除不必要的父布局:当你重复使用某个布局时,使用<merge>可以避免额外的布局元素,减少层级。
  • • 提高 UI 渲染效率:减少视图层级,优化布局的测量(measure)、布局(layout) 和绘制 (draw) 过程。

示例:优化嵌套层级

首先,假设我们有一个toolbar_layout.xml,它包含一个 LinearLayout 作为根视图:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_back"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="标题"
        android:textSize="18sp"/>
</LinearLayout>

在 activity_main.xml 中,使用<include>引入该布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="正文内容"/>
</LinearLayout>

此时,toolbar_layout.xml 中的 LinearLayout 会被嵌套在父布局中,造成不必要的额外层级。

使用<merge>优化

优化后的 toolbar_layout.xml 如下:

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_back"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="标题"
        android:textSize="18sp"/>
</merge>

优化后的 activity_main.xml 依然使用<include>引入布局,但没有额外的根视图层级:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="正文内容"/>
</LinearLayout>

通过这种方式,ImageView 和 TextView 直接成为父布局的子视图,减少了嵌套层级,从而提升了 UI 渲染效率。

总结

  • • ViewStub 适用于惰性加载,能够延迟加载视图,减少初始界面的渲染时间,提升应用启动速度。
  • • Merge 适用于减少布局层级,特别是当使用<include>标签重复使用布局时,它能去掉额外的根视图,提升 UI 渲染效率。

根据项目需求选择合适的优化策略,能够显著提升 Android 应用的性能,提供更流畅的用户体验。


来源:公众号
作者:代码说
原文地址:Android 布局优化:利用 ViewStub 和 Merge 提升性能

来源: 公众号
本文观点不代表码客-全球程序员交流社区立场,不承担法律责任,文章及观点也不构成任何投资意见。

赞 ()

相关推荐

  • 置顶 开发项目接单群,免费入群了

    无论你是Android、ios、java、php,或者你是产品经理、老板,都可以免费入群接单或者发布项目,全程不收取任何费用。

    2025年02月21日 15点27分
  • Android 布局优化:利用 ViewStub 和 Merge 提升性能

    提升界面渲染性能是一个至关重要的任务,尤其是在应用启动时,渲染界面需要快速且流畅。为了优化 UI 渲染速度,Android 提供了许多工具,其中 ViewStub 和 Merge 标签是非常有效的布局优化手段。通过合理使用这两者,可以延迟加载不必要的视图、减少布局的嵌套层级,从而加速应用的启动和运行。

    2025年02月26日 22点47分
  • Android加快你的编译速度

    工欲善其事,必先利其器。如果每次运行项目都要花费5-10分钟,那人的心态都要崩了。

    2025年02月25日 15点40分
  • Flutter多渠道打包的解决方案(walle)

    我们的应用集成了TalkingData这个第三方工具来统计日活、事件等,需要在应用启动时初始化SDK,这个时候需要传入当前渠道,以便数据的统计。 由于最开始是用脚本一个个打包,一直想解决打包过慢的问题,但是网上大多教程是基于命令行参数或flavor,实质上并没有根本解决打包效率的问题。直到发现了文章的主角 walle。

    2025年02月25日 15点36分
  • Android-分享一个对RecyclerView二次封装的库(EasyRecyclerView)

    在日常的Android开发当中,我们肯定会有使用到RecyclerView的需求,这里分享一个对RecyclerView二次封装的开源库——EasyRecyclerView。它基本上满足基本的开发需求,希望能帮看文章的小伙伴提高开发效率。

    2025年02月25日 15点31分
  • Android原生系统真的那么好用吗?安卓原生系统吊打其他系统,因为有Google-Play,所以应用都是纯净的?

    实际方面,原生 Android 的最大优势是更新快速,对供应商特别是 Android 上游的补丁的合并速度非常快,几乎总能在第一时间更新。因为系统越原生,更新的代价就越小。反之,如果一个停止更新的原生 Android 其实是没有多大意义的,它失去了它最大的优势。

    2025年02月25日 15点30分
  • Application 作为 Dialog 的 Context?小心踩坑!

    大家好,相信大家在使用 Dialog 时,都有一个非常基本的认知:就是 Dialog 的 context 只能是 Activity,而不能是 Application,不然会导致弹窗崩溃:

    2025年02月25日 15点25分
  • Android 应用的线程世界:最少需要几个线程才能启动?

    这篇文章主要介绍了 Android App 中的多种线程,包括守护线程(如 Signal Catcher 等)、渲染线程、主线程、三方线程(如 OkHttp、Glide、ARouter 相关线程)等,还提及三方库中线程池的情况及可能存在的问题。

    2025年02月25日 15点13分
  • Android 复杂项目崩溃率收敛至0.01%实践

    在我们的项目中,每个版本发布之后,我们会创建一个opt分支,用于修复线上崩溃以及业务逻辑BUG。

    2025年02月25日 15点11分
  • Android 能悄悄知道用户截屏?这里有你想要的答案

    很多应用在当你截屏的时候能够感知到,并提示你是否要发送截屏等等。

    2025年02月25日 15点07分
  • 科大讯飞讯飞星火API能力免费开放,引领大模型商业化新篇章

    合肥本土科技巨头科大讯飞传来振奋人心的消息:讯飞星火API能力正式向公众免费开放,其中,讯飞星火Lite API更是实现了永久免费。这一举措无疑为整个行业注入了新的活力,也彰显了科大讯飞在大模型商业化进程中的坚定决心。

    2025年02月21日 15点57分
  • 一木林接入AI大模型,实现智能体功能

    一木林——全能型AI电子工具箱。这是一款集多功能于一体的工具类应用,凭借小巧的体积与全面且强大的功能,赢得了极高的口碑。应用内汇聚了上百款实用工具,诸如指南针、计算器、分贝仪等,一应俱全。如今,一木林已携手星火AI大模型,实现了AI对话与智能体的创新功能。

    2025年02月21日 15点42分
  • PrivacySentry:隐私政策守护利器

    近年来,工信部对APP个人隐私要求越来越多,之后各大应用市场也开始要求,有违规情况的会导致APP下架或者无法上架。这不,我的app就因为三方SDK频繁获取Android ID 导致无法上架,等SDK商场更新也很浪费时间,所以只能想办法去处理这件事,好在找到了PrivacySentry这个神器,可规避应用市场上架合规检测的大部分问题

    2025年02月18日 23点20分
  • Kotlin协程:MutableSharedFlow的实现原理

    在Koltin协程:异步热数据流的设计与使用中,提到了可以通过MutableSharedFlow方法创建一个MutableSharedFlow接口指向的对象,代码如下:

    2025年02月18日 11点03分
  • 探索Markdown之父John Gruber对Markdown的看法

    Markdown的缔造者——约翰·格鲁伯,其形象正如上方头像所示。不禁让人遐想,国外的大师们是否都偏爱蓄须? 约翰·格鲁伯,1973年出生于美国宾夕法尼亚州,他是一位才华横溢的作家、博主、UI设计师,更是Markdown的创始人。他毕业于Drexel University(卓克索大学),并获得了计算机科学学士学位。在职业生涯中,他曾在Joyent公司任职,为大型企业提供了基础架构和平台服务。自2002年起,他开始撰写备受欢迎的科技博客《Daring Fireball》,并主持了知名的播客节目The Talk Show。2013年,他与两位友人共同创立了Q Branch,并开发了Vesper笔记应用。

    2025年02月18日 10点52分

发表回复

评论列表

点击查看更多

    联系我们

    在线咨询: QQ交谈

    微信:dxmcpjl

    邮件:1529097251#qq.com

    工作时间:周一至周五,9:30-18:30,节假日休息

    微信