ListAdapter
abstract class ListAdapter<T : Any!, VH : RecyclerView.ViewHolder!> : RecyclerView.Adapter<VH>
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
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 |
Called when the current List is updated.
|
open Unit |
Submits a new list to be diffed, and displayed.
|
open Unit |
Set the new list to be displayed.
|
Inherited functions |
From class Adapter
Unit |
bindViewHolder(@NonNull holder: VH, position: Int)
This method internally calls onBindViewHolder(ViewHolder, int) to update the ViewHolder contents with the item at the given position and also sets up some private fields to be used by RecyclerView. Adapters that merge other adapters should use bindViewHolder(ViewHolder, int) when calling nested adapters so that RecyclerView can track which adapter bound the ViewHolder to return the correct position from ViewHolder#getBindingAdapterPosition() method. They should also override the findRelativeAdapterPositionIn(Adapter, ViewHolder, int) method.
|
VH |
createViewHolder(@NonNull parent: ViewGroup, viewType: Int)
This method calls onCreateViewHolder(ViewGroup, int) to create a new ViewHolder and initializes some private fields to be used by RecyclerView.
|
Int |
findRelativeAdapterPositionIn(@NonNull adapter: RecyclerView.Adapter<out RecyclerView.ViewHolder!>, @NonNull viewHolder: RecyclerView.ViewHolder, localPosition: Int)
Returns the position of the given ViewHolder in the given Adapter . If the given Adapter is not part of this Adapter , RecyclerView#NO_POSITION is returned.
|
Long |
getItemId(position: Int)
Return the stable ID for the item at position . If hasStableIds() would return false this method should return NO_ID . The default implementation of this method returns NO_ID .
|
Int |
getItemViewType(position: Int)
Return the view type of the item at position for the purposes of view recycling.
The default implementation of this method returns 0, making the assumption of a single view type for the adapter. Unlike ListView adapters, types need not be contiguous. Consider using id resources to uniquely identify item view types.
|
RecyclerView.Adapter.StateRestorationPolicy |
getStateRestorationPolicy()
Returns when this Adapter wants to restore the state.
|
Boolean |
hasObservers()
Returns true if one or more observers are attached to this adapter.
|
Boolean |
hasStableIds()
Returns true if this adapter publishes a unique long value that can act as a key for the item at a given position in the data set. If that item is relocated in the data set, the ID returned for that item should be the same.
|
Unit |
notifyDataSetChanged()
Notify any registered observers that the data set has changed.
There are two different classes of data change events, item changes and structural changes. Item changes are when a single item has its data updated but no positional changes have occurred. Structural changes are when items are inserted, removed or moved within the data set.
This event does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. LayoutManagers will be forced to fully rebind and relayout all visible views.
RecyclerView will attempt to synthesize visible structural change events for adapters that report that they have stable IDs when this method is used. This can help for the purposes of animation and visual object persistence but individual item views will still need to be rebound and relaid out.
If you are writing an adapter it will always be more efficient to use the more specific change events if you can. Rely on notifyDataSetChanged() as a last resort.
|
Unit |
notifyItemChanged(position: Int)
Notify any registered observers that the item at position has changed. Equivalent to calling notifyItemChanged(position, null); .
This is an item change event, not a structural change event. It indicates that any reflection of the data at position is out of date and should be updated. The item at position retains the same identity.
|
Unit |
notifyItemChanged(position: Int, @Nullable payload: Any?)
Notify any registered observers that the item at position has changed with an optional payload object.
This is an item change event, not a structural change event. It indicates that any reflection of the data at position is out of date and should be updated. The item at position retains the same identity.
Client can optionally pass a payload for partial change. These payloads will be merged and may be passed to adapter's onBindViewHolder(ViewHolder, int, List) if the item is already represented by a ViewHolder and it will be rebound to the same ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing payloads on that item and prevent future payload until onBindViewHolder(ViewHolder, int, List) is called. Adapter should not assume that the payload will always be passed to onBindViewHolder(), e.g. when the view is not attached, the payload will be simply dropped.
|
Unit |
notifyItemInserted(position: Int)
Notify any registered observers that the item reflected at position has been newly inserted. The item previously at position is now at position position + 1 .
This is a structural change event. Representations of other existing items in the data set are still considered up to date and will not be rebound, though their positions may be altered.
|
Unit |
notifyItemMoved(fromPosition: Int, toPosition: Int)
Notify any registered observers that the item reflected at fromPosition has been moved to toPosition .
This is a structural change event. Representations of other existing items in the data set are still considered up to date and will not be rebound, though their positions may be altered.
|
Unit |
notifyItemRangeChanged(positionStart: Int, itemCount: Int)
Notify any registered observers that the itemCount items starting at position positionStart have changed. Equivalent to calling notifyItemRangeChanged(position, itemCount, null); .
This is an item change event, not a structural change event. It indicates that any reflection of the data in the given position range is out of date and should be updated. The items in the given range retain the same identity.
|
Unit |
notifyItemRangeChanged(positionStart: Int, itemCount: Int, @Nullable payload: Any?)
Notify any registered observers that the itemCount items starting at position positionStart have changed. An optional payload can be passed to each changed item.
This is an item change event, not a structural change event. It indicates that any reflection of the data in the given position range is out of date and should be updated. The items in the given range retain the same identity.
Client can optionally pass a payload for partial change. These payloads will be merged and may be passed to adapter's onBindViewHolder(ViewHolder, int, List) if the item is already represented by a ViewHolder and it will be rebound to the same ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing payloads on that item and prevent future payload until onBindViewHolder(ViewHolder, int, List) is called. Adapter should not assume that the payload will always be passed to onBindViewHolder(), e.g. when the view is not attached, the payload will be simply dropped.
|
Unit |
notifyItemRangeInserted(positionStart: Int, itemCount: Int)
Notify any registered observers that the currently reflected itemCount items starting at positionStart have been newly inserted. The items previously located at positionStart and beyond can now be found starting at position positionStart + itemCount .
Thi | |