【发布时间】:2016-11-09 13:11:26
【问题描述】:
这是一个关于 RecyclerView 内部行为的问题,适合了解其机制或愿意深入研究源代码的人。我想要一个通过引用源来支持的答案。
原始问题
(向下滚动到“换句话说”以获得更集中的问题)
我需要了解notify* 操作(例如notifyItemInserted())是如何排队的。假设我有一个由这个列表备份的适配器:
ArrayList<String> list = Arrays.asList("one", "three", "four");
我想添加缺少的值 zero 和 two。
示例 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);
这很简单明了,没什么好说的。
示例 2
但是如果两个动作彼此非常接近,并且中间没有布局传递怎么办?
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,因此第二个选项似乎更合理。
示例 3
list.add(0, “zero”);
adapter.notifyItemInserted(0);
list.add(2, “two”);
adapter.notifyItemInserted(...)
现在呢? 1 或 2 ?列表在之后立即更新,但我确信两者之间没有布局传递。
问题
您遇到了主要问题,我想知道在这些情况下我应该如何表现。真实情况是我有多个异步任务以 insert() 方法结束。我可以将他们的操作排入队列,但是:
- 如果已经有内部队列,我不想这样做,而且肯定有
- 我不知道如果两个动作之间没有布局传递会发生什么,请参见示例 3。
换句话说
要更新回收站,必须执行 4 个操作:
- 我实际上改变了数据模型(例如,在支持数组中插入一些东西)
- 我打电话给
adapter.notify*() - 回收商接到电话
- 回收器执行操作(例如,在适配器上调用
getItem*()和onBind())并列出更改。
在没有并发的情况下很容易理解,它们是按顺序发生的:
1. => 2. => 3. => 4. => (new update) 1. => 2. => 3. => 4. ...
让我们看看步骤之间会发生什么。
- 在 1. 和 2. 之间:我认为开发人员有责任在更改数据后立即调用 notify()。没关系。
- 在 2. 和 3. 之间:这会立即发生,这里没有问题。
- 在 3. 和 4. 之间:这不会立即发生!据我所知。所以很有可能在步骤 3 和 4 之间有一个新的更新(步骤 1 和 2)之前的更新。
我想了解在这种情况下会发生什么。 我们应该如何表现? 我是否应该确保在插入新内容之前确实执行了上一次更新的第 4 步?如果有怎么办?
【问题讨论】:
-
例如2:可以使用notifyitemrange方法。示例 3:使用 notifyiteminserted(2)
-
@Divyesh 我的测试显示了一个不同的故事,所以我想要一个参考代码支持的答案。此外,我使用小索引(0 和 1)来说明问题,但请把它们视为随机的(例如 0 和 25)。此外,如果您查看源代码,您会发现
notifyItemInserted(position)始终被视为notifyItemRangeInserted(position, 1)。您使用哪一个在这里没有什么区别。 -
对于多个操作,我认为你应该先全部插入,然后使用 notifydatasetchnged
标签: android android-recyclerview