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