在使用之前首先要知道什么是ViewStub?
ViewStub其实本质上也是一个View,其继承关系如图所示:
为什么ViewStub可以提高加载性能?
ViewStub使用的是惰性加载的方式,即使将其放置于布局文件中,如果没有进行加载那就为空,不像其它控件一样只要布局文件中声明就会存在。
那ViewStub适用于场景呢?通常用于网络请求页面失败的显示。一般情况下若要实现一个网络请求失败的页面,我们是不是使用两个View呢,一个隐藏,一个显示。试想一下,如果网络状况良好,并不需要加载失败页面,但是此页面确确实实已经加载完了,无非只是隐藏看不见而已。如果使用ViewStub,在需要的时候才进行加载,不就达到节约内存提高性能的目的了吗?
ViewStub的加载原理
ViewStub只能加载一次,重复加载会导致异常,这是因为ViewStub只要加载过一次,其自身就会被移除,把并自身所包含的内容全部传给父布局。
ViewStub如何使用
父布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.administrator.myviewstub.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="inflate"
android:text="inflate" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="setData"
android:text="setdata"/>
<ViewStub
android:id="@+id/vs"
android:layout="@layout/viewstub"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
可以看到ViewStub又引用了另外一个布局。
ViewStub布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/hello_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DATA EMPTY!"/>
</FrameLayout>
MainActivity
public class MainActivity extends AppCompatActivity {
private ViewStub viewStub;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewStub = (ViewStub) findViewById(R.id.vs);
//textView = (TextView) findViewById(R.id.hello_tv);空指针
}
public void inflate(View view){
viewStub.inflate();
//textView = (TextView) viewStub.findViewById(R.id.hello_tv);空指针
textView = (TextView) findViewById(R.id.hello_tv);
}
public void setData(View view){
textView.setText("DATA!!");
}
}
注意:
这里有几个坑,前面我们说了ViewStub只有在初始化之后才会存在,所以第一个注释中的空指针是因为ViewStub还未初始化。那第二个注释中的空指针是怎么回事呢?前面我们也说了,ViewStub在加载完成之后会移除自身,并把自身的内容转给父布局,所以此时viewStub中的内容已经不存在了,textView已经是父布局的东西了,所以不能使用viewStub来findViewById。另外,前面我们说了ViewStub只能加载一次,若调用两次inflate()的话会导致异常。
翻看源码只有就可以看到,ViewStub若之前没有进行inflate,setVisibility(View.VISIBLE)或setVisibility(View.INVISIBLE)会自动先进行加载,而加载之后可以设置显示和隐藏。并且ViewStub设置的不是自己,而是拿到关联的那个Layout设置visible。ViewStub此时并未销毁,所以建议初始化后将其设置为空。
自己写了一个栗子:
ViewStub 是一种可以动态加载的布局,默认情况下不显示
1 、定义要引入的布局,如: title_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/title_height"
android:background="@color/title_color">
<TextView
android:id="@+id/title_left_view"
android:layout_width="wrap_content"
android:layout_height="@dimen/title_height"
android:layout_marginLeft="3dp"
android:gravity="center_vertical"
android:textColor="#ffffffff"
android:textSize="18sp"/>
<TextView
android:id="@+id/title_center_view"
android:layout_width="wrap_content"
android:layout_height="@dimen/title_height"
android:gravity="center_vertical"
android:textColor="#ffffffff"
android:layout_centerInParent="true"
android:text=" 登录 "
android:textSize="24sp" />
<TextView
android:id="@+id/title_right_view"
android:layout_width="wrap_content"
android:layout_height="@dimen/title_height"
android:gravity="center_vertical"
android:textColor="#ffffffff"
android:layout_alignParentRight="true"
android:textSize="18sp"
android:layout_marginRight="3dp"/>
</RelativeLayout>
2 、定义 ViewStub 引入布局
<ViewStub
android:id="@+id/title_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/title_layout"/>
3 、 java 中动态控制
// 显示标题
ViewStub titleView = (ViewStub) findViewById(R.id.title_view);
titleView.setVisibility(View.VISIBLE);