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