最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
解决Android中Listview显示错乱问题
时间:2014-12-04 编辑:简简单单 来源:一聚教程网
问题
最近在项目中遇到过一个很棘手的问题,就是ListView在滑动后就莫名其妙的显示错乱,网上查阅资料后问题很容易的就解决了,但是对于问题产生的原因仍是一知半解,所以不甘心的我定下心来,狠读源码,终于理清了其中的”奥秘“。
由来
一般的关于Adapter中getView的写法不外乎以下形式:
代码如下 | 复制代码 |
@Override if (convertView == null) { |
在Android源码中关于getView方法的实现就是采用的以上形式,如ArrayAdapter等。因为这种写法的好处也是显而易见的,如果该position的convertview曾经被加载过,在数据集合未被改动的前提下,系统会自动将该position的convertview缓存起来,避免重复加载耗费资源。
然后问题就来了,当时我就”自作小聪明“,觉得当convertview==null时只是做了item布局的加载以及相关控件ID的绑定操作,为什么连内容的加载操作也放入其中呢,这样下次加载缓存是就省去内容set的操作了,然后就出现了滑动ListView后数据显示错位的问题-。-。
原因
后来看源码发现,原来AbListView中获取getView()和滑动操作是异步进行的,其中滑动操作在一个FlingRunnable的支线程中运行,所以这就导致了在ListView在滑动时可能已经滑动到了第十行,但可能第二行的数据这时就被直接使用了,这就是导致数据加载错乱的根本原因。
附上源码中对FlingRunnable的注释:
代码如下 | 复制代码 |
/** |
解决方法
所以唯一的解决方法就是只在convertview中缓存该ChildView的layout,但ChildView 中的数据必须每次都重新获取并加载。其实ListView数据加载及数据缓存是比较复杂的(几个相关的类加起来上完行=。=),所以以后有机会还是要好好研读源码,这样才能更加透彻的理解原理。
另一种情况 ListView滚动后内容重复的问题
最简单的解决方法就是,在上面的代码中不去判断赋值内容是否为空,而是直接设定对应该控件的值,即使用事例代码中的注释部分。(去掉上面代码中的if段)
真正的解决方法,则规避不对ViewHolder中的元素进行赋值这种情况。拿上面的代码来说:
代码如下 | 复制代码 |
If (!t == null){ mViewHolder.nameText.setText(t); } |
这个时候,在t == null 时,就没有对viewHolder进行赋值,所以在t == null时,界面上的元素就有可能是没有更新的,也就是重复上一个(这个位置视图)。所以可以加上一个else,并在里面对viewholder进行赋值。
代码如下 | 复制代码 |
If (!t == null){ mViewHolder.nameText.setText(t); }else{ mViewHolder.nameText.setText("unknow"); } |
这样问题就很好的解决了。
另外一种情况就是:
// 如果子控件为ImageView,当赋值内容为空时,直接设定默认的图像资源。如果使用setBackgroundResource可能出现默认的图像资源没有真正的设定到ImageView,必须使用setImageResource。setBackgroundResource是View类中的方法,而setImageResource是ImageView自己的方法。使用前者可能导致图像没有真正的设定到ImageView,此时ImageView显示上一次赋值的图像。