1、背景:为什么需要View的懒加载。
我们在做安卓项目的时候,经常会有一个使用场景:需要在运行时根据数据动态决定显示或隐藏某个View和布局。
上述场景,我们通常的解决方案就是:就是把可能用到的View先写在布局里,再初始化其可见性都设为View.GONE,然后在代码中根据数据动态的更改它的可见性。
虽然这样的实现,逻辑简单而且控制起来比较灵活;但是也存在一定的缺点耗费资源。
因为即使把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,故而:
(1)仍然会创建对象;
(2)仍然会被实例化;
(3)仍然会被设置属性从而导致耗费内存等资源。
这时候,我们就需要View的懒加载。
2、什么是ViewStub。
(1)ViewStub一个是直接继承于View的类。
(2)实质上是一个宽高都为 0 的不可见 View。
3、为什么能用ViewStub实现View的懒加载
ViewStub的特性:
(1)在初始化布局文件时,程序无需初始化<ViewStub>标签所指向的布局文件。 只有在特定的条件下,所指向的布局文件才需要被渲染,且此布局文件直接将当前的 <ViewStub> 替换掉。但这里的替换并不是完全意义上的替换,布局文件的 layout params 是以 ViewStub 为优先。
(2)当初次渲染布局文件时,ViewStub 控件虽然也占据内存, 但是相比于其他控件, 它所占内存很小. 它主要是作为一个“占位符”, 放置于 View Tree中, 且它本身是不可见的。
由于具有以上特性,只有当一个ViewStub的inflate()方法被调用或者被设为View.VISIBILITY时,此时ViewStub会把设定的布局才会被创建对应的对象和实例化,并替换当前ViewStub的位置,显示相应的效果。虽然一开始ViewStub就存在于视图树中,但是直到setVisibility(int)或inflate()方法被调用时才消耗资源,否则是不加载控件的,因此消耗的资源小。故而, ViewStub可以实现View的懒加载。
4、实现方法
(1)关键点
<ViewStub>标签可以看成是一个“占位符“,可以看成自身是不呈现任何UI效果的视图容器,主要就是用于存放真实的布局和视图,所以除了设置必要的尺寸属性和位置之外,通常必须设置三个重要属性和一个回调监听接口:
<1>android:id
——ViewStub 自身的Id,无论是否被inflate,都可以通过findViewById拿到对应的ViewStub控件本身。
<2>android:inflatedId
——ViewStub设置的被映射的布局文件中的跟节点的Id,inflate之后可以通过findViewById获取到对应的被映射的布局对象。
<3>android:layout
——将要映射的布局文件名
<4>ViewStub.OnInflateListener
——当ViewStub成功映射预先设置的布局会触发回调
(2)使用方法
设置完上述关键点,在程序中调用 inflate() 方法就能加载对应的layout。
还可以设定 Visibility 为 VISIBLE 或 INVISIBLE,也会触发 inflate()。 但是这里只会在首次使用 setVisibility() 会加载要渲染的布局文件。再次使用只是单纯的设置可见性。
对 inflate() 操作也只能进行一次,因为 inflate() 的时候是其指向的布局文件替换掉当前 <ViewStub> 标签。之后, 原来的布局文件中就没有 <ViewStub> 标签了。因此,如果多次 inflate() 操作,会报错:ViewStub must have a non-null ViewGroup viewParent。
(3)demo
<1>建立将要被映射的布局
<2>建立主布局引入ViewStub
<3>实现MainActivity