ViewStub的简单应用

一、什么是ViewStub

A ViewStub is an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime.
这是官方文档的定义,ViewStub是一个不可见的,大小为0的View,这个View能够用来在运行时懒加载布局资源。这里的懒加载的意思,就是在需要使用的时候才加载布局资源文件,这样的好处就是能够减少内存资源的使用,因为布局资源里的View对象(们)不会刚开始就创建,只有需要的时候才会创建。

二、ViewStub的简单使用

在这里我们简单定义两个布局文件:
(1)activity_view_stub,这个资源文件在setContentView中使用。

<?xml version="1.0" encoding="utf-8"?>
<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/btn_show"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Show"
        android:gravity="center"/>
    <Button
        android:id="@+id/btn_hide"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hide"
        android:gravity="center"/>
    <ViewStub
        android:id="@+id/view_stub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/view_stub_example"/>
</LinearLayout>

(2)view_stub_example,在ViewStub通过android:layout这个属性来应用该资源文件,具体可以看上面的布局文件。

<?xml version="1.0" encoding="utf-8"?>
<TextView
    android:id="@+id/tv_content"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:text="this is the text in layout resource"
    android:gravity="center"/>

(3)下面就是一个简单的activity,通过show和hide按钮来操作ViewStub。

public class ViewStubActivity extends Activity implements View.OnClickListener{
    private ViewStub mViewStub;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_stub);
        mViewStub = (ViewStub) findViewById(R.id.view_stub);
        findViewById(R.id.btn_show).setOnClickListener(this);
        findViewById(R.id.btn_hide).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_show:
                show();
                break;
            case R.id.btn_hide:
                hide();
                break;
            default:
                break;
        }
    }

    private void show() {
        mViewStub.inflate();
    }

    private void hide(){
        mViewStub.setVisibility(View.GONE);
    }
}

(4)点击show按钮前,通过dump view查看view的结构为

这里写图片描述

通过这个图可以看出ViewStub并不显示。

(5)点击show按钮后,通过dump view来查看view的结构为
点击show之后显示的图层

通过这个图,可以看出,点击show之后,定义在view_stub_example.xml资源文件中的TextView已经显示出来。
(6)点击hide按钮后,通过dump view查看view的结构为

这里写图片描述

通过这个图可以看出,TextView又隐藏起来了,看不见了。

(7)再次点击show按钮之后,发现activity崩溃了,为什么???,查看异常发现报java.lang.IllegalStateException: ViewStub must have a non-null ViewGroup viewParent,通过这个异常去查看ViewStub的代码,发现

public View inflate() {
        final ViewParent viewParent = getParent();

        if (viewParent != null && viewParent instanceof ViewGroup) {
            ...
        } else {
            throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
        }
    }

那么说明ViewStub这个时候的调用getParent()拿到的是null,为什么会这样啊???

这是因为ViewStub通过inflate()懒加载了定义在属性android:layout的布局文件后,ViewStub会从布局文件中删除,所以它的getParent()会拿到null。实际上在inflate()之后再通过findViewById去找ViewStub,此时也找不到ViewStub(为空)。

在这里我们可以验证一下

修改前

private void show() {
        mViewStub.inflate();
    }

修改后为

private void show() {
mViewStub.setVisibility(View.VISIBLE);
System.out.println(“ViewStub = ” + findViewById(R.id.view_stub));
}

查看log会发现打印 “System.out: ViewStub = null”,说明这个时候的确找不到这个ViewStub了,已经被删除了。

三、setVisibility()和inflate()的异同

相同:通过setVisibitlity()和inflate()都可以懒加载定义在android:layout中的布局文件,实际上setVisibility也是调用inflate()函数来加载布局文件的。

不同:如果通过setVisibility(),那么加载之后就不需要重新调用inflate()函数,直接设置View的Visibility属性即可。注意这里的措辞,是View的Visibility属性,而不是ViewStub的Visibility属性。在ViewStub调用inflate()之前,那么设置的是ViewStub的Visibility属性,调用inflate()函数之后,这个时候设置的是android:layout这个属性指定的布局文件加载后的根View(伪代码中的root)的Visibility属性,使用伪代码如下:

View root = factory.inflate(mLayoutResource, parent,false);

通过这个不同点,我们可以简单修改上述的代码,可以达到点击show和hide来展示和隐藏android:layout中定义的布局资源的目的

修改前

mViewStub.inflate();
        System.out.println("ViewStub = " + findViewById(R.id.view_stub));

修改后

mViewStub.setVisibility(View.VISIBLE);
        System.out.println("ViewStub = " + findViewById(R.id.view_stub));

这样随便点击显示和隐藏就不会造成崩溃,可以达到展示和隐藏的功能。

四、获取定义在android:layout布局文件中的View

这个实际上就跟include类似,在inflate()之后,就可以直接通过findViewById直接获取了。

  private void show() {
        mViewStub.setVisibility(View.VISIBLE);
        System.out.println("ViewStub = " + findViewById(R.id.view_stub));
        TextView content = (TextView) findViewById(R.id.tv_content);
        content.setText("This the content after changed");
    }

五、总结

ViewStub是一个size为0的View,并且是一个不可见的View。使用ViewStub可以达到懒加载资源文件的目的,从而减少资源使用。在ViewStub使用inflate()函数之后,ViewStub会从布局文件中删除,此时会将定义在android:layout中的资源文件加载后的根view替换ViewStub。

六、典型的应用场景

(1)网络请求的失败展示信息
(2)导航页和欢迎页的切换

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
viewStub是一个轻量级的View,它可以延迟加载布局资源,而不必在Activity或Fragment的onCreate方法中立即加载视图树,这样可以提高应用程序的性能。而viewBinding是一种新的方式,它允许您直接从布局文件中获取对视图的引用,而不必使用findViewById()方法。当您使用viewStub时,您需要在布局文件中定义一个viewStub元素,然后在代码中使用它来加载布局资源。而当您使用viewBinding时,您需要在Activity或Fragment的onCreate方法中初始化绑定对象,然后使用它来获取对布局文件中的视图的引用。如果您要在使用viewBinding的情况下使用viewStub,您可以使用ViewBinding.inflate()方法来创建ViewBinding对象,然后使用ViewBinding.getRoot()方法来获取根视图,然后将其传递给viewStub的setVisibility()方法来显示或隐藏它。例如,您可以使用以下代码来显示viewStub: ``` private lateinit var binding: ActivityMainBinding private lateinit var stub: ViewStub override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) stub = binding.viewStub val inflatedView = binding.viewStub.inflate() // Do something with inflatedView } ``` 在这个例子中,我们首先使用ViewBinding.inflate()方法初始化了绑定对象,然后使用ViewBinding.getRoot()方法获取根视图,并将其传递给viewStub的setVisibility()方法来显示它。然后,我们使用viewStub的inflate()方法来加载布局资源,并将返回的视图对象保存在一个变量中,以便我们可以在代码中使用它。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值