mirror of https://github.com/NekoX-Dev/NekoX.git
191 lines
7.4 KiB
Java
191 lines
7.4 KiB
Java
/*
|
|
* Copyright 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package androidx.recyclerview.widget;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
|
|
import java.util.List;
|
|
|
|
/**
|
|
* {@link RecyclerView.Adapter RecyclerView.Adapter} base class for presenting List data in a
|
|
* {@link RecyclerView}, including computing diffs between Lists on a background thread.
|
|
* <p>
|
|
* This class is a convenience wrapper around {@link AsyncListDiffer} that implements Adapter common
|
|
* default behavior for item access and counting.
|
|
* <p>
|
|
* While using a LiveData<List> is an easy way to provide data to the adapter, it isn't required
|
|
* - you can use {@link #submitList(List)} when new lists are available.
|
|
* <p>
|
|
* A complete usage pattern with Room would look like this:
|
|
* <pre>
|
|
* {@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 = ViewModelProviders.of(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);
|
|
* }
|
|
* {@literal @}Override
|
|
* public void onBindViewHolder(UserViewHolder holder, int position) {
|
|
* holder.bindTo(getItem(position));
|
|
* }
|
|
* 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);
|
|
* }
|
|
* }
|
|
* }</pre>
|
|
*
|
|
* Advanced users that wish for more control over adapter behavior, or to provide a specific base
|
|
* class should refer to {@link AsyncListDiffer}, which provides custom mapping from diff events
|
|
* to adapter positions.
|
|
*
|
|
* @param <T> Type of the Lists this Adapter will receive.
|
|
* @param <VH> A class that extends ViewHolder that will be used by the adapter.
|
|
*/
|
|
public abstract class ListAdapter<T, VH extends RecyclerView.ViewHolder>
|
|
extends RecyclerView.Adapter<VH> {
|
|
final AsyncListDiffer<T> mDiffer;
|
|
private final AsyncListDiffer.ListListener<T> mListener =
|
|
new AsyncListDiffer.ListListener<T>() {
|
|
@Override
|
|
public void onCurrentListChanged(
|
|
@NonNull List<T> previousList, @NonNull List<T> currentList) {
|
|
ListAdapter.this.onCurrentListChanged(previousList, currentList);
|
|
}
|
|
};
|
|
|
|
@SuppressWarnings("unused")
|
|
protected ListAdapter(@NonNull DiffUtil.ItemCallback<T> diffCallback) {
|
|
mDiffer = new AsyncListDiffer<>(new AdapterListUpdateCallback(this),
|
|
new AsyncDifferConfig.Builder<>(diffCallback).build());
|
|
mDiffer.addListListener(mListener);
|
|
}
|
|
|
|
@SuppressWarnings("unused")
|
|
protected ListAdapter(@NonNull AsyncDifferConfig<T> config) {
|
|
mDiffer = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), config);
|
|
mDiffer.addListListener(mListener);
|
|
}
|
|
|
|
/**
|
|
* Submits a new list to be diffed, and displayed.
|
|
* <p>
|
|
* 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.
|
|
*
|
|
* @param list The new list to be displayed.
|
|
*/
|
|
public void submitList(@Nullable List<T> list) {
|
|
mDiffer.submitList(list);
|
|
}
|
|
|
|
/**
|
|
* Set the new list to be displayed.
|
|
* <p>
|
|
* 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.
|
|
* <p>
|
|
* 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.
|
|
*
|
|
* @param list The new list to be displayed.
|
|
* @param commitCallback Optional runnable that is executed when the List is committed, if
|
|
* it is committed.
|
|
*/
|
|
public void submitList(@Nullable List<T> list, @Nullable final Runnable commitCallback) {
|
|
mDiffer.submitList(list, commitCallback);
|
|
}
|
|
|
|
protected T getItem(int position) {
|
|
return mDiffer.getCurrentList().get(position);
|
|
}
|
|
|
|
@Override
|
|
public int getItemCount() {
|
|
return mDiffer.getCurrentList().size();
|
|
}
|
|
|
|
/**
|
|
* Get the current List - any diffing to present this list has already been computed and
|
|
* dispatched via the ListUpdateCallback.
|
|
* <p>
|
|
* If a <code>null</code> List, or no List has been submitted, an empty list will be returned.
|
|
* <p>
|
|
* The returned list may not be mutated - mutations to content must be done through
|
|
* {@link #submitList(List)}.
|
|
*
|
|
* @return The list currently being displayed.
|
|
*
|
|
* @see #onCurrentListChanged(List, List)
|
|
*/
|
|
@NonNull
|
|
public List<T> getCurrentList() {
|
|
return mDiffer.getCurrentList();
|
|
}
|
|
|
|
/**
|
|
* Called when the current List is updated.
|
|
* <p>
|
|
* If a <code>null</code> List is passed to {@link #submitList(List)}, or no List has been
|
|
* submitted, the current List is represented as an empty List.
|
|
*
|
|
* @param previousList List that was displayed previously.
|
|
* @param currentList new List being displayed, will be empty if {@code null} was passed to
|
|
* {@link #submitList(List)}.
|
|
*
|
|
* @see #getCurrentList()
|
|
*/
|
|
public void onCurrentListChanged(@NonNull List<T> previousList, @NonNull List<T> currentList) {
|
|
}
|
|
}
|