-
public class AsyncListDiffer<T>
Helper for computing the difference between two lists via DiffUtil on a background thread.
It can be connected to a RecyclerView.Adapter, and will signal the adapter of changes between sumbitted lists.
For simplicity, the ListAdapter wrapper class can often be used instead of the AsyncListDiffer directly. This AsyncListDiffer can be used for complex cases, where overriding an adapter base class to support asynchronous List diffing isn't convenient.
The AsyncListDiffer can consume the values from a LiveData of
List
and present the data simply for an adapter. It computes differences in list contents via DiffUtil on a background thread as newList
s are received.Use getCurrentList to access the current List, and present its data objects. Diff results will be dispatched to the ListUpdateCallback immediately before the current list is updated. If you're dispatching list updates directly to an Adapter, this means the Adapter can safely access list items and total size via getCurrentList.
A complete usage pattern with Room would look like this:
{@literal @}
Dao interface UserDao {{@literal @}
Query("SELECT * FROM user ORDER BY lastName ASC") public abstract LiveData<List<User>> usersByLastName(); } class MyViewModel extends ViewModel { public final LiveData<List<User>> usersList; public MyViewModel(UserDao userDao) { usersList = userDao.usersByLastName(); } } class MyActivity extends AppCompatActivity {{@literal @}
Override public void onCreate(Bundle savedState) { super.onCreate(savedState); MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class); RecyclerView recyclerView = findViewById(R.id.user_list); UserAdapter adapter = new UserAdapter(); viewModel.usersList.observe(this, list -> adapter.submitList(list)); recyclerView.setAdapter(adapter); } } class UserAdapter extends RecyclerView.Adapter<UserViewHolder> { private final AsyncListDiffer<User> mDiffer = new AsyncListDiffer(this, DIFF_CALLBACK);{@literal @}
Override public int getItemCount() { return mDiffer.getCurrentList().size(); } public void submitList(List<User> list) { mDiffer.submitList(list); }{@literal @}
Override public void onBindViewHolder(UserViewHolder holder, int position) { User user = mDiffer.getCurrentList().get(position); holder.bindTo(user); } public static final DiffUtil.ItemCallback<User> DIFF_CALLBACK = new DiffUtil.ItemCallback<User>() {{@literal @}
Override public boolean areItemsTheSame({@literal @}
NonNull User oldUser,{@literal @}
NonNull User newUser) { // User properties may have changed if reloaded from the DB, but ID is fixed return oldUser.getId() == newUser.getId(); }{@literal @}
Override public boolean areContentsTheSame({@literal @}
NonNull User oldUser,{@literal @}
NonNull User newUser) { // NOTE: if you use equals, your object must properly override Object#equals() // Incorrectly returning false here will result in too many animations. return oldUser.equals(newUser); } } }
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description public interface
AsyncListDiffer.ListListener
Listener for when the current List is updated.
-
Constructor Summary
Constructors Constructor Description AsyncListDiffer(RecyclerView.Adapter adapter, DiffUtil.ItemCallback<T> diffCallback)
Convenience for {@code AsyncListDiffer(new AdapterListUpdateCallback(adapter), * new AsyncDifferConfig.Builder().setDiffCallback(diffCallback).build());}
AsyncListDiffer(ListUpdateCallback listUpdateCallback, AsyncDifferConfig<T> config)
Create a AsyncListDiffer with the provided config, and ListUpdateCallback to dispatchupdates to.
-
Method Summary
Modifier and Type Method Description List<T>
getCurrentList()
Get the current List - any diffing to present this list has already been computed anddispatched via the ListUpdateCallback. void
submitList(@Nullable() List<T> newList)
Pass a new List to the AdapterHelper. void
submitList(@Nullable() List<T> newList, @Nullable() Runnable commitCallback)
Pass a new List to the AdapterHelper. void
addListListener(@NonNull() AsyncListDiffer.ListListener<T> listener)
Add a ListListener to receive updates when the current List changes. void
removeListListener(@NonNull() AsyncListDiffer.ListListener<T> listener)
Remove a previously registered ListListener. -
-
Constructor Detail
-
AsyncListDiffer
AsyncListDiffer(RecyclerView.Adapter adapter, DiffUtil.ItemCallback<T> diffCallback)
Convenience for{@code AsyncListDiffer(new AdapterListUpdateCallback(adapter), * new AsyncDifferConfig.Builder().setDiffCallback(diffCallback).build());}
- Parameters:
adapter
- Adapter to dispatch position updates to.diffCallback
- ItemCallback that compares items to dispatch appropriate animations when
-
AsyncListDiffer
AsyncListDiffer(ListUpdateCallback listUpdateCallback, AsyncDifferConfig<T> config)
Create a AsyncListDiffer with the provided config, and ListUpdateCallback to dispatchupdates to.- Parameters:
listUpdateCallback
- Callback to dispatch updates to.config
- Config to define background work Executor, and DiffUtil.ItemCallback forcomputing List diffs.
-
-
Method Detail
-
getCurrentList
@NonNull() List<T> getCurrentList()
Get the current List - any diffing to present this list has already been computed anddispatched via the ListUpdateCallback.
If a
null
List, or no List has been submitted, an empty list will be returned.The returned list may not be mutated - mutations to content must be done through submitList.
-
submitList
void submitList(@Nullable() List<T> newList)
Pass a new List to the AdapterHelper. Adapter updates will be computed on a backgroundthread.
If a List is already present, a diff will be computed asynchronously on a background thread.When the diff is computed, it will be applied (dispatched to the ListUpdateCallback),and the new List will be swapped in.
- Parameters:
newList
- The new List.
-
submitList
void submitList(@Nullable() List<T> newList, @Nullable() Runnable commitCallback)
Pass a new List to the AdapterHelper. Adapter updates will be computed on a backgroundthread.
If a List is already present, a diff will be computed asynchronously on a background thread.When the diff is computed, it will be applied (dispatched to the ListUpdateCallback),and the new List will be swapped in.
The commit callback can be used to know when the List is committed, but note that itmay not be executed. If List B is submitted immediately after List A, and iscommitted directly, the callback associated with List A will not be run.
- Parameters:
newList
- The new List.commitCallback
- Optional runnable that is executed when the List is committed, ifit is committed.
-
addListListener
void addListListener(@NonNull() AsyncListDiffer.ListListener<T> listener)
Add a ListListener to receive updates when the current List changes.
- Parameters:
listener
- Listener to receive updates.
-
removeListListener
void removeListListener(@NonNull() AsyncListDiffer.ListListener<T> listener)
Remove a previously registered ListListener.
- Parameters:
listener
- Previously registered listener.
-
-
-
-