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 18package com.example.android.supportv7.widget; 19 20import android.view.LayoutInflater; 21import android.view.View; 22import android.view.ViewGroup; 23import android.widget.TextView; 24 25import androidx.core.util.Pair; 26import androidx.recyclerview.widget.DividerItemDecoration; 27import androidx.recyclerview.widget.LinearLayoutManager; 28import androidx.recyclerview.widget.RecyclerView; 29 30import com.example.android.supportv7.Cheeses; 31import com.example.android.supportv7.R; 32 33import java.util.ArrayList; 34import 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 */ 61public 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