Android关于ListView中的getItemViewType与getViewTypeCount

Android中对于ListView自定义的时候,经常会有这样一种需求:在同一个ListView中显示不同的两种或者两种以上的条目。比如:一种条目是只显示一个TextView,而另一种条目时显示一个TextView加上一个ImageView,这种需求很常见。

在实现这种效果的时候,我们就会用到题目中提到的两个函数,getItemViewType与getViewTypeCount。

那么,这两个函数的作用是什么呢?它们之间又有什么关系呢?

首先是这两个函数的作用,getItemViewType的作用,就是返回一个整数,这个我们可以理解为这个整数就是返回的type类型,比如我们可以将只含有一个TextView的Item的type定义为 0,含有一个TextView与一个ImageView的Item的type 定义为1(怎么定义完全由自己决定),这个函数会接收一个int类型的position参数,这个其实就是ListView显示条目的position,我们可以根据不同的position来返回不同的类型(比如position为单数时返回0,position为双数时返回1)

那么,返回的不同的类型,有什么用呢?

非常有用!我们在ListView中交叉显示不同的条目,主要就是靠这个函数的返回值。具体的做法是:我们可以在getView方法中得到返回的type值,然后根据type值来判断,不同的type值填充不同的xml布局文件,然后再将填充好的布局文件返回,这样就达到了在一个ListView中显示多种不同的Item的目的)

好,现在getItemViewType函数的作用已经基本说完了,其实用法很简单。但是用这个函数的时候有一个陷阱,那就是在重写这个函数的时候(这个函数是BaseAdapter从父类那里继承来的),我们必须也重写getViewTypeCount这个函数。

那么有的同学就要问了,如果不重写getViewTypeCount这个函数会怎么样呢?

答案是,会报错!以下是我的程序没有重写这个函数时报的错误:

 20701-20701/exercise.viewpager.me.listviewforscrollviewstudy E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.ClassCastException: exercise.viewpager.me.listviewforscrollviewstudy.MainActivity$ViewHolder1 cannot be cast to exercise.viewpager.me.listviewforscrollviewstudy.MainActivity$ViewHolder2
            at exercise.viewpager.me.listviewforscrollviewstudy.MainActivity$MyAdapter.getView(MainActivity.java:125)
            at android.widget.AbsListView.obtainView(AbsListView.java:2161)
            at android.widget.ListView.measureHeightOfChildren(ListView.java:1247)

......

再后面的log没有什么价值,就不一一粘贴了,大家会看到,报的错误很诡异,是告诉我们类型转换异常,

那么好,我们重写这个方法,我们直接重写会发现这个方法默认是这样的:

 @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount();
        }
大家很可能以为这样复写一下就可以了,那大家就大错特错了,这样重写这个方法得到的结果,跟没有写这个函数是一样的,还是报一个类型转换错误。(我最后会把自己试验的代码分享给大家,有兴趣的同学可以下载看一看,不过我的代码时用AndroidStudio写的工程,用Eclipse的同学,可能需要自建工程,粘贴试验用的代码与布局了)

那么问题来了,既然不写这个函数也报错,直接复写也报相同的错,那么我们要在这个函数中返回一个什么样的值呢?

答案是:需要返回一个与我们需要的类型数目相同或大于我们需要的类型数目的值。

比如说,我们现在需要让ListView显示两种不同的Item,那么我们就需要返回2,或者大于2的整数。(一般都会返回2,因为返回大于2的整数也没有什么实际意义)

而且还有一点需要格外注意,因为很隐蔽,很坑爹,那就是除了这里要返回大于等于我们需要的Item的类型数之外,还需要让我们返回的Type是从0开始的连续的整数。

如果你不这样做的话,会报下面的错误(比如我们getViewTypeCount中返回了2,但是我们type的值定义的是1,2,这时就会报下面的错误)

 22928-22928/exercise.viewpager.me.listviewforscrollviewstudy E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.ArrayIndexOutOfBoundsException: length=3; index=3
            at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:6424)
            at android.widget.ListView.measureHeightOfChildren(ListView.java:1259)
            at android.widget.ListView.onMeasure(ListView.java:1159)

.......(剩余的略)

大家可以看到,这时报的是一个数组越界的错误,这个错误 真的很坑爹,机会就等于没有头绪,我也就是被这个错误卡了一天。因为怎么检查代码,怎么想,都不知道自己到底错在哪,因为数组越界的下标是3,但是自己定义的type数量也是3个,并没有越界的可能啊。后来经过调查才发现,原来是因为type没有从0开始增加。

将type变为0,1之后,就一切正常了。

好,要分享的东西也就这么多,不是多么高深的知识,但是如果不知道也足够卡小半天的。

如果想知道的更详细的话,可以去百度搜索这两个函数的用法,有的资料还是很有启发的。

最后总结一下,关于这两个函数的用法需要注意的地方:

1.getItemViewType与getViewTypeCount这两个函数必须联合使用。

2.我们在指定type的值时,要从0开始,依次增加,不要跳跃的定义type的值,因为可能会引起数组越界或空指针的错误。

3.getViewTypeCount中返回的值要大于等于type的数量(前提是你是从0开始连续的定义type的值)

4.如果跳跃的定义type的值,会发生空指针异常(报在ListView这个类上),如果连续定义type值,但是没有从0开始,而你又返回了type的真正数量,会出现数组越界异常。(比如type定义为1,2,3 getViewTypeCount中返回3,这是会数组越界)

5.最后的结论就是:1)从0开始连续定义type的值。2)在getViewTypeCount函数中,返回定义type的个数。     只要遵守这两条,就不会出现任何问题。就可以实现在一个ListView中显示不同类型的Item的效果了。

最后送上自己的实验代码:(传上去的代码都是能够正确运行的,大家可以按照本篇文章的说明来修改不同的值,来验证一下在各种情况下会发生什么样的错误。)顺便提一句,如果我们在getView中判断type的值时写错了,也可能会发生空指针异常(比如type为0,1,2 但是你switch type的值的时候写成了1,2,3)  好,不啰嗦了,下面是代码的地址,有兴趣的同学可以下载实验一下哦~

http://download.csdn.net/detail/awy1988/8543367


猜你喜欢

转载自blog.csdn.net/awy1988/article/details/44708579