我正在使用带有RecyclerView的ListAdapter
,在某些情况下,应用程序会变得非常慢 - 它会冻结10秒,并列出1000个项目。
情况是,首先我提交一个包含1000个项目的列表(首先按预期提交快速),然后我再次提交相同的列表,但排序方式不同。
通过调试很多,我终于发现,ListAdapter触发了notifyItemRangeChanged(0, 999)
,所以基本上是完整的列表。我读到其他地方(here和here),不应该这样做,因为它使RecyclerView变慢 - 这显然是正确的 - 但是,我无法影响ListAdapter的行为。
有人有解决方案吗?我不想再次删除ListAdapter,因为对于大多数其他用例,它是快速和方便的,自动执行各种动画等。
编辑 - 一些代码
关于代码没什么好看的,基本上是这样的:
RecyclerView mListView;
EnryListAdapter mEntryListAdapter; // <-- extends ListAdapter<Entry, VH>
...
mEntryListAdapter = new EntryListAdapter();
mListView.setAdapter(mEntryListAdapter);
mListView.setLayoutManager(new LinearLayoutManager(this));
mListView.setHasFixedSize(true);
((DefaultItemAnimator) mListView.getItemAnimator()).setSupportsChangeAnimations(false);
List<Entry> entryList = getEntryList(); // <-- list with 1000 entries
mEntryListAdapter.submitList(entryList); // <-- first submit is fast
entryList = getDifferentlySortedEntryList(); // <-- list with same entries, sorted differently
mEntryListAdapter.submitList(entryList); // <-- freezes app for over 10 seconds
最后,我发现这是我自己的错误。
在我执行DiffUtil.ItemCallback<Entry>#areContentsTheSame
时,我有这个检查:
oldItem.flags == newItem.flags
其中Entry.flags
首先是long
,但后来我把它改成了一个类的实例,而没有改变这个比较。由于实例不是相同的对象,因此这种比较始终导致false
。用它替换它
ObjectsCompat.equals(oldItem.flags, newItem.flags)
解决了这个问题。