Home | History | Annotate | Download | only in widget
      1 
      2 /*
      3  * Copyright (C) 2016 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.example.android.supportv7.widget;
     19 
     20 import android.view.LayoutInflater;
     21 import android.view.View;
     22 import android.view.ViewGroup;
     23 import android.widget.TextView;
     24 
     25 import androidx.core.util.Pair;
     26 import androidx.recyclerview.widget.DividerItemDecoration;
     27 import androidx.recyclerview.widget.LinearLayoutManager;
     28 import androidx.recyclerview.widget.RecyclerView;
     29 
     30 import com.example.android.supportv7.Cheeses;
     31 import com.example.android.supportv7.R;
     32 
     33 import java.util.ArrayList;
     34 import java.util.List;
     35 
     36 /**
     37  * A sample Stable Id RecyclerView activity.
     38  *
     39  * Stable Ids guarantee that items that remain onscreen due to a data set change are rebound to the
     40  * same views. This sample visually identifies views (independent from their data) to demonstrate
     41  * how RecyclerView does this rebinding. In addition, you can observe how RecyclerView recycles
     42  * items in response to a scroll or fling.
     43  *
     44  * Tapping an item will send it's data to the top of the list. RecyclerView will detect that the
     45  * data with that stable ID has moved position, and move the View accordingly, even though the only
     46  * signal sent to the RecyclerView was notifyDataSetChanged().
     47  *
     48  * Compared to DiffUtil or SortedList, stable Ids are often easier to use, but are less efficient,
     49  * and can only look at attached views to try and form reasonable animations for an update. Note
     50  * that notifyDataSetChanged() will still always cause every visible item to be rebound, since
     51  * RecyclerView isn't told what *inside the item* may have changed.
     52  *
     53  * It is suggested instead to use DiffUtil or SortedList to dispatch minimal updates from your
     54  * data set to the RecyclerView. SortedList allows you to express operations like moving or removing
     55  * an item very efficiently, without RecyclerView needing to find and compare the state of each
     56  * child before and after an operation. DiffUtil can compute minimal alterations (such as inserts
     57  * and moves) from lists that you pass it - useful if your data source or server doesn't provide
     58  * delta updates. Both DiffUtil and SortedList allow you to avoid rebinding each item when a small
     59  * change occurs.
     60  */
     61 public class StableIdActivity extends BaseLayoutManagerActivity<LinearLayoutManager> {
     62     @Override
     63     protected LinearLayoutManager createLayoutManager() {
     64         return new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
     65     }
     66 
     67     @Override
     68     protected RecyclerView.Adapter createAdapter() {
     69         return new StableIdAdapter(Cheeses.sCheeseStrings);
     70     }
     71 
     72     @Override
     73     protected void onRecyclerViewInit(RecyclerView recyclerView) {
     74         recyclerView.addItemDecoration(
     75                 new DividerItemDecoration(this, mLayoutManager.getOrientation()));
     76     }
     77 
     78     static class StableIdAdapter extends RecyclerView.Adapter<StableIdAdapter.ViewHolder> {
     79         List<Pair<Integer, String>> mData = new ArrayList<>();
     80 
     81         public static class ViewHolder extends RecyclerView.ViewHolder {
     82             static int sHolderNumber = 0;
     83 
     84             private final TextView mHolderNumberView;
     85             private final TextView mDataView;
     86 
     87             public ViewHolder(View itemView) {
     88                 super(itemView);
     89                 mHolderNumberView = (TextView) itemView.findViewById(R.id.holder_number_text);
     90                 mDataView = (TextView) itemView.findViewById(R.id.data_text);
     91 
     92                 // Just for demonstration, we visually uniquely identify which ViewHolder is which,
     93                 // so rebinding / moving due to stable IDs can be observed:
     94                 mHolderNumberView.setText("View Nr: " + sHolderNumber++);
     95             }
     96         }
     97 
     98         StableIdAdapter(String[] strings) {
     99             // comment out this line to dispatch updates without using stable IDs -
    100             // this prevents RecyclerView from knowing what changed, so animations don't run
    101             setHasStableIds(true);
    102 
    103 
    104             for (int i = 0; i < 20; i++) {
    105                 mData.add(new Pair<>(500 + i, strings[i]));
    106             }
    107         }
    108 
    109         @Override
    110         public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    111             LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    112             final ViewHolder viewHolder = new ViewHolder(
    113                     inflater.inflate(R.layout.stable_id_item, parent, false));
    114 
    115             viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
    116                 @Override
    117                 public void onClick(View v) {
    118                     final int pos = viewHolder.getAdapterPosition();
    119                     if (pos != RecyclerView.NO_POSITION) {
    120                         // swap item to top, and notify data set changed
    121                         Pair<Integer, String> d = mData.remove(pos);
    122                         mData.add(0, d);
    123 
    124                         notifyDataSetChanged();
    125                     }
    126                 }
    127             });
    128             return viewHolder;
    129         }
    130 
    131         @Override
    132         public void onBindViewHolder(ViewHolder holder, int position) {
    133             holder.mDataView.setText(mData.get(position).second);
    134         }
    135 
    136         @Override
    137         public long getItemId(int position) {
    138             return mData.get(position).first;
    139         }
    140 
    141         @Override
    142         public int getItemCount() {
    143             return mData.size();
    144         }
    145     }
    146 }
    147