【问题标题】:Android ListView: Changes made to Items affect other ItemsAndroid ListView:对项目所做的更改会影响其他项目
【发布时间】:2016-03-19 07:24:42
【问题描述】:

我知道这是使用 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 模式?

【问题讨论】:

    标签: java android listview android-adapter


    【解决方案1】:

    您的代码看起来是正确的,所以我会大胆猜测并说您从外部修改了支持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;
    }
    

    【讨论】:

    • 感谢您的回答! :) 我有点困惑。什么是 setItems 以及何时调用?还有,为什么要清空构造函数?
    • 1) 每当您对数据集进行更改时,请致电setItems。这包括添加项目、删除项目、修改项目、移动项目。 2) 构造函数是空的,因为我在那里不需要任何东西。当我需要 ListView(父级)时,我会从 ListView(父级)获得一个 LayoutInflater,这应该避免任何与主题相关的问题(想象活动的主题与列表视图不同)。
    【解决方案2】:

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

    还有一件奇怪的事情。 getViewTypeCount() 返回您想在列表中增加的 XML 数量。如果您只有 1 个 xml,则返回 1 是可以的(但是,对于我来说,当它为 1 时,显式编写此方法是多余的)。但是在 getItemViewType() 中,您应该根据项目获得一个或另一个 viewType 来编写条件。然后你返回当前位置,最好修复它:)

    【讨论】:

    • 我改变了行中的文本视图:' holder.name.setText(set.getUser().getName());'适配器内部
    【解决方案3】:

    通过使用阵列适配器

    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;
    }
    

    【讨论】:

    • 你能解释一下你在这里做了什么改变吗?
    • 是的,当然.. 我删除了 final 关键字并使用帮助位置在 arraylist 中获取值
    • 我使用 BaseAdapter 但没有运气的伙伴。还是有问题
    • 你能分享我的课程吗?
    • 只是字符串名称,在该类中有一个 getter setter
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多