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