对于了解其机制或愿意深入了解源代码的人来说,这是一个关于RecyclerView内部行为的问题。我希望通过对来源的引用来支持答案。
(向下滚动到'换句话说'以获得更集中的问题)
我需要了解notify*
行为(例如notifyItemInserted()
)如何排队。想象一下,我有一个由此列表备份的适配器:
ArrayList<String> list = Arrays.asList("one", "three", "four");
我想添加缺少的值zero
和two
。
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);
这非常简单明了,无需说明。
但是如果两个动作彼此非常接近,并且两者之间没有布局传递怎么办?
list.add(1, "two");
list.add(0, "zero”);
我现在该怎么办?
adapter.notifyItemInserted(1);
adapter.notifyItemInserted(0);
或者
adapter.notifyItemInserted(2);
adapter.notifyItemInserted(0);
?从适配器的角度来看,列表立即从one, three, four
切换到zero, one, two, three, four
,因此第二个选项似乎更合理。
list.add(0, “zero”);
adapter.notifyItemInserted(0);
list.add(2, “two”);
adapter.notifyItemInserted(...)
现在怎么样? 1
或2
?该列表在之后立即更新,但我确信它们之间没有布局传递。
你遇到了主要问题,我想知道在这些情况下我应该怎么做。真实情况是我有多个异步任务以insert()
方法结束。我可以排队他们的行动,但是:
要更新回收商,必须执行4项操作:
adapter.notify*()
getItem*()
和onBind()
)并列出更改。当没有并发性时,很容易理解这一点,并且它们按顺序发生:
1. => 2. => 3. => 4. => (new update) 1. => 2. => 3. => 4. ...
让我们看看步骤之间会发生什么。
我想了解在这种情况下会发生什么。 我们该怎么做? 我应该确保在插入新内容之前确实已执行上一次更新的 4 步骤吗?如果是这样的话?
答案 0 :(得分: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.
如果我想直接在列表末尾插入1个以上的项目,但是 想要为每个插入的项目分离动画,我应该:
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());
希望这可以提供帮助。
答案 1 :(得分:4)
因此,让我们从简介介绍到RecyclerView与通知项目一起使用。并且使用其他已保存的ViewGroup项列表(前面的ListView)
非常简单 RecyclerView具有已绘制的查看项目队列。并且不会调用notify(...)
方法,也不知道您的任何更新。当您添加新项目并通知RecyclerView时,它会开始循环以逐个检查所有视图。
RecyclerView contains and drawn next objects
View view-0 (position 0), view-1 (position 1), View-2 (position 2)
// Here is changes after updating
You added Item View view-new into (position 1) and Notify
RecyclerView starts loop to check changes
RecyclerView received unmodified view-0(position-0) and left them;
RecyclerView found new item view-new(position 1)
RecyclerView removing old item view-1(position 1)
RecyclerView drawing new item view-new(position 1)
// In RecyclerView queue in position-2 was item view-2,
// But now we replacing previous item to this position
RecyclerView found new item view-1 (new position-2)
RecyclerView removing old item view-2(position 2)
RecyclerView drawing new item view-1(position 2)
// And again same behavior
RecyclerView found new item view-3 (new position-3)
RecyclerView drawing new item view-1(position 2)
// And after all changes new RecyclerView would be
RecyclerView contains and drawn next objects
View view-0 (position 0), view-new (position 1) view-1 (position 2), View-2 (position 3)
它只是工作通知函数的主要流程,但应该知道所有这些操作都发生在UI线程,主线程上,甚至可以从异步任务调用更新。并回答你2问题 - 你可以根据需要调用通知到RecyclerView,并确保你的行动将在正确的队列上。
RecyclerView在任何用途中都能正常工作,更复杂的问题将适用于您的适配器工作。首先,您需要同步适配器操作,例如添加删除项,以及完全拒绝索引使用。例如,对于示例3来说,它会更好
Item firstItem = new Item(0, “zero”);
list.add(firstItem);
adapter.notifyItemInserted(list.indexOf(firstItem));
//Other action...
Item nextItem = new Item(2, “two”);
list.add(nextItem);
adapter.notifyItemInserted(list.indexOf(nextItem))
//Other actions
更新|
与 RecyclerView.Adapter Doc相关,您可以在其中看到与notifyDataSetChanged()
相同的功能。如果此RecyclerView.Adapter
调用包含android.database.Observable
个扩展名的子项,请参阅更多About Observable。对此Observable Holder的访问是同步的,直到RecyclerView中的View Element释放使用。
另请参阅支持库版本25.0中的RecyclerView 9934行 - 9988;
答案 2 :(得分:2)
如果在布局过程之间进行多次更新,那应该不是问题。 RecyclerView
旨在处理(并优化)此案例:
RecyclerView在。之间引入了额外的抽象层次 RecyclerView.Adapter和RecyclerView.LayoutManager能够 在布局计算期间批量检测数据集更改。 [...] RecyclerView中有两种与位置相关的方法:
- 布局位置:项目在最新布局计算中的位置。这是LayoutManager的位置 透视图。
- 适配器位置:项目在适配器中的位置。这是从Adapter的角度来看的位置。
除调度之间的时间外,这两个位置相同 adapter.notify *事件和计算更新的布局。
在您的情况下,步骤是:
您更新数据层
您致电adapter.notify*()
recyclerview记录更改(如果我正确理解代码,则在AdapterHelper.mPendingUpdates
中)。此更改将反映在ViewHolder.getAdapterPosition()中,但尚未显示在ViewHolder.getLayoutPosition()中。
1。, 2。, 3。序列可以发生任意次,只要 2。紧跟 1。(两者都发生在主线程上)。
(1. => 2. => 3.) ... (1. => 2. => 3.) ... 4.
答案 3 :(得分:-2)
Item firstItem = new Item(0, “zero”);
list.add(firstItem);
adapter.notifyItemInserted(list.indexOf(firstItem));
//Other action...
Item nextItem = new Item(2, “two”);
list.add(nextItem);
adapter.notifyItemInserted(list.indexOf(nextItem))