android studio listview|解决Android中Listview显示错乱问题

时间:2019-08-19  来源:js教程  阅读:

问题

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

另一种情况 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显示上一次赋值的图像。

android studio listview|解决Android中Listview显示错乱问题

http://m.bbyears.com/wangyezhizuo/63124.html

推荐访问:android listview优化
相关阅读 猜你喜欢
本类排行 本类最新