问题
最近在项目中遇到过一个很扎手的问题,便是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数据加载及数据缓存是比较复杂的(几个相关的类加起来上完行=。=),所以今后有时机仍是要好好研读源码,这样才干愈加透彻的了解原理。