Android 带有 CursorAdapter bindView 的 ListView 在滚动时工作错误

Android ListView with CursorAdapter bindView works erroneous when scrolling

我已经阅读了几个小时的解决方案,但我仍然没有找到正确的答案。我有一个带有 CursorAdapter 的 ListFragment。行如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/circle"
        android:src="@drawable/white_circle"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="italic"
        android:textColor="#C0C0C0"
        android:textSize="20sp"
        android:id="@+id/tvStationName"
        android:layout_toRightOf="@+id/circle"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_alignBottom="@+id/way"
        android:gravity="top|start"
        android:layout_marginLeft="5dp"/>
    <ImageView
        android:id="@+id/way"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/circle"
        android:src="@drawable/white_way"/>
</RelativeLayout>

由于 ListFragment 表示一条路线,其中有车站(圆圈)和车站之间的道路(路),我不希望在最后一站之后出现道路。因此,我更改了最后一个 listview 元素的图像资源。问题如下:

如果我向下滚动列表,似乎一切正常。然后,滚动回顶部,如果它是列表的最后一个元素,则在两个中间站之间至少缺少一种方式。当我滚动更多时,我会得到更多丢失的方式,有时我会找回一些,这似乎是随机的。

适配器class的代码如下:

public class StationAdapter extends CursorAdapter {

    private static final String TAG = "StationAdapter";
    private Route route;
    private Cursor storedCursor;
    private LayoutInflater storedInflater;

    private final class ViewHolder {
        public TextView stationTv;
        public ImageView stationIv;
        public ImageView wayIv;
    }

    public StationAdapter(Context context, Cursor cursor, Route route) {
        super(context, cursor, false);
        this.route = route;
        this.storedCursor = cursor;
        this.storedInflater = LayoutInflater.from(context);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        final LayoutInflater inflater = LayoutInflater.from(context);
        View row = inflater.inflate(R.layout.station_list_row, null);
        bindView(row, context, cursor);
        return row;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (storedCursor.moveToPosition(position)) {
            ViewHolder holder;
            if (convertView == null) {
                convertView = storedInflater.inflate(R.layout.station_list_row, null);
                holder = new ViewHolder();
                holder.stationTv = (TextView)convertView.findViewById(R.id.tvStationName);
                holder.stationIv = (ImageView)convertView.findViewById(R.id.circle);
                holder.wayIv = (ImageView)convertView.findViewById(R.id.way);
                convertView.setTag(holder);
            }
            else {
                holder = (ViewHolder)convertView.getTag();
            }
            Station station = DbLoader.getStationByCursor(storedCursor);
            // now we use the references
            holder.stationTv.setText(station.getName());
            if (station.equals(route.lastStation())) {
                holder.wayIv.setImageResource(R.drawable.zero_way);
            }
        }
        return convertView;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        // UI elements
        TextView stationTv = (TextView)view.findViewById(R.id.tvStationName);
        ImageView wayIv = (ImageView)view.findViewById(R.id.way);
        ImageView stationIv = (ImageView)view.findViewById(R.id.circle);
        // station by cursor
        Station station = DbLoader.getStationByCursor(cursor);
        // set UI label
        stationTv.setText(station.getName());
        if (station.equals(route.lastStation())) {
            wayIv.setImageResource(R.drawable.zero_way);
        }
    }

    @Override
    public Station getItem(int position) {
        getCursor().moveToPosition(position);
        return DbLoader.getStationByCursor(getCursor());
    }
}

我不想引用太多细节,希望这些就足够了。

提前致谢。

问题是适配器试图提高效率。重用您滚动离开的视图。

如果您有条件更改视图的默认位置,则需要设置视图的默认位置。

例如,如果您更改背景图片。当该视图被回收时,它将在重复使用时使用相同的图像。

if (station.equals(route.lastStation())) {
    holder.wayIv.setImageResource(R.drawable.zero_way);
}

例如,需要重置为默认值。

if (station.equals(route.lastStation())) {
    holder.wayIv.setImageResource(R.drawable.zero_way);
} else {
    holder.wayIv.setImageResource(R.drawable.white_way);
}