5

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
Ridcully
  • 23,362
  • 7
  • 71
  • 86
  • 1
    Please add some code, how you are using it. – Md. Tahmid Mozaffar Mar 15 '19 at 20:02
  • Try using ListAdapter's parent class, RecyclerView.Adapter, https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.Adapter.html A usage example is given here: https://developer.android.com/guide/topics/ui/layout/recyclerview – MD Naseem Ashraf Mar 15 '19 at 20:18
  • @MDNaseemAshraf I'm specifically using ListAdapter because of its benefits. As said, I do not want to remove it and go back to the regular Adapter, if possible. – Ridcully Mar 15 '19 at 21:26
  • 1
    For gross changes, like changing the sort order, I'm not surprised at poor performance, though this is worse than I would expect. For bulk changes, I would create a fresh `ListAdapter` wrapped around your changed list and switch the `RecyclerView` to it. Use `submitList()` for incremental changes. – CommonsWare Mar 15 '19 at 23:19
  • The very benefits of listadapter are causing performance issues as you've seen yourself. Using RecyclerViewAdapter is the way to go. Another option might be using the recently introduced Paging library with the Recyclerview, depending on your use case. Read here: https://developer.android.com/topic/libraries/architecture/paging Paging library is part of the Android Jetpack Architecture Components and is used with the latest introduced methods of using MVVM and LiveData. – MD Naseem Ashraf Mar 16 '19 at 03:45
  • 1
    Actually, I am using ViewModel and LiveData. The activity observes the LiveData of the list and submits it to the ListAdapter. Because of this, I cannot/do not, at the moment, distinguish between small and large changes of list. Based on the description of ListAdapter, I was under the impression that it would be smart enough to do that for me. – Ridcully Mar 16 '19 at 05:09

1 Answers1

3

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.

Ridcully
  • 23,362
  • 7
  • 71
  • 86