Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

ListAdapter

abstract class ListAdapter<T : Any!, VH : RecyclerView.ViewHolder!> : RecyclerView.Adapter<VH>
kotlin.Any
   ↳ 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:

@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 = new ViewModelProvider(this).get(MyViewModel.class);
          RecyclerView recyclerView = findViewById(R.id.user_list);
          UserAdapter<User> adapter = new UserAdapter();
          viewModel.usersList.observe(this, list -> adapter.submitList(list));
          recyclerView.setAdapter(adapter);
      }
  }
 
  class UserAdapter extends ListAdapter<User, UserViewHolder> {
      public UserAdapter() {
          super(User.DIFF_CALLBACK);
      }
      @Override
      public void onBindViewHolder(UserViewHolder holder, int position) {
          holder.bindTo(getItem(position));
      }
      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);
          }
      }
  }
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.

Summary

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

Protected constructors

<init>

protected ListAdapter(@NonNull diffCallback: DiffUtil.ItemCallback<T>)

<init>

protected ListAdapter(@NonNull config: AsyncDifferConfig<T>)

Public methods

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>: The list currently being displayed.

getItemCount

open fun getItemCount(): Int

onCurrentListChanged

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

Called when the current List is updated.

If a null List is passed to submitList(List), or no List has been submitted, the current List is represented as an empty List.

Parameters
previousList MutableList<T>: List that was displayed previously.
currentList MutableList<T>: new List being displayed, will be empty if null was passed to submitList(List).

submitList

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

Submits a new list to be diffed, and displayed.

If a list is already being displayed, a diff will be computed on a background thread, which will dispatch Adapter.notifyItem events on the main thread.

Parameters
list MutableList<T>?: The new list to be displayed.

submitList

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

Set the new list to be displayed.

If a List is already being displayed, a diff will be computed on a background thread, which will dispatch Adapter.notifyItem events on the main thread.

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
list MutableList<T>?: The new list to be displayed.
commitCallback MutableList<T>?: Optional runnable that is executed when the List is committed, if it is committed.

Protected methods

getItem

protected open fun getItem(position: Int): T