Удалите дочерние данные из адаптера RecyclerView, не затрагивая в настоящее время видимое представление - PullRequest
0 голосов
/ 01 июня 2018

Я строю бесконечный горизонтальный список прокрутки, используя представление Recycler.1-2 ребенка могут быть видны на экране все время (так как их ширина больше, чем область просмотра экрана, и поэтому у нас никогда не будет более 2 видимых детей).

Исходное состояние:

initial state


Пока пользователь выполняет прокрутку (он может прокручивать ОБА вперед и назад - но для этого примера давайте предположимони прокручивают BACKWARDS ), я извлекаю больше данных и добавляю их к данным моего адаптера.

Затем я звоню notifyItemRangeInserted - пока все хорошо.

После предварительного добавления:

After prepend and notifyItemRangeInserted


Время отсечения:

clipping the opposite end of data

В то же время я добавляю всех тех детей, которых проверяю, теперь у нас получается больше, чем MAX_DATASOURCE_CNT элементов висточник данных.

Предположим, что MAX_DATASOURCE_CNT для этого примера 6 .

Если мы это сделаем, я удаляю лишних дополнительных дочерних элементов из конца нашего источника данных иЗвоните notifyItemRangeRemoved.

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

Проблема:

devil

После того, как происходит процесс предварительной подготовки, если пользователь прокручивает слишком быстро, иногда onBindViewHolder(RecyclerView.ViewHolder holder, int position) get вызывается с помощью position == 0 (также holder.getAdapterPosition() == 0)

Это полностью портит мой взгляд, как если бы мой взгляд перепрыгнул к совершенно не относящемуся к делу ребенку и показывает его.

Текущее решение:

Я заметил, что если я удаляю весь процесс отсечения, который в основном состоит из следующих строк кода:

if (itemCountAfterPrepend > MAX_DATASOURCE_CNT) {

    int extraItemCnt = itemCountAfterPrepend - MAX_DATASOURCE_CNT;

    // remove every extra item from the end of the array
    removeRange(MAX_DATASOURCE_CNT, itemCountAfterPrepend);

    // and notify our adapter about the removal
    notifyItemRangeRemoved(MAX_DATASOURCE_CNT, extraItemCnt);
}

все работает нормально.Но я действительно хочу урезать свои данные.Что я могу сделать?

Спасибо

1 Ответ

0 голосов
/ 01 июня 2018

Хорошо, я не нашел конкретного ответа, поэтому вместо этого вот что я сделал.

Так как проблема была notifyItemRangeRemoved запущена, когда представление ограничено, и представление было связано, потому что пользовательвсе еще прокручивая, я удалил процесс обрезки из функций prepend / append.

Вместо этого я сделал процесс обрезки отдельной функцией (clipExtraDataIfNecessary).

Это ТОЛЬКО get вызывается в onScrollStateChanged(RecyclerView recyclerView, int newState) и ТОЛЬКО когда newState == SCROLL_STATE_IDLE, т.е. у пользователя остановлена ​​ прокрутка:

Методы отсечения данных теперь выглядят так:

/**
 * make sure we never surpass the MAX_DATASOURCE_CNT limit
 * Clips the data ArrayList from the ending (right) side
 */
public void clipExtraEndData() {
    int itemCountAfterPrepend = this.data.size();
    // if we went above our max data source count limit
    if (itemCountAfterPrepend > MAX_DATASOURCE_CNT) {
        int extraItemCnt = itemCountAfterPrepend - MAX_DATASOURCE_CNT;

        synchronized (dataMutationLock) {
            // remove every extra item from the end of the array
            removeRange(MAX_DATASOURCE_CNT, itemCountAfterPrepend);

            // and notify our adapter about the removal
            notifyItemRangeRemoved(MAX_DATASOURCE_CNT, extraItemCnt);
        }
    }
}


/**
 * make sure we never surpass the MAX_DATASOURCE_CNT limit
 * Clips the data ArrayList from the beginning (left) side
 */
public void clipExtraStartData() {
    int itemCountAfterAppend = this.data.size();
    // if we went above our max data-source count limit
    if (itemCountAfterAppend > MAX_DATASOURCE_CNT) {
        int extraItemCnt = itemCountAfterAppend - MAX_DATASOURCE_CNT;

        synchronized (dataMutationLock) {
            // remove every extra item from the beginning of the array
            removeRange(0, extraItemCnt);

            // and notify our adapter about the removal
            notifyItemRangeRemoved(0, extraItemCnt);
        }
    }
}

/**
 * Removes all the extra data that we have accumulated by prepending/appending
 * as the user was scrolling
 *
 * CAUTION: MAKE SURE YOU RUN THIS at a time where the user is NOT scrolling,
 * otherwise we run the risk of bindViewRow being called with preLayout position
 * values (a.k.a 0)
 * @param curVisiblePosition
 */
public void clipExtraDataIfNecessary(int curVisiblePosition) {
    int initialItemCnt = size();
    if (initialItemCnt > MAX_DATASOURCE_CNT) {
        if (curVisiblePosition < initialItemCnt - curVisiblePosition) {
            // we have extra children on the end of our data
            clipExtraEndData();
        } else {
            // we have extra children on the beginning of our data
            clipExtraStartData();
        }
    }
}
...