Android 12 Developer Preview is here! Try it out, and give us your feedback!


abstract class ListAdapter<T : Any!, VH : RecyclerView.ViewHolder!> : RecyclerView.Adapter<VH>
   ↳ androidx.recyclerview.widget.RecyclerView.Adapter<VH>
   ↳ androidx.recyclerview.widget.ListAdapter

RecyclerView.Adapter base class for presenting List data in a RecyclerView, including computing diffs between Lists on a background thread.

This class is a convenience wrapper around AsyncListDiffer that implements Adapter common default behavior for item access and counting.

While using a LiveData<List> is an easy way to provide data to the adapter, it isn't required - you can use submitList(List) when new lists are available.

A complete usage pattern with Room would look like this:

  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 {
      public void onCreate(Bundle savedState) {
          MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
          RecyclerView recyclerView = findViewById(;
          UserAdapter<User> adapter = new UserAdapter();
          viewModel.usersList.observe(this, list -> adapter.submitList(list));
  class UserAdapter extends ListAdapter<User, UserViewHolder> {
      public UserAdapter() {
      public void onBindViewHolder(UserViewHolder holder, int position) {
      public static final DiffUtil.ItemCallback<User> DIFF_CALLBACK =
              new DiffUtil.ItemCallback<User>() {
          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();
          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);
Advanced users that wish for more control over adapter behavior, or to provide a specific base class should refer to AsyncListDiffer, which provides custom mapping from diff events to adapter positions.


Protected constructors
<init>(@NonNull diffCallback: DiffUtil.ItemCallback<T>)

<init>(@NonNull config: AsyncDifferConfig<T>)

Public methods
open MutableList<T>

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

open Int

open Unit
onCurrentListChanged(@NonNull previousList: MutableList<T>, @NonNull currentList: MutableList<T>)

Called when the current List is updated.

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

Submits a new list to be diffed, and displayed.

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

Set the new list to be displayed.

Protected methods
open T
getItem(position: Int)

Inherited functions