Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

androidx.RecyclerView ListAdapter very slow

I am using the ListAdapter with RecyclerView and under certain circumstances the app becomes extremely slow -- it freezes for 10 seconds with a list of 1000 items.

The circumstances are, that at first I submit a list with 1000 items (at first submit its fast as expected) and then I submit the same list again, but sorted differently.

By debugging a lot, I finally found out, that the ListAdapter triggers a notifyItemRangeChanged(0, 999), so basically for the complete list. I read elsewhere (here and here), that one should not do this, because it makes the RecyclerView slow -- which apparently is true -- however, I cannot influence the behaviour of the ListAdapter.

Does anyone have a solution for that? I don't want to remove ListAdapter again, because for most other usecases it is fast and handy, doing various animations etc. automatically.

EDIT - some code

There is nothing fancy about the code, basically it's like that:

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
like image 842
Ridcully Avatar asked Oct 17 '22 05:10

Ridcully


1 Answers

In the end, I found out that it was my own mistake.

In my implementation of DiffUtil.ItemCallback<Entry>#areContentsTheSame I had this check:

oldItem.flags == newItem.flags

where Entry.flags was a long first, but later on I changed it to be an instance of a class, without changing this comparison. Since the instances aren't the same objects, this comparison then resulted in false all the time. Replacing it with

ObjectsCompat.equals(oldItem.flags, newItem.flags)

fixed the issue.

like image 58
Ridcully Avatar answered Oct 21 '22 05:10

Ridcully