Home | History | Annotate | Download | only in widget
      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&lt;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&lt;List&lt;User>> usersByLastName();
     40  * }
     41  *
     42  * class MyViewModel extends ViewModel {
     43  *     public final LiveData&lt;List&lt;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&lt;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&lt;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&lt;User> DIFF_CALLBACK =
     70  *             new DiffUtil.ItemCallback&lt;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  * @param  A 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