如果你对ListView多种布局不甚明了,可以先看看Android ListView 多种布局–初步,在这一篇博文中我们初步认识了ListView多种布局的一般处理方法,这种简单的多种布局一般在开发中不会遇到什么问题,但是复杂的多种布局就不好说了,比如像下面这样:
如果需要整体布局,上面这个需求怎么办?
很明显我们需要ListView作为整体布局,然后使用ListView为我们提供的多种布局来解决上面的需求,在解决这个需求之前,我们先来了解一下ListView的缓存策略,为了直观期间,我们用Android ListView 多种布局–初步这篇博文上的Demo直接打上Tag的方法来看看View是如何初始化和复用的。
经过上面的测试我们来小结一下:
一个屏幕上能够显示的相同Type的Item的个数就是需要初始化的次数,上面这句话有没有问题,我们看完Log分析再来评价就好。
我们可以通过截图看到TitleView在一个屏幕上有3个显示出来,所以一下在初始化了三次TitleView,当向上滑动以后,位于最上面的TitleView因滚动而划出屏幕外,此时位于屏幕下方的View为ContentView,所以此时不会再次初始化TitleView,而是初始化ContentView,因为在屏幕上面最上面的ContentView并没有划出屏幕外,因此还需要继续初始化,就像Log打印出来的一样:
Content Inflate Times: 9,注意在一开始打开App的时候屏幕上就有8个ContentView,接下来初始化的第9个ContentView许多人可能不太清楚,所以
ContentView在一个屏幕上显示8个,并不是说就初始化8次,而是当向上或者向下滑动的时候有没有满足可以复用View的条件,如果满足复用条件,那么就不会重新创建View,反之就会重新创建View,接下来看看这个复用条件是什么?
在可视范围内,如果位于最上面的相同Type的View在向上滑动的过程中在可见状态的情况下,位于最下面的相同Type的View进入视野,那么这个Type的View是必须重建的,此种情况下不满足复用条件,反之则满足复用条件。
由此可见,最上面小结的一个屏幕上的可视范围的相同Type的View就是初始化的次数是错误的
好了,我们通过实验了解了基本的ListView复用机制,虽然实验出真知,但是不看看源代码,心理总感觉虚,所以接下来看看源代码,这里先给出最基本的几个代码中的实现思路:
mActiveViews
: Views that were on screen at the start of layout. This array is populated at the start of layout, and at the end of layout all view in mActiveViews are moved to mScrapViews. Views in mActiveViews represent a contiguous range of Views, with position of the first view store in mFirstActivePosition.布局开始时屏幕显示的view,这个数组会在布局开始时填充,布局结束后所有view被移至mScrapViews。
mScrapViews
:ArrayList[] Unsorted views that can be used by the adapter as a convert view.可以被适配器用作convert view的无序view数组。 这个ArrayList就是adapter中getView方法中的参数convertView的来源。注意:这里是一个数组,因为如果adapter中数据有多种类型,那么就会有多个ScrapViews。
mViewTypeCount
:view类型总数,列表中可能有多种数据类型,比如内容数据和分割符。
mCurrentScrap
:跟mScrapViews的却别是,mScrapViews是个队列数组,ArrayList[]类型,数组长度为mViewTypeCount,而默认ViewTypeCount = 1的情况下mCurrentScrap=mScrapViews[0]。
由上面的几处实现思路可知,如果viewTypeCount = 2;而我们通过
@Overridepublic int getItemViewType(int position){ final ItemFeed feed = data.get(position); if (feed != null) { return feed.getItemType().getValue(); } return super.getItemViewType(position);}
这个方法返回的int值 应该全部小于2才不出数组越界。为了验证这个问题,我们这样改写Android ListView 多种布局–初步代码如下
private enum ItemType{ TITLE(1), CONTENT(2); public int getValue() { return value; } private int value; ItemType(int value) { this.value = value; }}
并且去掉
@Overridepublic int getItemViewType(int position){ return super.getItemViewType(position);}
是不是出现了久违的Crash啦。
所以我们在处理多种布局的ListView的时候必须重写对应的两个方法,否则Crash是正常的。
关于博文开头提及的需求,我们另外开个博文来详细数一下实现细节,敬请关注。
版权声明:本文为博主原创文章,未经博主允许不得转载。