Почему в RecyclerView adapter не всегда вызывается метод onCreateViewHolder?

Имею адаптер для RecyclerView с возможностью добавления двух разных view (view, progress).
Код реализации метода onCreateViewHolder:
//--Создание View--//
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder;
        if (viewType == POST_CARD_VIEW) {
            Log.d("TEST:", "onCreateViewHolder POST:" + test1);
            View view = inflater.inflate(R.layout.post_card, parent, false);
            viewHolder = new ViewHolderPost(view);
            test1 ++;
        }
        else {
            Log.d("TEST:", "onCreateViewHolder PROGRESS:" + test2);
            View view = inflater.inflate(R.layout.progres_bar, parent, false);
            viewHolder = new ProgressViewHolder(view);
            test2++;
        }
        return viewHolder;
    }


Код реализации метода onBindViewHolder:
//--Метод onBind--//
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        if (holder instanceof ViewHolderPost) {
            Log.d("TEST:", "onBindViewHolder POST:" + test3);
            holder.itemView.setTag(mData.get(position));
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.d("TEST:", "OnClick on Post: " + position);
                }
            });
            addData((ViewHolderPost) holder, mData.get(position));
            test3++;
            Log.d("TEST:", "------------------------------------------------------------------------");
        }
        else {
            Log.d("TEST:", "onBindViewHolder PROGRESS:" + test4);
            ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
            test4++;
            Log.d("TEST:", "------------------------------------------------------------------------");
        }
    }


Верстка контейнера для RecyclerView:
<FrameLayout
            android:id="@+id/container" <!--Контейнер для RecyclerView-->
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/appBarLayout"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <android.support.v4.widget.NestedScrollView
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/mScrollingContent"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#EEEEEE"
                android:isScrollContainer="false"
                android:theme="@style/AppTheme"
                app:layout_behavior="@string/appbar_scrolling_view_behavior">

            </android.support.v4.widget.NestedScrollView>
        </FrameLayout>

Допустим, передал я в адаптер 10 вьюшек, с ними все хорошо, они отобразились (создаются в таком случае по мере их появления на экране), но при скроллинге до 6 вьюшки метод onCreateViewHolder перестает вызываться, при этом метод onBindViewHolder вызывается по мере скроллинга дальше:
D/TEST:: onCreateViewHolder PROGRESS:0
D/TEST:: onBindViewHolder PROGRESS:0
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onCreateViewHolder POST:0
D/TEST:: onBindViewHolder POST:0
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onCreateViewHolder POST:1
D/TEST:: onBindViewHolder POST:1
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onCreateViewHolder POST:2
D/TEST:: onBindViewHolder POST:2
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onCreateViewHolder POST:3
D/TEST:: onBindViewHolder POST:3
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onCreateViewHolder POST:4
D/TEST:: onBindViewHolder POST:4
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onCreateViewHolder POST:5
D/TEST:: onBindViewHolder POST:5
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onBindViewHolder POST:6
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onBindViewHolder POST:7
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onBindViewHolder POST:8
D/TEST:: -----------------------------------------------------------------------
D/TEST:: onBindViewHolder POST:9
D/TEST:: -----------------------------------------------------------------------

Метод onScrolled переопределен, но что он пустой, что с логикой, ситуация не меняется.
Если сделать контейнером для RecyclerView NestedScrollView и удалить FrameLayout, ошибка пропадет (так, как onScrolled не вызывается) и будут созданы сразу все 10 вьюшек.

А так, как в методе onBindViewHolder у меня загружаются фото, получается ситуация, что вьюшка под номер 1 при скролле может иметь фото вьюшек под номер 10, 4, 6, 1...всех сразу(в методе динамичное создание ImageView).

Что я не верно сделал? Может чего то не хватает?
  • Вопрос задан
  • 2030 просмотров
Решения вопроса 2
zagayevskiy
@zagayevskiy Куратор тега Android
Android developer at Yandex
Так в этом смысл ресайклера. Он переиспользует вьюхи. По-вашему, если их будет 100, он должен создать 100 вьюх? Нет.
Ответ написан
Комментировать
ziginsider
@ziginsider
C#, Xamarin, Android, python
Принцип работы RecyclerView в общих словах:

1) прокручивается список, создаются вьюхи и выводятся на экран, при этом выполняется onCreateViewHolder() и onBindViewHolder() .

2) ушедшие за экран вьюхи не уничтожаются, а попадают в пул объектов.

3) При дальнейшем скролле, вьюхи появляющиеся из-за экране не пересоздаются, а берутся из этого самого пула . При этом срабатывает только onBindViewHolder().

Говоря отвлеченно, метод onCreateViewHolder() создает "бассейн", а метод onBindViewHolder() "наполняет бассейн водой". Если каждый раз, когда меняется представление (скролл) не "менять воду в бассейне" полностью т.е. не переопределять содержание всех элементов, которые могут измениться, в onBindViewHolder(), то вьюха может выдавать сюрпризы в виде старых значений.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы