android ListView 在初始化时多次调用getView()原因分析

   今天在做一个功能:在初始化ListView时,把第一行背景置为黄色,同时保存第一行对象,用于在点击其他行时将该行重新置为白色。

if(position==0){
                convertView.setBackgroundColor(Color.YELLOW);
                lastconvertView=convertView;
            }

 

结果运行时发现第一行的颜色一直会是黄色而无法改变。调试了之后发现getView中 if(position==0) 居然会多次进入,最终导致的结果便是我最后一次取得的lastconvertView并非listview上面的第一行。网上查了之后发现原因是因为未固定listview的高度导致的,但是root cause却找不到说明。于是去翻阅了源码+大量调试,大概推算出了原因,在此记录。

首先是说明下ListView的显示机制,listview的机制是这样子的:

假如你有1000条数据,但是屏幕只能显示10条,那么当你第一次加载显示的时候,会先创建10个View,1-10,当你拖动Listview,使1隐藏而11显示的时候,系统会自动把填充1的View传递过来,注意看代码Adapter的getView方法

@Override
public View getView(final int position, View convertView, ViewGroup parent) 

这里的converView就是1的view,一般的做法会把这个view拿来复用,作为11的view。

 

当我们固定listview的高度时(fill_parent或直接固定高度),那么listview很容易就能计算出容器内可以显示多少行。但如果我们使用了“wrap_content”,只有在屏幕内控件完全加载后才知道到底能显示多少行数据时,ListView自身便会做一些尝试性计算。在源码中可以发现一些叫做onMeasure的方法,目测是做此用处(源码略显复杂,没读透)。

当listview计算出屏幕一共需要多少行后,如果listview自身高度不变,那么它的容纳的行数就不会变,使用getChildCount()可以得到它的最大行数。

再回到原来的问题,为什么最后一次取得的结果不是listview的第一行呢? 将listview设置为“wrap_content”后用下面的测试代码,看下输出。

//获取当前listview的个数 相等输出个数和站点名 不相等输出个数和"无"
            if(listView.getChildCount() == position)
            {
                //child个数 当前position位置 +站名
                Log.i("", listView.getChildCount()+" "+position+" "+coordInfo.stationname);
            }
            else {
                //child个数 当前position位置+无
                Log.i("", listView.getChildCount()+" "+position+" "+"无");
            }

android ListView 在初始化时多次调用getView()原因分析_第1张图片

在我的测试应用中,listview刚好可以放11个view,看下输出发现,listview在开始时,实例化了11个view进行填充,即前面10个“无”结尾的+第一个”客运中心“结尾的view,由此测量出了listview的容量。换句话说,这11个view都只是用于测量的临时view。另外在正是填充完之后,listview再次创建了11个临时view用于确认高度是否正确。而由于我的代码逻辑设计失误,在

android ListView 在初始化时多次调用getView()原因分析_第2张图片

进行到这一步时,由于position会再次等于0,因此会把一个临时的view赋值给lastconvertView。

到此原因找到,同时将listview的高度设为fill_parent后,问题解决。

 

另外说下网上说的另外一个解决方法

if(parent.getchildcount() == position)
{
       正常情况下应该执行的代码
}
else
{
     这里就是多次加载的问题,可以不用理这里面的 代码,
}

这个方法是不可行的,因为在不改变listview高度的情况下,listview的getchildcount()在加载完成后是固定的,position指的却是在adapter中的位置,当adapter的个数大于listview的容纳个数时,该判断条件不会成立,即滑动listview时,不会成立。

转载于:https://www.cnblogs.com/linjzong/p/3494090.html

你可能感兴趣的:(android ListView 在初始化时多次调用getView()原因分析)