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