【问题标题】:RecyclerView is duplicating itemsRecyclerView 正在复制项目
【发布时间】:2019-02-22 02:31:13
【问题描述】:

当我滚动它时,我的 recyclerview 正在复制项目,我已经打电话给 adapter.notifyDataSetChanged()

所以,可能我在错误的地方调用了数据集更新,但我找不到它是如何工作的。

这里有一些代码:

       RecyclerView packageRecyclerView;
        Intent intent;
        ChecklistAdapter recyclerViewAdapter;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_checklist);
    
            intent = getIntent();
            size = intent.getIntExtra("size", 0);
            Log.d(TAG, "onCreate - Qtd Questões: " + size);
    
            packageRecyclerView = findViewById(R.id.package_lst);
    
            LinearLayoutManager recyclerLayoutManager = new LinearLayoutManager(this);
            packageRecyclerView.setLayoutManager(recyclerLayoutManager);
    
            DividerItemDecoration dividerItemDecoration =
                    new DividerItemDecoration(packageRecyclerView.getContext(),
                            recyclerLayoutManager.getOrientation());
            packageRecyclerView.addItemDecoration(dividerItemDecoration);
    
            List<Checklist> modelList = new ArrayList<>();
            recyclerViewAdapter = new ChecklistAdapter(modelList,this);
            modelList = getPackages();
            recyclerViewAdapter = new ChecklistAdapter(modelList,this);
    
    //        recyclerViewAdapter = new ChecklistAdapter(getPackages(),this);
    
            packageRecyclerView.setAdapter(recyclerViewAdapter);
    
    
        }
    
        private List<Checklist> getPackages() {
            List<Checklist> modelList = new ArrayList<>();
            Log.d(TAG, "getPackages: " + size);
            for (int i=0; i<size;i++) {
    
                List<String> priceList = new ArrayList<>();
                priceList.add("Sim");
                priceList.add("Não");
                priceList.add("Não se Aplica");
                modelList.add(new Checklist(intent.getStringExtra("q"+i), priceList));
            }
    
            recyclerViewAdapter.notifyDataSetChanged();
            return modelList;
        }

这是我的适配器:

    public class ChecklistAdapter extends
        RecyclerView.Adapter<ChecklistAdapter.ViewHolder> {

    private List<Checklist> packageList;
    private Context context;

    public ChecklistAdapter(List<Checklist> packageListIn
            , Context ctx) {
        packageList = packageListIn;
        context = ctx;
    }

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

    @Override
    public void setHasStableIds(boolean hasStableIds) {
        super.setHasStableIds(hasStableIds);
    }

    @Override
    public long getItemId(int position) {
        return super.getItemId(position);
    }

    @Override
    public ChecklistAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                                    int viewType) {

        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.rv_checklistlines, parent, false);

        ChecklistAdapter.ViewHolder viewHolder =
                new ChecklistAdapter.ViewHolder(view);
        return viewHolder;
    }


    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads) {
        super.onBindViewHolder(holder, position, payloads);
    }

    @Override
    public void onBindViewHolder(ChecklistAdapter.ViewHolder holder,
                                 int position) {
        Checklist packageModel = packageList.get(position);
        holder.packageName.setText(packageModel.getTitle());

        int id = (position+1)*100;
        for(String price : packageModel.getQuestions()){
            RadioButton rb = new RadioButton(ChecklistAdapter.this.context);
            rb.setId(id++);
            rb.setText(price);

            holder.priceGroup.addView(rb);
        }
    }

    @Override
    public int getItemCount() {
        return packageList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        public TextView packageName;
        public RadioGroup priceGroup;

        public ViewHolder(View view) {
            super(view);
            packageName = view.findViewById(R.id.package_name);
            priceGroup = view.findViewById(R.id.price_grp);

            priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(RadioGroup radioGroup, int i) {

                    Toast.makeText(ChecklistAdapter.this.context,
                            "Radio button clicked " + radioGroup.getCheckedRadioButtonId(),
                            Toast.LENGTH_SHORT).show();
                    
                }
            });
        }
    }
}
    

在下图中,您可以看到单选按钮是重复的,并且所有行中都有一些额外的空白区域。我在这里和其他论坛上看到了很多关于此的问题,但我不清楚在哪里调用此更新数据集。

我不是高级Android开发者,所以如果你能解释一下,对我来说会更容易。

编辑 1

清单类:

       import java.util.List;
    
    public class Checklist {
    
        String title;
        List<String> questions;
    
        public Checklist(String title, List<String> questions) {
            this.title = title;
            this.questions = questions;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public List<String> getQuestions() {
            return questions;
        }
    
        public void setQuestions(List<String> questions) {
            this.questions = questions;
}

编辑 2

适配器代码已更新

【问题讨论】:

  • priceListmodelList设置为全局,将modelList.add(new Checklist(intent.getStringExtra("q"+i), priceList));移出for循环并尝试
  • @JohnJoe 这样我只有一个问题,只有 3 个单选按钮。我想要所有问题(图片 5.10、5.11、5.12 等),每个问题都有 3 个单选按钮。
  • 发布您的清单代码
  • @JohnJoe 已编辑
  • @Alan, 你应该在setAdapter之后使用这个方法recyclerViewAdapter.notifyDataSetChanged();

标签: android android-recyclerview notifydatasetchanged


【解决方案1】:

onCreateViewHolder() 中使用holder.setIsRecyclable(false)

它对我有用。

【讨论】:

  • 这有助于解决 ViewPager2 和具有多种视图类型的回收器适配器的问题
  • 这将违反recycler view的真实用例。
【解决方案2】:

我复制了你的问题。

onBindViewHolder 上添加holder.priceGroup.removeAllViews(); 将修复它。像这样:

 @Override
public void onBindViewHolder(ChecklistAdapter.ViewHolder holder,
                             int position) {
    Checklist packageModel = packageList.get(position);
    holder.packageName.setText(packageModel.getTitle());

    int id = (position+1)*100;
    holder.priceGroup.removeAllViews();

    for(String price : packageModel.getQuestions()){
        RadioButton rb = new RadioButton(ChecklistAdapter.this.context);
        rb.setId(id++);
        rb.setText(price);
        holder.priceGroup.addView(rb);
    }
}

您每次都添加到视图中而没有删除以前的视图。

【讨论】:

  • 太棒了。有用。我还删除了 setHasStableIds 和 getItemViewType,也许它可以帮助其他人。谢谢你的时间。
  • 刚刚意识到一件事,它不再重复,但是当我滚动时它会丢失选定的收音机。
  • 其实我明白,每次滚动时视图都会被破坏,您需要存储这些数据并在返回时检索它并在返回视图时设置它。
  • 查看答案here
  • 又一次帮助了我。
【解决方案3】:

您必须在您的活动中为您的适配器 setHasStableIds(true)。

在您的 Adapter 类中,您必须设置以下方法。它可能会帮助你。这对我有用。

  @Override
    public long getItemId(int position) {
        return position;
    }

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


    @Override
    public void setHasStableIds(boolean hasStableIds) {
        super.setHasStableIds(hasStableIds);
    }

你想要这样吗?

【讨论】:

  • 它现在正在重复所有项目,不仅仅是收音机。
  • 我按照你说的做了。我想要您在图片中显示的内容,但每个问题只有 3 个收音机。使用您的代码进行复制。
【解决方案4】:

您只需要在插入RecyclerViewAdapter 之前调用list.clear();。然后调用adapter.notifyDatasetChange()

【讨论】:

  • 请不要分享代码图片而不是代码片段。
【解决方案5】:

将 holder.setIsRecyclable(false) 放入 onBindViewHolder() 中,如下例所示。

@Override
    public void onBindViewHolder(UsageStatVH holder, int position) {
        holder.bindTo(list.get(position));
        holder.setIsRecyclable(false);
    }

【讨论】:

    【解决方案6】:

    请覆盖 ChecklistAdapter 中的以下方法

    @Override
    public long getItemId(int position) {
        return position;
    }
    

    在你的 onCreate() 中添加:

    recyclerViewAdapter.setHasStableIds(true);
    

    【讨论】:

    • 我收到一个错误:当适配器注册了观察者时,无法更改此适配器是否具有稳定的 ID。
    • @Alan 你必须使用 recyclerViewAdapter.setHasStableIds(true);之前 packageRecyclerView.setAdapter(recyclerViewAdapter);
    • @Alan stackoverflow.com/questions/52460141/… 希望对你有帮助
    • 它不再复制收音机,但它正在重新排序项目和收音机,所以我无法得到响应。
    • @Alan 你会覆盖适配器中的 getItemViewType() 吗?
    【解决方案7】:

    这是因为您将列表设置为三次适配器,

    此时我无法编写整个代码,但在您的代码中替换此块即可。

    试试这个代码,

        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(packageRecyclerView.getContext(), recyclerLayoutManager.getOrientation()); 
        packageRecyclerView.addItemDecoration(dividerItemDecoration);
        List<Checklist> modelList = new ArrayList<>(); 
        modelList = getPackages(); recyclerViewAdapter = new ChecklistAdapter(modelList,this);  
        packageRecyclerView.setAdapter(recyclerViewAdapter);
    

    并且还从您的 getPackages() 函数中删除以下行。

    recyclerViewAdapter.notifyDataSetChanged();
    

    【讨论】:

    • 还是一样,当我滚动时,项目重复。
    • 您正在 for 循环中制作 modelList,将其从 for 循环中删除并仅添加一次数据。
    • modelList 是在 for 循环之前创建的,我只是在 for 循环中添加项目。
    • 是的,这就是问题所在,您正在循环中添加数据,因此您列出的数据将包含三次相同的数据。
    • 看一下图片,在循环中我为每个问题添加一个标题(图片问题)和 3 个单选按钮。当我滚动它时,它会复制到六个单选按钮。
    【解决方案8】:

    代替

     List<Checklist> modelList = new ArrayList<>();
        recyclerViewAdapter = new ChecklistAdapter(modelList,this);
        modelList = getPackages();
        recyclerViewAdapter = new ChecklistAdapter(modelList,this);
        packageRecyclerView.setAdapter(recyclerViewAdapter);
    

    这样使用

        recyclerViewAdapter = new ChecklistAdapter(getPackages(),this);
        packageRecyclerView.setAdapter(recyclerViewAdapter);
    

    并修改您的 getPackages 方法,例如

    private List<Checklist> getPackages() {
     List<Checklist> modelList = new ArrayList<>();
     Log.d(TAG, "getPackages: " + size);
    
    for (int i=0; i<size;i++) {
       List<String> priceList = new ArrayList<>();
        priceList.add("Sim");
        priceList.add("Não");
        priceList.add("Não se Aplica");
        modelList.add(new Checklist(intent.getStringExtra("q"+i), priceList));
    }
    return modelList;
    }
    

    希望这会对你有所帮助。

    【讨论】:

    • @Alan 如果您的项目在您滚动时重复,那么当您在单选组中添加单选按钮时,这是您的 onBindViewHolder 中的问题。 这是因为每次滚动时,您的 onBindViewHolder 方法都会调用并添加新的单选按钮
    • 你能解释一下吗?您的回答没有解决问题。
    • @Alan 我添加了另一个答案。
    【解决方案9】:

    修改您的清单...

    public class Checklist {
    
        String title;
        List<String> questions;
        boolean isRadioButtonAdded;
    
        public Checklist(String title, List<String> questions) {
            this.title = title;
            this.questions = questions;
        }
        public boolean getIsAdded(){
            return isRadioButtonAdded;
        }
        
        public void setIsAdded(boolean isAdded){
            this.isRadioButtonAdded = isAdded;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public List<String> getQuestions() {
            return questions;
        }
    
        public void setQuestions(List<String> questions) {
            this.questions = questions;
    }
    

    并修改你的 onBindViewHolder

    @Override
    public void onBindViewHolder(ChecklistAdapter.ViewHolder holder,
                                 int position) {
        Checklist packageModel = packageList.get(position);
        holder.packageName.setText(packageModel.getTitle());
    
        int id = (position+1)*100;
        if(!packageModel.getIsAdded){
            for(String price : packageModel.getQuestions()){
                RadioButton rb = new RadioButton(ChecklistAdapter.this.context);
                rb.setId(id++);
                rb.setText(price);
    
                holder.priceGroup.addView(rb);
                packageModel.setIsAdded(true)
            }
        }
    }
    

    【讨论】:

    • 列出重复的剧照。 :(
    猜你喜欢
    • 1970-01-01
    • 2021-12-20
    • 2018-06-30
    • 2021-04-09
    • 2018-05-11
    • 2018-07-16
    • 1970-01-01
    • 2016-02-05
    • 1970-01-01
    相关资源
    最近更新 更多