/* * 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. *

* This class is a convenience wrapper around {@link 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 {@link #submitList(List)} when new lists are available. *

* A complete usage pattern with Room would look like this: *

 * {@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);
 *         }
 *     }
 * }
* * 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 Type of the Lists this Adapter will receive. * @param A class that extends ViewHolder that will be used by the adapter. */ public abstract class ListAdapter extends RecyclerView.Adapter { private final AsyncListDiffer mHelper; @SuppressWarnings("unused") protected ListAdapter(@NonNull DiffUtil.ItemCallback diffCallback) { mHelper = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), new AsyncDifferConfig.Builder<>(diffCallback).build()); } @SuppressWarnings("unused") protected ListAdapter(@NonNull AsyncDifferConfig config) { mHelper = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), config); } /** * 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. * * @param list The new list to be displayed. */ @SuppressWarnings("WeakerAccess") public void submitList(@Nullable List list) { mHelper.submitList(list); } @SuppressWarnings("unused") protected T getItem(int position) { return mHelper.getCurrentList().get(position); } @Override public int getItemCount() { return mHelper.getCurrentList().size(); } }