ListView中的分类getItemViewType和getViewTypeCount的使用详解

最近忙着学习IOS和公司安卓的培训一直没空弄博客,越到后面空闲时间越少了,上周给公司同事讲解ListView分类,自己都懵了,以前一直用的取巧的办法:在一个布局中定义item,然后在getView中动态控制item元素的显示和隐藏,知道有getItemViewType和getViewType方法,但都没静下心来研究,都是网上照葫芦画瓢,自己研究了发现其实网上的做法也不敢苟同,下面就详细的说下Android中分类的做法。

先看两张效果图:

     

第一张                               第二张

大家应该都知道ListView中我们为了提高效率经常会用到ViewHolder来缓存视图,但是在ListView分类中这种做法貌似就失灵了,我反正没想到方法,知道的朋友们不妨跟帖告知,感激不尽。先来看看我做的demo中Adapter类的实现。

ItemAdapter类:

在上面的类中,我们先不要管具体的实现,我们先看看打印结果:

这里我只过滤出在getView中判断语句内部打印情况,大家可以看到一共执行了11次,也就是创建了11个item,而根据我们以往的经验,应该是9行才对,因为我们看第一张图片一屏只显示了9个item,那多出来的两个怎么解释呢。这里我先说下,我们在使用ListView分类的时候会用到两个方法getItemViewType和getViewTypeCount,getViewTypeCount这个方法告诉ListView我共有多少种item,getItemViewType方法告诉ListView每行该显示哪种item,并且该方法中返回的type类型必须为整数且不能大于getViewTypeCount返回的数。

我们有开发经验的朋友应该都知道ListView的缓存机制,我简单的介绍下,ListView显示的view从我们重写的getView方法创建,并且一共创建的个数是一屏显示的个数,比方说我们手机上一屏能显示9个item,那么ListView刚开始显示的时候就创建了9个ListView的item,而当我们向上滚动ListView的时候第一个item不可见,下面的第10个item并没有重新创建而实际上复用的是第一个item。这样设计的目的就是为我们节省了很大的内存开销。

回到上面的问题,为什么会多出两个item呢,这里我们需要明白ListView中如果我们重写了那两个get方法,那么ListView给我们初始创建的item的个数是一屏显示的个数+item的种类数(也就是getViewTypeCount返回的个数),多出来的这两个item会先放到缓存池中为我们接下来的复用做准备的。当我们滚动到让下面第10个item(不要被列表item上的文字混淆了,从上向下数第10个item)显示出来的时候,打印结果如下:

我们看到内存地址6557b68,其实用的就是上面多创建出来的item。我们可以这么来理解:ListView为我们创建了11个item,这11个item中有9个是显示在屏幕上的,另外两个item放入了一个缓存池,当我们滑动到让第10个item显示出来之前,首先会执行getItemViewType这个方法判断该行item的类型,然后再从缓存池中查看是否有该类型item的缓存给我们用,有的话就直接拿过来,没有就创建。为了验证我们所说的,我们再将ListView滑动到让第11个item(也就是Label9)显示出来,看下面的打印:

我们看到显示第11个item的时候是重新创建了一个item,因为此时缓存池中已经没有该类型的item缓存给我们来复用了。

再结合例子来讲解如何实现这种分类

工程结构如下:

先定义个基类Item,该类是所有ListView的item的基类

ItemView接口定义了两个方法:

TextItem类实现了Item类并定义了自己的成员变量text

SeparatorItem和ContentItem类继承自TextItem并重写了newView方法返回他们自己定义两个layout

SeparatorItem:

ContentItem:

再看看自定义的两个view,SeparatorItemView和ContentItemView

SeparatorItemView:

ContentItemView:

MainActivity:

separator_item_view.xml

content_item_view.xml

 

这里是源码,有兴趣的可以下载看看。

 

“ListView中的分类getItemViewType和getViewTypeCount的使用详解”的10个回复

  1. 你的item的布局和label的布局是不同的,比如item的布局是relativelayout,而label是线性布局,只要判断一下,instanceof relativelayout就可以避免复用带来的问题。

  2. 学习了,貌似这种方法对同类型的视图(itemview)是可以复用的。子视图作为成员变量跟itemview绑定在一起了,也达到了ViewHolder缓存视图的目的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注