Android ListView:对项目所做的更改会影响其他项目

时间:2016-03-19 07:24:42

标签: java android listview android-adapter

我知道这是使用ListView时遇到的一个非常常见的问题。但是,我没有发现我的实现有任何问题,因为我已经正确地使用ViewHolder模式作为我的自定义适配器。

问题:

对项目所做的更改(例如一次更改textview文本)会在向下/向上滚动时影响其他随机项目。当我向上滚动时,原始项目以及其他项目都会更改。

可以使用 ViewHolder 模式修复此问题。这很奇怪我仍然遇到问题!

适配器代码:

public class TrackerAdapter extends BaseAdapter {
    private Activity activity;
    private static LayoutInflater inflater = null;
    ArrayList <Set> sets = new ArrayList <> ();

    public TrackerAdapter(Activity a, final ArrayList <Set> sets) {
        this.activity = a;
        this.inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.sets = sets;
    }

    public int getCount() {
        return sets.size();
    }
    public Set getItem(int position) {
        return sets.get(position);
    }
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    @Override
    public int getItemViewType(int position) {
        return position;
    }

    public View getView(final int position, View convertView, ViewGroup parent) {
        View view = convertView;
        final Set set = sets.get(position);
        final Holder holder;
        try {
            if (view == null) {
                view = inflater.inflate(R.layout.row_single, null);
                holder = new Holder();
                holder.name = (TextView) view.findViewById(R.id.name);
                view.setTag(holder);
            } else {
                holder = (Holder) view.getTag();
            }
            holder.name.setText(set.getUser().getName());
        } catch (Exception ex) {
            Log.d("CHECK", "Error at TrackerAdapter");
            Log.d("CHECK", Log.getStackTraceString(ex));
        }
        return view;
    }
    public static class Holder {
        TextView name;
    }
}

您在我的代码中看到了什么问题?我是否正确实现了ViewHolder模式?

3 个答案:

答案 0 :(得分:0)

使用阵列适配器

Holder holder = new Holder();
if (convertView == null) {
    convertView = inflater.inflate(R.layout.row_single, null);
    holder.name = (TextView) view.findViewById(R.id.name);
    convertView.setTag(holder);
} else {
    holder = (Holder) convertView.getTag();
}
holder.set = getItem(position);
holder.name.setText(holder.set.getUser().getName());
public static class Holder {
    TextView name;
    Set set;
}

使用基本适配器

Holder holder = new Holder();
if (convertView == null) {
    convertView = inflater.inflate(R.layout.row_single, null);
    holder.name = (TextView) view.findViewById(R.id.name);
    convertView.setTag(holder);
} else {
    holder = (Holder) convertView.getTag();
}
holder.name.setText(sets.get(position).getName());
public static class Holder {
    TextView name;
}

答案 1 :(得分:0)

您更改TextView文本的方式是什么?在TextView本身或ArrayList的相应项中,然后只是adapter.notifyDataSetChanged()?

还有一件奇怪的事。 getViewTypeCount()返回您希望在列表中膨胀的XML数。如果你只有1 xml,那么返回1就可以了(但是,对于我来说,当它为1时,显式地写这个方法是多余的)。但是在getItemViewType()中,您应该根据项目获取一个或另一个viewType来编写条件。你返回当前位置,更好地解决它:)

答案 2 :(得分:0)

您的代码看起来是正确的,所以我会猜测并说您从外部修改了支持ArrayList。如果在进行更改后未通知ListView,则无法执行此操作。

以下代码将解耦您的工作数组和显示的数据。

final ArrayList <Set> sets = new ArrayList <> ();

public TrackerAdapter() {
}

public void setItems(ArrayList<Set> sets) {
    this.sets.clear();
    this.sets.addAll(sets)
    notifyDataSetChanged();
}

public View getView(final int position, View convertView, ViewGroup parent) {
    View view = convertView;
    final Set set = sets.get(position);
    final Holder holder;

    if (view == null) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);
        view = inflater.inflate(R.layout.row_single, parent, false);
        holder = new Holder();
        holder.name = (TextView) view.findViewById(R.id.name);
        view.setTag(holder);
    } else {
        holder = (Holder) view.getTag();
    }

    holder.name.setText(set.getUser().getName());

    return view;
}