ViewStub懒加载
ViewStub常用于优化布局,使用它可以提高布局加载的性能。
1、ViewStub介绍
①ViewStub继承自View
②ViewStub默认是不可见(GONE),而且View的大小为0
③当一个ViewStub被设置成可见visible或者调用inflate()方法时,ViewStub得到填充。此时ViewStub所引用的layout布局会替换掉当前ViewStub显示出来。
2、使用ViewStub
和使用其它控件一样,在布局中用<ViewStub />标签来使用ViewStub:
<ViewStub
android:id="@+id/view_stub"
android:inflatedId="@+id/inflate_layout"
android:layout="@layout/more_text" />
三个属性提一下:id就是当前ViewStub的id;inflatedId是布局被加载出来的要设置id;layout是需要加载的布局。
3、ViewStub加载布局
3.1、通过inflate()方式加载布局
先通过findViewById(),在调用ViewStub的inflate()方法初始化ViewStub对象:
ViewStub mViewStub= (ViewStub) findViewById(R.id.view_stub);
View inflated = mViewStub.inflate();
ViewStub在第一次加载完成之后会移除自身,并把自身的内容转给父布局;所以不能借助ViewStub来findViewById()查找包所含布局中的控件。另外,ViewStub只能加载一次,若多次调用inflate()会导致异常:"ViewStub must have a non-null ViewGroup viewParent"。
3.2、通过设置setVisibility()加载布局
直接通过设置ViewStub的setVisibility();ViewStub第一次被设置成VISIBLE的时候会自动调用inflate()加载布局,即使后面多次设置VISIBLE也不会出错。比直接调用ViewStub的inflate()方法相对安全一些。
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.show_view_stub:
mViewStub.setVisibility(View.VISIBLE);
break;
case R.id.hide_view_stub:
mViewStub.setVisibility(View.GONE);
break;
default:
break;
}
}
3.3、判断ViewStub是否已经加载布局
①ViewStub调用inflate()后会被从布局中移除。所以每次在inflate的时候重新findViewById()去页面中寻找一下ViewStub,如果返回值不为null则ViewStub没有被inflate。
// 每次在inflate之前都调用一遍findViewById
ViewStub viewStub= (ViewStub) findViewById(R.id.viewstub);
if(viewStub!=null){
viewStub.inflate();
}
②利用ViewStub的parent来判断。当ViewStub被inflate后,会被从布局中移除,其getParent()返回值是null。
//初始化,不必每次都调用ViewStub viewStub= (ViewStub) findViewById(R.id.viewstub);
....
if(viewStub.getParent() !=null){
viewStub.inflate();
}
通过打印日志,查看ViewStub的getParent()是否为空,当ViewStub没被加载可以getParent()获取到父布局。但一旦调用过ViewStub的inflate()方法,那么getParent()就会返回null;可以通过这个方式来判断ViewStub是否已被加载。如下:初始化-> inflate() -> 隐藏。可以看见inflate()之后getParent()为null。
4、注意*
ViewStub所包含布局中的控件在ViewStub被inflate()之前都不可用,也不能被findViewById()查找到,因为还没有添加到当前布局中:
mViewStub = findViewById(R.id.test_view_stub);
mImageView = findViewById(R.id.view_stub_image);
Log.e(TAG, "初始化ViewStub中的ImageView:\tImageView == null:" + (mImageView == null));
mImageView = mViewStub.findViewById(R.id.view_stub_image);
Log.e(TAG, "初始化ViewStub中的ImageView:\tImageView == null:" + (mImageView == null));
结果都不能初始化ViewStub中的ImageView,均为空:
直到ViewStub被加载之后,ViewStub被布局中的内容替换,可用直接通过findViewById()找到由ViewStub引入布局中的控件。但是仍然不能通过ViewStub去findViewById(),因为被加载的布局是替换ViewStub,被添加到ViewStub所在的父布局,而不是添加到ViewStub中。通过ViewStub获得的控件仍然是null。
mViewStub.inflate();
Log.e(TAG, "初始化ViewStub中的ImageView: findViewById()\tImageView == null:" + (findViewById(R.id.view_stub_image) == null));
Log.e(TAG, "初始化ViewStub中的ImageView: ViewStub.findViewById()\tImageView == null:" + (mViewStub.findViewById(R.id.view_stub_image) == null));
实际执行结果如下: