布局性能优化利器: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...
    }
});
相关推荐
循环不息优化不止2 小时前
Ktor Pipeline 机制深度解析
android
q***56382 小时前
Springboot3学习(5、Druid使用及配置)
android·学习
q***64972 小时前
SpringSecurity踢出指定用户
android·前端·后端
q***76662 小时前
SpringSecurity 实现token 认证
android·前端·后端
Chejdj2 小时前
ViewModel#onCleared的实现原理
android·源码阅读
CheungChunChiu3 小时前
Android 系统中的 NTP 服务器配置与选择逻辑详解
android·运维·服务器
q***49863 小时前
MySQL数据的增删改查(一)
android·javascript·mysql
aqi003 小时前
FFmpeg开发笔记(九十一)基于Kotlin的Android直播开源框架RootEncoder
android·ffmpeg·kotlin·音视频·直播·流媒体
鹏多多3 小时前
flutter睡眠与冥想数据可视化神器:sleep_stage_chart插件全解析
android·前端·flutter