布局性能优化利器:ViewStub 极简指南

ViewStub 是 Android 开发中优化布局性能的高频实用工具,它通过让布局按需加载,来解决一系列问题。本文将全面讲解 ViewStub 在使用中必知必会的那些点,还有注意事项。

基础用法

为了演示 ViewStub 的使用,我简单做了个两个布局。

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">

    <Button
        android:id="@+id/inflate_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="INFLATE"/>

    <ViewStub
        android:id="@+id/view_stub"
        android:layout_width="500dip"
        android:layout_height="500dip"
        android:layout="@layout/target_layout" />

</LinearLayout>

target_layout:

xml 复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_green_light">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dip"
        android:text="ViewStub Target Layout" />

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

</LinearLayout>

当点击按钮时,就会调用 ViewStub 的 inflate() 方法将 target_layout 加载到 Activity 中:

java 复制代码
public class MainActivity  extends Activity {

    @Override
    protected void onCreate( Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button button = findViewById(R.id.inflate_button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final ViewStub viewStub = findViewById(R.id.view_stub);
                if(viewStub != null)
                    viewStub.inflate();
            }
        });

    }
}

在加载布局时,虽然布局文件中有 ViewStub,但是它是第一个零宽、零高、不可见的 View,而且在内存中几乎不占据任何空间。任何消耗都在其被调用 inflate 之后。

这里可以看到,只要找到 ViewStub 然后调用 inflate() 方法,就可以加载指定布局。这个布局可以通过 ViewStub 的 android:layout 属性来指定。

这是 ViewStub 最基础的使用,但是它还有一些注意事项。

注意事项

这几个注意事项我先列出来,如下:

  • ViewStub 在 inflate 之后就从布局中消失了,无法再被 findViewById
  • ViewStub 的 width 和 height 属性无效,是用于传递给目标 layout 的
  • 可以通过设置 inflatedId 来设置目标 layout 根布局的 id 属性
  • 可以在代码中设置 setLayoutResource 来覆盖 XML 中的 android:layout 属性,指定要加载的布局
  • 对 ViewStub 调用 setVisibility(VISIBLE) 与调用 inflate() 的效果是完全一样的
  • 要加载的布局不能是 merge 或 include
  • 可以通过 setOnInflateListener 来监听加载完成事件

接下对这些注意事项我们就一一说道说道。

前面说过,ViewStub 的核心任务就是 "一次性替换"。当调用 inflate() 方法或将其设置为 VISIBLE 时,它会找到自身所在的父布局,将自己从父布局的 View 树中移除,然后将它指向的 target_layout 加载进来并替换自己的位置。一旦被移除,ViewStub 这个对象就不再存在于当前的 View 层次结构中,自然也就不能再通过任何方式(包括 findViewById)查找和操作它。所以当第二次调用 findViewById 查找时,只能返回 null。

ViewStub 自身在 View 树中是一个 零尺寸 的 View。它的职责是占位,而不是占空间。因此,它自身的宽高设置对它自己不起作用。当 ViewStub 执行替换操作时,它会把自己定义的 android:layout_width 和 android:layout_height 属性,作为 LayuoutParams 传递给被加载的 target_layout 的根 View。这决定了被加载 View 在父容器中的大小和定位。

同理,ViewStub 中的 android:inflatedId 属性,也会覆盖 target_layout 的根 View 的 id 属性。而且这个 target_layout 的根 View 会在 inflate 时返回。

上面说到说可以过 setOnInflateListener 来监听加载完成事件,这里有点要注意,那就是在使用时要注意清空这个 Listener,避免内存泄漏。

java 复制代码
viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
    @Override
    public void onInflate(ViewStub stub, View inflated) {
        // inflated 就是被加载进来的 target_layout 的根 View
        viewStub.setOnInflateListener(null);
        // TODO...
    }
});
相关推荐
allk5517 分钟前
Android 屏幕适配全维深度解析
android·性能优化·界面适配
Android系统攻城狮28 分钟前
Android ALSA驱动进阶之获取采样格式位宽snd_pcm_format_width:用法实例(九十八)
android·pcm·音频进阶·alsa驱动
莫比乌斯环1 小时前
【日常随笔】Android 跳离行为分析 - Instrumentation
android·架构·代码规范
aningxiaoxixi1 小时前
android 媒体之 MediaSession
android·媒体
GoldenPlayer1 小时前
Android文件权限报错
android
Jomurphys1 小时前
Compose 适配 - 全屏显示 EdgeToEdge
android
ii_best1 小时前
「安卓开发辅助工具按键精灵」xml全分辨率插件jsd插件脚本教程
android·xml·开发语言·编辑器·安卓
消失的旧时光-19431 小时前
从 Android 回调到 C 接口:函数指针 + void* self 的一次彻底理解
android·c语言·开发语言
dvlinker1 小时前
动态代理技术实战测评—高效解锁Zillow房价历史
android·java·数据库
峥嵘life1 小时前
Android16 EDLA 认证BTS测试Failed解决总结
android·java·linux·运维·学习