RecyclerView和Adapter数据更新

nat*_*rio 22 android recycler-adapter android-recyclerview

对于了解其机制或愿意深入了解源代码的人来说,这是一个关于RecyclerView内部行为的问题.我希望通过对源代码的引用来支持答案.

原始问题

(向下滚动到'换句话说'以获得更集中的问题)

我需要了解notify*行为(例如notifyItemInserted())是如何排队的.想象一下,我有一个由此列表备份的适配器:

ArrayList<String> list = Arrays.asList("one", "three", "four");
Run Code Online (Sandbox Code Playgroud)

我想补充的价值观zerotwo,即失踪.

例1

list.add(1, "two");
// notify the view
adapter.notifyItemInserted(1);


// Seconds later, I go on with zero
list.add(0, "zero");
// notify the view
adapter.notifyItemInserted(0);
Run Code Online (Sandbox Code Playgroud)

这非常简单明了,无话可说.

例2

但是,如果两个动作彼此非常接近,并且两者之间没有布局传递怎么办?

list.add(1, "two");
list.add(0, "zero”);
Run Code Online (Sandbox Code Playgroud)

我现在应该怎么做?

adapter.notifyItemInserted(1);
adapter.notifyItemInserted(0);
Run Code Online (Sandbox Code Playgroud)

或者可能

adapter.notifyItemInserted(2);
adapter.notifyItemInserted(0);
Run Code Online (Sandbox Code Playgroud)

?从适配器的角度来看,列表立即切换one, three, fourzero, one, two, three, four第二个选项似乎更合理.

例3

list.add(0, “zero”);
adapter.notifyItemInserted(0);
list.add(2, “two”);
adapter.notifyItemInserted(...)
Run Code Online (Sandbox Code Playgroud)

现在怎么样?1还是2?该列表之后立即更新,但我确信它们之间没有布局传递.

你遇到了主要问题,我想知道在这些情况下我应该怎么做.真实情况是我有多个异步任务以一个insert()方法结束.我可以排队他们的行动,但是:

  1. 如果已经有一个内部队列,我不想这样做,肯定是
  2. 我不知道如果两个动作在没有布局传递的情况下发生会发生什么,请参见示例3.

换一种说法

要更新回收器,必须执行4个操作:

  1. 我实际上改变了数据模型(例如在插入数组中插入一些东西)
  2. 我打电话 adapter.notify*()
  3. Recycler接到电话
  4. Recycler 执行操作(例如,调用getItem*()onBind()适配器)并列出更改.

当没有并发性时,很容易理解这一点,它们按顺序发生:

1. => 2. => 3. => 4. => (new update) 1. => 2. => 3. => 4. ...
Run Code Online (Sandbox Code Playgroud)

让我们看看步骤之间发生了什么.

  • 介于1.2之间:我认为开发人员有责任在更改数据后立即调用notify().没关系.
  • 介于2.3之间:这种情况立即发生,这里没有问题.
  • 之间34:这并不会立即发生!据我所知.因此,它完全可能的是,新的更新(步骤12)来步骤之间34 之前的更新.

我想了解在这种情况下会发生什么.我们该怎么做?我是否应确保在插入新内容之前确实已执行上一次更新的第4步?如果是这样的话?

yww*_*ynm 7

我之前想过类似的问题,我决定:

  1. 如果我想直接在列表末尾插入多个项目并想要为所有人制作动画,我应该:

    list.add("0");
    list.add("1");
    adapter.notifyItemRangeInserted(5, 2); // Suppose there were 5 items before so "0" has index of 5 and we want to insert 2 items.
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果我想直接在列表末尾插入多个项目,但想为每个插入的项目分别获取动画,我应该:

    list.add("0");
    list.add("1");
    adapter.notifyItemInserted(0);
    mRecyclerView.postDelayed(new Runnable() {
        @Override
        public void run() {
            // before this happens, Be careful to call other notify* methods. Never call notifyDataSetChanged.
            adapter.notifyItemInserted(1); 
        }
    }, mRecyclerView.getItemAnimator().getAddDuration());
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如果我想将多于1个项目插入到列表的不同位置,则类似于2.

希望这可以提供帮助.


Gen*_*mes 4

因此,让我们从 RecyclerView 与通知项的简单介绍开始。并且与保存的 ViewGroup 项目的其他列表(例如 ListView)一起使用非常简单。

\n\n

RecyclerView 具有已绘制的视图项目队列。并且不知道您的任何更新,无需调用notify(...)方法。当您添加新的 Item 并通知 RecyclerView 时,它会开始一一检查所有 View 的循环。

\n\n
RecyclerView contains and drawn next objects\nView view-0 (position 0), view-1 (position 1), View-2 (position 2)\n\n// Here is changes after updating\nYou added Item View view-new into (position 1) and Notify\nRecyclerView starts loop to check changes\nRecyclerView received unmodified view-0(position-0) and left them;\nRecyclerView found new item view-new(position 1)\nRecyclerView removing old item view-1(position 1)\nRecyclerView drawing new item view-new(position 1)\n\n// In RecyclerView queue in position-2 was item view-2, \n// But now we replacing previous item to this position\nRecyclerView found new item view-1 (new position-2)\nRecyclerView removing old item view-2(position 2)\nRecyclerView drawing new item view-1(position 2)\n\n// And again same behavior \nRecyclerView found new item view-3 (new position-3)\nRecyclerView drawing new item view-1(position 2)\n\n// And after all changes new RecyclerView would be\nRecyclerView contains and drawn next objects\nView view-0 (position 0), view-new (position 1) view-1 (position 2), View-2 (position 3)\n
Run Code Online (Sandbox Code Playgroud)\n\n

它只是工作通知函数的主要流程,但应该知道所有这些操作都发生在 UI 线程、主线程上,甚至您可以从异步任务调用更新。并回答您 2 个问题 - 您可以根据需要向 RecyclerView 调用 Notify,并确保您的操作位于正确的队列上。

\n\n

RecyclerView 在任何使用中都可以正确工作,更复杂的问题将涉及到您的 Adapter 工作。首先,您需要同步您的适配器操作,例如添加删除项目,并完全拒绝索引使用。例如,对于示例 3 来说会更好

\n\n
Item firstItem = new Item(0, \xe2\x80\x9czero\xe2\x80\x9d);\nlist.add(firstItem);\nadapter.notifyItemInserted(list.indexOf(firstItem));\n//Other action...\nItem nextItem = new Item(2, \xe2\x80\x9ctwo\xe2\x80\x9d);\nlist.add(nextItem);\nadapter.notifyItemInserted(list.indexOf(nextItem))\n//Other actions\n
Run Code Online (Sandbox Code Playgroud)\n\n

更新 |

\n\n

与RecyclerView.Adapter相关的文档,您可以在其中看到与 相同的功能notifyDataSetChanged()。如果这RecyclerView.Adapter会调用带有扩展的子项android.database.Observable,请参阅更多关于 Observable。对这个Observable Holder的访问是同步的,直到RecyclerView中的View Element释放使用。

\n\n

另请参阅支持库版本 25.0 第 9934 - 9988 行中的 RecyclerView;

\n