Save the date! Android Dev Summit is coming to Sunnyvale, CA on Oct 23-24, 2019.

AsyncListDiffer

open class AsyncListDiffer<T : Any!>
kotlin.Any
   ↳ androidx.recyclerview.widget.AsyncListDiffer

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 new Lists 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:

@Dao
  interface UserDao {
      @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 {
      @Override
      public void onCreate(Bundle savedState) {
          super.onCreate(savedState);
          MyViewModel viewModel = ViewModelProviders.of(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);
      @Override
      public int getItemCount() {
          return mDiffer.getCurrentList().size();
      }
      public void submitList(List<User> list) {
          mDiffer.submitList(list);
      }
      @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>() {
          @Override
          public boolean areItemsTheSame(
                  @NonNull User oldUser, @NonNull User newUser) {
              // User properties may have changed if reloaded from the DB, but ID is fixed
              return oldUser.getId() == newUser.getId();
          }
          @Override
          public boolean areContentsTheSame(
                  @NonNull User oldUser, @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);
          }
      }
  }

Summary

Nested classes
abstract

Listener for when the current List is updated.

Public constructors
<init>(@NonNull adapter: RecyclerView.Adapter<RecyclerView.ViewHolder!>, @NonNull diffCallback: DiffUtil.ItemCallback<T>)

Convenience for AsyncListDiffer(new AdapterListUpdateCallback(adapter), new AsyncDifferConfig.Builder().setDiffCallback(diffCallback).build());

<init>(@NonNull listUpdateCallback: ListUpdateCallback, @NonNull config: AsyncDifferConfig<T>)

Create a AsyncListDiffer with the provided config, and ListUpdateCallback to dispatch updates to.

Public methods
open Unit

Add a ListListener to receive updates when the current List changes.

open MutableList<T>

Get the current List - any diffing to present this list has already been computed and dispatched via the ListUpdateCallback.

open Unit

Remove a previously registered ListListener.

open Unit
submitList(@Nullable newList: MutableList<T>?)

Pass a new List to the AdapterHelper.

open Unit
submitList(@Nullable newList: MutableList<T>?, @Nullable commitCallback: Runnable?)

Pass a new List to the AdapterHelper.

Public constructors

<init>

AsyncListDiffer(@NonNull adapter: RecyclerView.Adapter<RecyclerView.ViewHolder!>, @NonNull diffCallback: DiffUtil.ItemCallback<T>)

Convenience for AsyncListDiffer(new AdapterListUpdateCallback(adapter), new AsyncDifferConfig.Builder().setDiffCallback(diffCallback).build());

Parameters
adapter RecyclerView.Adapter<RecyclerView.ViewHolder!>: Adapter to dispatch position updates to.
diffCallback RecyclerView.Adapter<RecyclerView.ViewHolder!>: ItemCallback that compares items to dispatch appropriate animations when

<init>

AsyncListDiffer(@NonNull listUpdateCallback: ListUpdateCallback, @NonNull config: AsyncDifferConfig<T>)

Create a AsyncListDiffer with the provided config, and ListUpdateCallback to dispatch updates to.

Parameters
listUpdateCallback ListUpdateCallback: Callback to dispatch updates to.
config ListUpdateCallback: Config to define background work Executor, and DiffUtil.ItemCallback for computing List diffs.

Public methods

addListListener

open fun addListListener(@NonNull listener: AsyncListDiffer.ListListener<T>): Unit

Add a ListListener to receive updates when the current List changes.

Parameters
listener AsyncListDiffer.ListListener<T>: Listener to receive updates.

getCurrentList

@NonNull open fun getCurrentList(): MutableList<T>

Get the current List - any diffing to present this list has already been computed and dispatched 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(List).

Return
MutableList<T>: current List.

removeListListener

open fun removeListListener(@NonNull listener: AsyncListDiffer.ListListener<T>): Unit

Remove a previously registered ListListener.

Parameters
listener AsyncListDiffer.ListListener<T>: Previously registered listener.

submitList

open fun submitList(@Nullable newList: MutableList<T>?): Unit

Pass a new List to the AdapterHelper. Adapter updates will be computed on a background thread.

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 MutableList<T>?: The new List.

submitList

open fun submitList(@Nullable newList: MutableList<T>?, @Nullable commitCallback: Runnable?): Unit

Pass a new List to the AdapterHelper. Adapter updates will be computed on a background thread.

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 it may not be executed. If List B is submitted immediately after List A, and is committed directly, the callback associated with List A will not be run.

Parameters
newList MutableList<T>?: The new List.
commitCallback MutableList<T>?: Optional runnable that is executed when the List is committed, if it is committed.