欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

探究Android中Listview显示错乱问题

来源: 开发者 投稿于  被查看 45190 次 评论:59

探究Android中Listview显示错乱问题


问题
最近在项目中遇到过一个很棘手的问题,就是ListView在滑动后就莫名其妙的显示错乱,网上查阅资料后问题很容易的就解决了,但是对于问题产生的原因仍是一知半解,所以不甘心的我定下心来,狠读源码,终于理清了其中的”奥秘“。
 
由来
一般的关于Adapter中getView的写法不外乎以下形式:
 
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
 
if (convertView == null) {
convertView = mLayout.inflate(R.layout....);
holder = new ViewHolder();
holder.textView = (TextView) convertView
.findViewById(R.id.textview);
... ...
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textView.setText(mText + position);
return convertView;
}
在Android源码中关于getView方法的实现就是采用的以上形式,如ArrayAdapter等。因为这种写法的好处也是显而易见的,如果该position的convertview曾经被加载过,在数据集合未被改动的前提下,系统会自动将该position的convertview缓存起来,避免重复加载耗费资源。
 
然后问题就来了,当时我就”自作小聪明“,觉得当convertview==null时只是做了item布局的加载以及相关控件ID的绑定操作,为什么连内容的加载操作也放入其中呢,这样下次加载缓存是就省去内容set的操作了,然后就出现了滑动ListView后数据显示错位的问题-。-。
 
原因
后来看源码发现,原来AbListView中获取getView()和滑动操作是异步进行的,其中滑动操作在一个FlingRunnable的支线程中运行,所以这就导致了在ListView在滑动时可能已经滑动到了第十行,但可能第二行的数据这时就被直接使用了,这就是导致数据加载错乱的根本原因。
附上源码中对FlingRunnable的注释:
 
/**
 * Responsible for fling behavior. Use {@link #start(int)} to
 * initiate a fling. Each frame of the fling is handled in {@link #run()}.
 * A FlingRunnable will keep re-posting itself until the fling is done.
 *
 */
private class FlingRunnable implements Runnable {
    /**
     * Tracks the decay of a fling scroll
     */
    private final OverScroller mScroller;
... ...
}
解决方法
所以唯一的解决方法就是只在convertview中缓存该ChildView的layout,但ChildView 中的数据必须每次都重新获取并加载。其实ListView数据加载及数据缓存是比较复杂的(几个相关的类加起来上完行=。=),所以以后有机会还是要好好研读源码,这样才能更加透彻的理解原理。

用户评论