从RecyclerView适配器中删除数据子项而不影响当前可见的视图

时间:2018-06-01 16:57:12

标签: android android-recyclerview recyclerview-layout

我正在使用Recycler视图构建无限水平滚动列表。 屏幕上始终可以看到1-2个孩子(因为他们的宽度超过了屏幕视口,因此我们永远不会有超过2个孩子可见)。

初始状态:

initial state

当用户滚动时(他们可以向前和向后滚动 - 但是为了摇动这个例子,让我们假设他们正在滚动后退),我正在获取更多数据,而我m将它们添加到我的适配器数据中。

我正在调用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)使用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 :(得分:0)

好的,我没有找到具体的答案,所以反而是我的所作所为。

由于在绑定视图时问题是notifyItemRangeRemoved正在运行,并且由于用户仍在滚动而绑定了视图,因此我从prepend / append函数中删除了剪切过程。

相反,我将剪辑过程设为独立函数(clipExtraDataIfNecessary)。

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(); } } } 时调用,即用户已停止滚动:

数据剪辑方法现在看起来像这样:

Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_ALT);
robot.keyPress(KeyEvent.VK_TAB);
robot.delay(100);
robot.keyRelease(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_ALT);