【转】Android布局优化之ViewStub
ViewStub是Android布局优化中⼀个很不错的标签/控件,直接继承⾃View。虽然Android开发⼈员基本上都听说过,但是真正⽤的可能不多。
ViewStub可以理解成⼀个⾮常轻量级的View,与其他的控件⼀样,有着⾃⼰的属性及特定的⽅法。当ViewStub使⽤在布局⽂件中时,当程序inflate布局⽂件时,ViewStub本⾝也会被解析,且占据内存控件,但是与其他控件相⽐,主要区别体现在以下⼏点:
android layout布局1.当布局⽂件inflate时,ViewStub控件虽然也占据内存,但是相相⽐于其他控件,ViewStub所占内存很⼩;
2.布局⽂件inflate时,ViewStub主要是作为⼀个“占位符”的性质,放置于view tree中,且ViewStub本⾝是不可见的。ViewStub中有⼀个layout属性,指向ViewStub本⾝可能被替换掉的布局⽂件,在⼀定时机时,通过viewStub.inflate()完成此过程;
3.ViewStub本⾝是不可见的,对ViewStub setVisibility(..)与其他控件不⼀样,ViewStub的setVisibility 成View.VISIBLE或INVISIBLE如果是⾸次使⽤,都会⾃动inflate其指向的布局⽂件,并替换ViewStub本⾝,再次使⽤则是相当于对其指向的布局⽂件设置可见性。
这⾥需要注意的是:
1.ViewStub之所以常称之为“延迟化加载”,是因为在教多数情况下,程序⽆需显⽰ViewStub所指向的布局⽂件,只有在特定的某些较少条件下,此时ViewStub所指向的布局⽂件才需要被inflate,且此布局⽂件直接将当前ViewStub替换掉,具体是通过viewStub.infalte()或viewStub.setVisibility(View.VISIBLE)来完成;
2.正确把握住ViewStub的应⽤场景⾮常重要,正如如1中所描述需求场景下,使⽤ViewStub可以优化布局;
3.对ViewStub的inflate操作只能进⾏⼀次,因为inflate的时候是将其指向的布局⽂件解析inflate并替换掉当前ViewStub本⾝(由此体现出了ViewStub“占位符”性质),⼀旦替换后,此时原来的布局⽂件中就没有ViewStub控件了,因此,如果多次对ViewStub进⾏infalte,会出现错误信息:ViewStub must have a non-null ViewGroup viewParent。
4.3中所讲到的ViewStub指向的布局⽂件解析inflate并替换掉当前ViewStub本⾝,并不是完全意义上的替换(与include标签还不太⼀样),替换时,布局⽂件的layout params是以ViewStub为准,其他布局属性是以布局⽂件⾃⾝为准。
下⾯看⼀下简单的需求场景:在listview显⽰列表数据时,可能会出现服务端⼀条数据都没有的情况,此时显⽰⼀个EmptyView,提⽰⽤户暂⽆数据。此时考虑到实际应⽤中EmptyView显⽰出来的机会相当⼩,因此,可以在布局⽂件中使⽤ViewStub站位,然后确实没有数据时才viewStub.infalte()。
相关部分代码如下:
1 public void showEmptyView() {
2    listview.setVisibility(View.GONE);
3    if (noDataView == null) {
4        ViewStub noDataViewStub = (ViewStub) view.findViewById(_data_viewstub);
5        noDataView = noDataViewStub.inflate();
6    } else {
7        noDataView.setVisibility(View.VISIBLE);
8    }
9 }
10
11 public void showListView(){
12    listview.setVisibility(View.VISIBLE);
13    if(noDataView != null){
14        noDataView.setVisibility(View.GONE);
15    }
16 }
特别需要注意的是对ViewStub是否已经inflate的判断。
在Listview Item中,有时候可能遇到如下场景:在不同的列表页item的布局⼀部分不同,但相对于整个item布局来说⼜不是很多,此时最常见的有如下两种处理:
1.对不同的部分都写出来,放到⼀个item⽂件中,然后逻辑分别处理不同部分的显⽰与否(View.VISIBLE和View.GONE);
2.对这两种不同的item整个部分都分别区分开,完全写成两个item⽂件,然后结合listView显⽰不同布局分别做逻辑处理(通过getItemType()等⽅式)。
以上两种处理⽅式其实都可以,第⼀种⽅式逻辑清晰,⾮常灵活,只是在⼀定程度上增加了内存和资源消耗。第⼆种⽅式是的布局⽂件有重复(虽然相同部分可以通过include,但是逻辑上还是有重复的),包括逻辑上处理的代码实质上的重复。⼀般对于有较⼤不同的item布局推荐采⽤此种⽅式。
有时候结合需求,可以在第⼀种⽅式的基础上,结合ViewStub“占位符”可以⽐较好的完成此类需求。也相当于是两种⽅式的⼀种折中形式,但同时兼顾了内存和资源消耗以及不同的布局逻辑控件。
原⽂: