1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.recyclerview.widget; 18 19 import androidx.annotation.NonNull; 20 import androidx.annotation.Nullable; 21 22 import java.util.List; 23 24 /** 25 * {@link RecyclerView.Adapter RecyclerView.Adapter} base class for presenting List data in a 26 * {@link RecyclerView}, including computing diffs between Lists on a background thread. 27 * <p> 28 * This class is a convenience wrapper around {@link AsyncListDiffer} that implements Adapter common 29 * default behavior for item access and counting. 30 * <p> 31 * While using a LiveData<List> is an easy way to provide data to the adapter, it isn't required 32 * - you can use {@link #submitList(List)} when new lists are available. 33 * <p> 34 * A complete usage pattern with Room would look like this: 35 * <pre> 36 * {@literal @}Dao 37 * interface UserDao { 38 * {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC") 39 * public abstract LiveData<List<User>> usersByLastName(); 40 * } 41 * 42 * class MyViewModel extends ViewModel { 43 * public final LiveData<List<User>> usersList; 44 * public MyViewModel(UserDao userDao) { 45 * usersList = userDao.usersByLastName(); 46 * } 47 * } 48 * 49 * class MyActivity extends AppCompatActivity { 50 * {@literal @}Override 51 * public void onCreate(Bundle savedState) { 52 * super.onCreate(savedState); 53 * MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class); 54 * RecyclerView recyclerView = findViewById(R.id.user_list); 55 * UserAdapter<User> adapter = new UserAdapter(); 56 * viewModel.usersList.observe(this, list -> adapter.submitList(list)); 57 * recyclerView.setAdapter(adapter); 58 * } 59 * } 60 * 61 * class UserAdapter extends ListAdapter<User, UserViewHolder> { 62 * public UserAdapter() { 63 * super(User.DIFF_CALLBACK); 64 * } 65 * {@literal @}Override 66 * public void onBindViewHolder(UserViewHolder holder, int position) { 67 * holder.bindTo(getItem(position)); 68 * } 69 * public static final DiffUtil.ItemCallback<User> DIFF_CALLBACK = 70 * new DiffUtil.ItemCallback<User>() { 71 * {@literal @}Override 72 * public boolean areItemsTheSame( 73 * {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) { 74 * // User properties may have changed if reloaded from the DB, but ID is fixed 75 * return oldUser.getId() == newUser.getId(); 76 * } 77 * {@literal @}Override 78 * public boolean areContentsTheSame( 79 * {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) { 80 * // NOTE: if you use equals, your object must properly override Object#equals() 81 * // Incorrectly returning false here will result in too many animations. 82 * return oldUser.equals(newUser); 83 * } 84 * } 85 * }</pre> 86 * 87 * Advanced users that wish for more control over adapter behavior, or to provide a specific base 88 * class should refer to {@link AsyncListDiffer}, which provides custom mapping from diff events 89 * to adapter positions. 90 * 91 * @param <T> Type of the Lists this Adapter will receive. 92 * @paramA class that extends ViewHolder that will be used by the adapter. 93 */ 94 public abstract class ListAdapter<T, VH extends RecyclerView.ViewHolder> 95 extends RecyclerView.Adapter<VH> { 96 private final AsyncListDiffer<T> mHelper; 97 98 @SuppressWarnings("unused") 99 protected ListAdapter(@NonNull DiffUtil.ItemCallback<T> diffCallback) { 100 mHelper = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), 101 new AsyncDifferConfig.Builder<>(diffCallback).build()); 102 } 103 104 @SuppressWarnings("unused") 105 protected ListAdapter(@NonNull AsyncDifferConfig<T> config) { 106 mHelper = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), config); 107 } 108 109 /** 110 * Submits a new list to be diffed, and displayed. 111 * <p> 112 * If a list is already being displayed, a diff will be computed on a background thread, which 113 * will dispatch Adapter.notifyItem events on the main thread. 114 * 115 * @param list The new list to be displayed. 116 */ 117 @SuppressWarnings("WeakerAccess") 118 public void submitList(@Nullable List<T> list) { 119 mHelper.submitList(list); 120 } 121 122 @SuppressWarnings("unused") 123 protected T getItem(int position) { 124 return mHelper.getCurrentList().get(position); 125 } 126 127 @Override 128 public int getItemCount() { 129 return mHelper.getCurrentList().size(); 130 } 131 } 132