RecyclerView 通知xxx
RecyclerView notifyxxx
最近从 notifyDataSetChanged
切换到 notifyItemInserted/Changed/Removed
以保留动画。
我陷入了这种情况。我的适配器列表最初是:
A
B
C
D
然后我合并 A、B 和 C,在最后位置插入一个新的 E 项目:
A
E
我想我可以通知索引 1 (B) 已删除,索引 2 (C) 已删除,索引 3 (D) 已删除,然后新索引 1 (E) 已插入,但异常来自我不知道哪里说:
Inconsistency detected. Invalid view holder adapter
positionViewHolder...
所以我认为可能是索引 1 通知两次引起的问题,所以我将其更改为通知索引 1 (B) 已更改为 E,索引 2 (C) 已删除,索引 3 (D)已删除,但抛出相同的异常,让我别无选择。
在这种情况下,正确的做法应该是什么?
不要让问题没有答案,以防其他人遇到同样的问题
随着支持库 24.2 Diffutils 的发布,它有助于 class 计算两组项目之间的差异。
示例代码可能看起来像这样(创建两个列表并按下按钮交换适配器中的项目)。 DiffUtil.DiffResult 将处理所有 notify
个电话。
final List<RecyclerObject> list = new ArrayList<>();
list.add(new RecyclerObject("A"));
list.add(new RecyclerObject("B"));
list.add(new RecyclerObject("C"));
list.add(new RecyclerObject("D"));
final TestAdapter adapter = new TestAdapter(list);
recycler.setAdapter(adapter);
final List<RecyclerObject> newList = new ArrayList<>();
newList.add(new RecyclerObject("A"));
newList.add(new RecyclerObject("E"));
final View button = findViewById(R.id.mainButton);
button.setOnClickListener(v -> {
adapter.setList(newList);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallback(list, newList));
diffResult.dispatchUpdatesTo(adapter);
});
Diffcallback 是自己创建的 class,实现可能看起来像这样。 (为了更好的可读性删除了不必要的代码)
public class DiffCallback extends DiffUtil.Callback {
DiffCallback(final List<RecyclerObject> list, final List<RecyclerObject> newList) {
this.list = list;
this.newList = newList;
}
@Override
public int getOldListSize() {
return list.size();
}
@Override
public int getNewListSize() {
return newList.size();
}
@Override
public boolean areContentsTheSame(final int oldItemPosition, final int newItemPosition) {
return list.get(oldItemPosition).title.equals(newList.get(newItemPosition).title);
}
}
还有一种不太花哨的方法:如果我们可以保证支持适配器的项目是 "stable" 并且相同的项目将始终具有相同的标识符,recycler.adapter 允许 setHasStableIds
选项。这样一来,即使仅使用 notifyDatasetChanged
(通常会杀死动画)也能正确处理它们。需要覆盖函数 getItemId()
最近从 notifyDataSetChanged
切换到 notifyItemInserted/Changed/Removed
以保留动画。
我陷入了这种情况。我的适配器列表最初是:
A
B
C
D
然后我合并 A、B 和 C,在最后位置插入一个新的 E 项目:
A
E
我想我可以通知索引 1 (B) 已删除,索引 2 (C) 已删除,索引 3 (D) 已删除,然后新索引 1 (E) 已插入,但异常来自我不知道哪里说:
Inconsistency detected. Invalid view holder adapter positionViewHolder...
所以我认为可能是索引 1 通知两次引起的问题,所以我将其更改为通知索引 1 (B) 已更改为 E,索引 2 (C) 已删除,索引 3 (D)已删除,但抛出相同的异常,让我别无选择。
在这种情况下,正确的做法应该是什么?
不要让问题没有答案,以防其他人遇到同样的问题
随着支持库 24.2 Diffutils 的发布,它有助于 class 计算两组项目之间的差异。
示例代码可能看起来像这样(创建两个列表并按下按钮交换适配器中的项目)。 DiffUtil.DiffResult 将处理所有 notify
个电话。
final List<RecyclerObject> list = new ArrayList<>();
list.add(new RecyclerObject("A"));
list.add(new RecyclerObject("B"));
list.add(new RecyclerObject("C"));
list.add(new RecyclerObject("D"));
final TestAdapter adapter = new TestAdapter(list);
recycler.setAdapter(adapter);
final List<RecyclerObject> newList = new ArrayList<>();
newList.add(new RecyclerObject("A"));
newList.add(new RecyclerObject("E"));
final View button = findViewById(R.id.mainButton);
button.setOnClickListener(v -> {
adapter.setList(newList);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallback(list, newList));
diffResult.dispatchUpdatesTo(adapter);
});
Diffcallback 是自己创建的 class,实现可能看起来像这样。 (为了更好的可读性删除了不必要的代码)
public class DiffCallback extends DiffUtil.Callback {
DiffCallback(final List<RecyclerObject> list, final List<RecyclerObject> newList) {
this.list = list;
this.newList = newList;
}
@Override
public int getOldListSize() {
return list.size();
}
@Override
public int getNewListSize() {
return newList.size();
}
@Override
public boolean areContentsTheSame(final int oldItemPosition, final int newItemPosition) {
return list.get(oldItemPosition).title.equals(newList.get(newItemPosition).title);
}
}
还有一种不太花哨的方法:如果我们可以保证支持适配器的项目是 "stable" 并且相同的项目将始终具有相同的标识符,recycler.adapter 允许 setHasStableIds
选项。这样一来,即使仅使用 notifyDatasetChanged
(通常会杀死动画)也能正确处理它们。需要覆盖函数 getItemId()