Хобрук: Ваш путь к мастерству в программировании

RecyclerView дублирует элементы

Мой 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

Код адаптера обновлен


  • установите priceList и modelList как глобальные, переместите modelList.add(new Checklist(intent.getStringExtra("q"+i), priceList)); за пределы цикла for и попробуйте 22.02.2019
  • @JohnJoe Таким образом, у меня есть только один вопрос и только 3 переключателя. Мне нужны все вопросы (изображения 5.10, 5.11, 5.12 и другие) с 3 переключателями для каждого вопроса. 22.02.2019
  • опубликуйте свой код чек-листа 22.02.2019
  • @JohnJoe отредактировано 22.02.2019
  • @Alan, вы должны использовать этот метод recyclerViewAdapter.notifyDataSetChanged(); после setAdapter 22.02.2019
  • @RakeshKumar Я безуспешно пробовал. 22.02.2019
  • @ Алан, тебе понравился мой ответ? 22.02.2019
  • @Alan Это повторяется только один раз или несколько раз при прокрутке? 22.02.2019
  • @ Алан, ты позаботился о том, чтобы убрать второй recyclerViewAdapter = new ChecklistAdapter(modelList,this);, когда пробовал предложение @Rakesh Kumar? 22.02.2019
  • @ Алан, тебе не нужно звонить recyclerViewAdapter = new ChecklistAdapter(modelList,this); дважды 22.02.2019
  • @RakeshKumar Я знаю, это был просто тест. 22.02.2019
  • @ Алан, ты проверял размер списка на адаптере packageList = packageListIn; ?? У тебя так же??? 22.02.2019

Ответы:


1

Я воспроизвел вашу проблему.

добавление holder.priceGroup.removeAllViews(); к 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;
    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);
    }
}

Вы добавляли к представлению каждый раз, не удаляя предыдущие представления.

22.02.2019
  • Потрясающий. Оно работает. Я также удалил setHasStableIds и getItemViewType, возможно, это может помочь кому-то еще. Спасибо всем за ваше время. 22.02.2019
  • Не беспокойтесь, я даже не включил их, когда копировал ваш код, просто использовал оригинал. 22.02.2019
  • Только что понял еще одну вещь, он больше не дублируется, но теряет выбранные радиоприемники при прокрутке. 22.02.2019
  • радиоприемники, которые вы нажали, скажем, на вопрос 3? и вы прокручиваете вниз, чтобы сказать вопрос 25, а затем вернуться к вопросу 3? и это не проверено? В этом проблема? 22.02.2019
  • Да, это проблема. 22.02.2019
  • на самом деле я понимаю, что представления уничтожаются каждый раз, когда вы прокручиваете, вам нужно будет хранить эти данные и извлекать их, когда вы возвращаетесь, и устанавливать их, когда вы возвращаетесь к представлению. 22.02.2019
  • См. ответы здесь 22.02.2019
  • Еще один раз мне помог. 22.02.2019
  • СПАСИБО СПАСИБО СПАСИБО!!!!. У меня похожая проблема, потому что я добавлял представления к родителю как recyclerview. Данные дублировались после добавления новых данных/прокрутки, теперь я знаю почему, спасибо!!!! 30.04.2020

  • 2

    Используйте holder.setIsRecyclable(false) в onCreateViewHolder()

    Это сработало для меня.

    17.04.2020
  • Это помогло решить проблему с ViewPager2 и адаптером ресайклера с несколькими типами представления. 05.05.2020
  • Это нарушит реальный вариант использования представления ресайклера. 24.02.2021

  • 3

    вы должны установитьHasStableIds(true) для своего адаптера в своей деятельности.

    и в вашем классе адаптера вы должны установить метод ниже. Это может помочь вам. это работа для меня.

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

    ты хочешь такой?

    введите здесь описание изображения

    22.02.2019
  • теперь повторяются все предметы, а не только радио. 22.02.2019
  • Я сделал это, как ты сказал. Я хочу именно то, что вы показываете на своей картинке, но только с 3 радиоприемниками для каждого вопроса. С вашим кодом его дублирование. 22.02.2019

  • 4

    Поместите держатель.setIsRecyclable(false) в onBindViewHolder(), как показано ниже.

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

    5

    Переопределите приведенный ниже метод в ChecklistAdapter.

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

    И в вашем onCreate() добавьте:

    recyclerViewAdapter.setHasStableIds(true);
    
    22.02.2019
  • Я получил сообщение об ошибке: Невозможно изменить, имеет ли этот адаптер стабильные идентификаторы, пока в адаптере зарегистрированы наблюдатели. 22.02.2019
  • @Alan Вы должны использовать recyclerViewAdapter.setHasStableIds(true); перед packageRecyclerView.setAdapter(recyclerViewAdapter); 22.02.2019
  • @Alan stackoverflow.com/questions/52460141/ надеюсь, что это поможет вам 22.02.2019
  • Он больше не дублирует радиоприемники, но переупорядочивает предметы и радиоприемники, поэтому я не могу получить ответы. 22.02.2019
  • @Alan Алан, вы переопределяете getItemViewType() в адаптере? 22.02.2019
  • помните, что вы комментируете блок кода, который изменяет lastCheckedRadioGroup 22.02.2019
  • вам не нужно иметь getItemViewType() в вашем адаптере, так как в нем есть только 1 тип элементов; поэтому, пожалуйста, удалите его 22.02.2019
  • заменить вернуть super.getItemId (позиция); только с возвратом позиции; 22.02.2019
  • С этим изменением он вернулся, дав мне 6 радиостанций. 22.02.2019
  • @ Алан, проверь мой новый ответ. 22.02.2019

  • 6

    Вам просто нужно вызвать list.clear(); перед вставкой в ​​RecyclerViewAdapter. затем звоните после звонка adapter.notifyDatasetChange()

    11.07.2020
  • Пожалуйста, не делитесь изображением кода вместо фрагмента кода. 11.07.2020

  • 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();
    
    22.02.2019
  • То же самое, когда я прокручиваю, элементы дублируются. 22.02.2019
  • Вы создаете modelList в цикле for, удаляете его из цикла for и добавляете данные только один раз. 22.02.2019
  • modelList создается перед циклом for, я просто добавляю в него элементы внутри цикла for. 22.02.2019
  • Да, в этом проблема, вы добавляете данные в цикле, поэтому ваш список будет содержать одни и те же данные три раза. 22.02.2019
  • Взгляните на изображение, в цикле я добавляю один заголовок (вопрос с изображением) и 3 переключателя к каждому вопросу. Когда я прокручиваю, он дублируется до шести переключателей. 22.02.2019

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

    Надеюсь, что это поможет вам.

    22.02.2019
  • @Alan, если ваш элемент дублируется при прокрутке, то это проблема в вашем onBindViewHolder, когда вы добавляете переключатель в группу переключателей. Это связано с тем, что каждый раз при прокрутке вызывается метод onBindViewHolder и добавляется новый переключатель 22.02.2019
  • Можете ли вы объяснить больше, пожалуйста? Ваш ответ не решил проблему. 22.02.2019
  • @ Алан, я добавил еще один ответ. 22.02.2019

  • 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)
            }
        }
    }
    

    Я думаю, что это решает вашу проблему. Удачного кодирования

    22.02.2019
  • Список повторяющихся кадров. :( 22.02.2019
  • Новые материалы

    Решения DBA Metrix
    DBA Metrix Solutions предоставляет удаленного администратора базы данных (DBA), который несет ответственность за внедрение, обслуживание, настройку, восстановление базы данных, а также другие..

    Начало работы с Блум
    Обзор и Codelab для генерации текста с помощью Bloom Оглавление Что такое Блум? Некоторые предостережения Настройка среды Скачивание предварительно обученного токенизатора и модели..

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...