为啥 DefaultItemAnimator 强制更改的 ViewHolders 重新创建?
Posted
技术标签:
【中文标题】为啥 DefaultItemAnimator 强制更改的 ViewHolders 重新创建?【英文标题】:Why is DefaultItemAnimator forcing changed ViewHolders to recreate?为什么 DefaultItemAnimator 强制更改的 ViewHolders 重新创建? 【发布时间】:2021-05-29 13:28:42 【问题描述】:嘿,所以基本上我最近遇到了RecyclerView
的问题(这里描述了我遇到的问题:RecyclerView recreating ViewHolder instead of rebinding)。我发现,RecyclerView
中的 ItemAnimator
决定了更改后的 ViewHolder
是否只需重新绑定或创建新的 ViewHolder 并进行淡入淡出。
这篇文章解释了一些事情: https://medium.com/android-news/anatomy-of-recyclerview-part-1-a-search-for-a-viewholder-continued-d81c631a2b91
我假设这是 DefaultItemAnimator 的一部分,它决定应该发生什么:
/**
* @inheritDoc
* <p>
* If the payload list is not empty, DefaultItemAnimator returns <code>true</code>.
* When this is the case:
* <ul>
* <li>If you override @link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int), both
* ViewHolder arguments will be the same instance.
* </li>
* <li>
* If you are not overriding @link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int),
* then DefaultItemAnimator will call @link #animateMove(RecyclerView.ViewHolder, int, int, int, int) and
* run a move animation instead.
* </li>
* </ul>
*/
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull List<Object> payloads)
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
现在我的问题的解决方案是使用一些任意有效负载调用onItemRangeChanged()
,它总是会重用ViewHolder
。
我的问题:
现在我想知道为什么以及何时重新创建整个ViewHolder
并淡入淡出它比仅仅更新它的特定部分更好?在上面提到的交叉引用问题中,我只是更改了 ViewHolder 的一小部分的可见性,但整个事情都被重新创建了,我认为这在性能方面会更差吗?
【问题讨论】:
【参考方案1】:记住RecyclerView
可以有多个项目视图类型。当notifyItemChanged
导致视图类型发生变化时,无论有效负载如何,视图持有者都没有资格重复使用。
通过替换 viewholders 动画师在这种情况下保持统一的行为。
此外,通过更新 ViewHolder,它们将不会使用适配器 onViewAttachedToWindow(holder)
,这是人们在布置新项目时可能会期望的,也不会使用 onViewRecycled(holder)
和 onViewDetachedFromWindow(holder)
,它们会为正在删除的项目调用。
附带说明,如果您在后续范围更新(无负载)期间遇到 onCreateViewHolder
调用,您可能应该增加 RecyclerView.RecycledViewPool
的大小。
【讨论】:
嘿,非常感谢您的回答。好的,如果 RecyclerView 需要这样做以保持一致性,我很好,但有两个问题:如果 ViewHolder 被完全替换,则会有轻微的闪烁(请参阅引用问题中的视频)以及我应该如何动画更改视图内部的状态? ViewHolder 完全重新创建,所有旧的 View 状态都丢失了? @MaxGierlachowski 如果您正在为更改设置动画,请提供更改有效负载并覆盖onBindViewHolder(holder, position, payloads)
以使用它。 Recyclerview 假设没有有效负载的更改意味着项目被另一个项目完全替换,因此它只是交换视图而不是尝试更改它。以上是关于为啥 DefaultItemAnimator 强制更改的 ViewHolders 重新创建?的主要内容,如果未能解决你的问题,请参考以下文章