Recyclerview Объединение переработанных вьюхолдеров

У меня есть вид переработчика. У меня много просмотров для разных типов контента.

Я создаю свои держатели следующим образом:

  /**
     * Create instance of
     * compatible viewholder
     *
     * @param viewType
     * @param parent
     * @return
     */
    private AbstractHolder createAbstractHolder(int viewType, ViewGroup parent) {
        AbstractHolder holder = null;

        switch (viewType) {
            case VersyConstants.HOLDER_TYPE_1:
                holder = ViewHolder_Var1.create(parent, mUserHomeFragment, mUserStreamFragment);

                break;

            case VersyConstants.HOLDER_TYPE_2:
                holder = ViewHolder_Var2.create(parent, mUserHomeFragment, mUserStreamFragment);
                break;

            case VersyConstants.HOLDER_TYPE_3:
                holder = ViewHolder_Var3.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 3");
                break;

            case VersyConstants.HOLDER_TYPE_4:
                holder = ViewHolder_Var4.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 4");
                break;

            case VersyConstants.HOLDER_TYPE_5:
                holder = ViewHolder_Var5.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 5");
                break;

            case VersyConstants.HOLDER_TYPE_6:
                holder = ViewHolder_Var6.create(parent,  mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 6");
                break;

            case VersyConstants.HOLDER_TYPE_7:
                holder = ViewHolder_Var7.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 7");
                break;

            case VersyConstants.HOLDER_TYPE_8:
                holder = ViewHolder_Var8.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 8");
                break;

            case VersyConstants.HOLDER_TYPE_9:
                holder = ViewHolder_Var9.create(parent, mUserHomeFragment, mUserStreamFragment);
                break;

            case VersyConstants.HOLDER_TYPE_10:
                holder = ViewHolder_Var10.create(parent, mThumbnailViewToLoaderMap, mUserHomeFragment, mUserStreamFragment);
        }
        return holder;
    }

Проблема в том, что у меня возникает, когда я прокручиваю свой вид ресайклера вниз, и, например, держатель представления 3 создается для 1-го элемента и 5-го элемента, когда я прокручиваю обратно вверх до элемента №. 1, он переработал держатель представления из 5-го элемента, который, как я знаю, является идеей представления переработчика.

В средствах просмотра я скрываю/показываю текстовые представления, если соответствующие данные поступают в формате JSON. Я показываю хэш-теги, если они есть, поэтому в моем первом пункте ниже:Элемент 1 Recyclerview — без тегов

Затем, когда я прокручиваю вниз до 5-го элемента с тегами (ниже):Recyclerview 5-й элемент с тегами

Затем, когда я прокручиваю назад до первого элемента, теги добавляются, когда они не должны быть, поскольку с этим объектом не связаны данные тега (см. Ниже):

Первый элемент теперь с тегами

Я отладил, и в данных объекта нет путаницы, нет тегов, добавленных через код, это связано с переработкой recyclerview, оба этих элемента имеют один и тот же держатель представления (держатель представления 3). Есть ли способ предотвратить это?

Ниже приведен метод заполнения тегов. В зависимости от размера списка я устанавливаю видимость текстового представления видимым и заполняю:

 protected void populateTags(List<String>tags, TextView[] array){
        for(int i=0;i<tags.size(); i++){
            array[i].setText(tags.get(i));
            array[i].setVisibility(View.VISIBLE);
        }
    }

Я называю приведенное выше так: List<String> tagsList = feedContent.getTags(); if(tagsList.size>0)populateTags(tagsList, tagsArray); Это происходит не только с пунктами 1 и 5, это зависит от того, какие представления используются повторно. Если есть представление, повторно используемое для представления, уже отображающего теги, добавляются теги из повторно используемого представления. Это очень плохо


person DJ-DOO    schedule 21.10.2015    source источник


Ответы (2)


По сути, RecyclerView — это переработка. Он повторно использует контейнеры, но не сбрасывает их!

Это означает, что каждый раз, когда вы заполняете ViewHolder данными, вам нужно как добавлять новые данные, так и удалять старые данные (или скрывать некоторые представления). Если вы этого не сделаете, вы получите данные из ранее надутого объекта :-(

РЕДАКТИРОВАТЬ: Итак, если у вас есть что-то подобное в вашем коде раздувания

if(item.getTagsCount() > 0)
    tags.setVisibility(View.VISIBLE);

вам нужно обновить его до чего-то вроде этого

if(item.getTagsCount() > 0)
    tags.setVisibility(View.VISIBLE);
else 
    tags.setVisibility(View.GONE);

or

if(item.getTagsCount() > 0)
    tags.setVisibility(View.VISIBLE);
else if(item.getTagsCount() == 0)
    tags.setVisibility(View.GONE);

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

person Kelevandos    schedule 22.10.2015
comment
Спасибо за ответ. Я решил, что это проблема в порядке. Могу я спросить, каков самый чистый способ добиться этого? - person DJ-DOO; 22.10.2015
comment
Если вы имеете в виду автоматический способ, его нет (кроме повторного раздувания представления, но это противоречит всей идее RecyclerView). Смотрите обновленный ответ для общей концепции :-) - person Kelevandos; 22.10.2015
comment
Обновил его немного больше, чтобы лучше соответствовать вашей ситуации. - person Kelevandos; 22.10.2015
comment
Поскольку вы, кажется, разбираетесь в этом, не могли бы вы проверить аналогичную проблему, с которой я сталкиваюсь, с просмотром recyclerview и представлением изображения в держателе представления? stackoverflow.com/questions/33283493 / Заранее спасибо - person DJ-DOO; 22.10.2015

Итак, я нашел этот вопрос адаптер RecyclerView, принимающий неправильные значения на SO. Та же проблема, что и выше, но предложенный ответ не работает. Я заметил: «Обычно это происходит, когда у вас есть что-то вроде «if (field != null)holder.setField(field)», без else. Держатель переработан, это означает, что у него там будут значения, поэтому вам нужно очистить или замените КАЖДОЕ значение, если оно равно нулю, вы должны обнулить его, если нет, вы должны написать его ВСЕГДА. Уже поздно, но в качестве ответа для других». в комментариях. Поэтому я изменил свой вызов для заполнения с if(tagsList.size>0)populateTags(tagsList, tagsArray); на populateTags(tagsList, tagsArray);, поскольку у меня не было другого, и эта логика была в методе.

Вот и все.. надеюсь, кому-нибудь еще пригодится

person DJ-DOO    schedule 22.10.2015