ViewInfoStore.java revision c39d9c75590eca86a5e7e32a8824ba04a0d42e9b
1e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar/*
2e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar *
4e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * you may not use this file except in compliance with the License.
6e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * You may obtain a copy of the License at
7e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar *
8e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar *
10e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * See the License for the specific language governing permissions and
14e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar * limitations under the License.
15e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar */
16e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarpackage android.support.v7.widget;
17e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
18e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport android.support.annotation.NonNull;
19e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport android.support.annotation.Nullable;
20e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport android.support.annotation.VisibleForTesting;
21e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport android.support.v4.util.ArrayMap;
22e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport android.support.v4.util.LongSparseArray;
23e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport android.support.v4.util.Pools;
244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.view.View;
25e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
26e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.RecyclerView.ViewHolder;
27e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
28e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
29e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_PRE_AND_POST;
30e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_AND_DISAPPEAR;
31e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE_AND_POST;
32e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
33e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
34e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
35e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarimport static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_POST;
36e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar/**
37c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette * This class abstracts all tracking for Views to run animations.
38e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar */
39e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyarclass ViewInfoStore {
40e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
41e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    private static final boolean DEBUG = false;
42e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
43e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
44e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * View data records for pre-layout
45e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
46e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    @VisibleForTesting
47e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    final ArrayMap<ViewHolder, InfoRecord> mLayoutHolderMap = new ArrayMap<>();
48e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
49e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    @VisibleForTesting
50e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    final LongSparseArray<ViewHolder> mOldChangedHolders = new LongSparseArray<>();
51e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
52e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
53e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Clears the state and all existing tracking data
54e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
55e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void clear() {
56e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        mLayoutHolderMap.clear();
57e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        mOldChangedHolders.clear();
58e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
59e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
60e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
61e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Adds the item information to the prelayout tracking
62e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param holder The ViewHolder whose information is being saved
63e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param info The information to save
64e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
65e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void addToPreLayout(ViewHolder holder, ItemHolderInfo info) {
66e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        InfoRecord record = mLayoutHolderMap.get(holder);
67e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        if (record == null) {
68e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            record = InfoRecord.obtain();
69e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            mLayoutHolderMap.put(holder, record);
70e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
71e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        record.preInfo = info;
72e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        record.flags |= FLAG_PRE;
73e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
74e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
7513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    boolean isDisappearing(ViewHolder holder) {
7613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        final InfoRecord record = mLayoutHolderMap.get(holder);
7713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        return record != null && ((record.flags & FLAG_DISAPPEARED) != 0);
7813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    }
7913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
80e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
81e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Finds the ItemHolderInfo for the given ViewHolder in preLayout list and removes it.
8213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar     *
83e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param vh The ViewHolder whose information is being queried
84e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @return The ItemHolderInfo for the given ViewHolder or null if it does not exist
85e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
86e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    @Nullable
87e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    ItemHolderInfo popFromPreLayout(ViewHolder vh) {
8813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        return popFromLayoutStep(vh, FLAG_PRE);
8913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    }
9013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
9113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    /**
9213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar     * Finds the ItemHolderInfo for the given ViewHolder in postLayout list and removes it.
9313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar     *
9413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar     * @param vh The ViewHolder whose information is being queried
9513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar     * @return The ItemHolderInfo for the given ViewHolder or null if it does not exist
9613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar     */
9713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    @Nullable
9813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    ItemHolderInfo popFromPostLayout(ViewHolder vh) {
9913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        return popFromLayoutStep(vh, FLAG_POST);
10013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    }
10113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
10213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    private ItemHolderInfo popFromLayoutStep(ViewHolder vh, int flag) {
103e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        int index = mLayoutHolderMap.indexOfKey(vh);
104e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        if (index < 0) {
105e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            return null;
106e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
107e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        final InfoRecord record = mLayoutHolderMap.valueAt(index);
10813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        if (record != null && (record.flags & flag) != 0) {
10913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            record.flags &= ~flag;
11013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            final ItemHolderInfo info;
11113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            if (flag == FLAG_PRE) {
11213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                info = record.preInfo;
11313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            } else if (flag == FLAG_POST) {
11413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                info = record.postInfo;
11513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            } else {
11613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                throw new IllegalArgumentException("Must provide flag PRE or POST");
11713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            }
11813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            // if not pre-post flag is left, clear.
11913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            if ((record.flags & (FLAG_PRE | FLAG_POST)) == 0) {
120e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                mLayoutHolderMap.removeAt(index);
121e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                InfoRecord.recycle(record);
122e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            }
123e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            return info;
124e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
125e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        return null;
126e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
127e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
128e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
129e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Adds the given ViewHolder to the oldChangeHolders list
130e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param key The key to identify the ViewHolder.
131e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param holder The ViewHolder to store
132e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
133e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void addToOldChangeHolders(long key, ViewHolder holder) {
134e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        mOldChangedHolders.put(key, holder);
135e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
136e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
137e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
138e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Adds the given ViewHolder to the appeared in pre layout list. These are Views added by the
139e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * LayoutManager during a pre-layout pass. We distinguish them from other views that were
140e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * already in the pre-layout so that ItemAnimator can choose to run a different animation for
141e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * them.
142e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     *
143e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param holder The ViewHolder to store
144e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param info The information to save
145e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
146e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void addToAppearedInPreLayoutHolders(ViewHolder holder, ItemHolderInfo info) {
147e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        InfoRecord record = mLayoutHolderMap.get(holder);
148e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        if (record == null) {
149e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            record = InfoRecord.obtain();
150e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            mLayoutHolderMap.put(holder, record);
151e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
152e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        record.flags |= FLAG_APPEAR;
153e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        record.preInfo = info;
154e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
155e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
156e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
157e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Checks whether the given ViewHolder is in preLayout list
158e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param viewHolder The ViewHolder to query
159e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     *
160e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @return True if the ViewHolder is present in preLayout, false otherwise
161e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
162e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    boolean isInPreLayout(ViewHolder viewHolder) {
163e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        final InfoRecord record = mLayoutHolderMap.get(viewHolder);
164e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        return record != null && (record.flags & FLAG_PRE) != 0;
165e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
166e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
167e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
168e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Queries the oldChangeHolder list for the given key. If they are not tracked, simply returns
169e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * null.
170e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param key The key to be used to find the ViewHolder.
171e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     *
172e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @return A ViewHolder if exists or null if it does not exist.
173e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
174e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    ViewHolder getFromOldChangeHolders(long key) {
175e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        return mOldChangedHolders.get(key);
176e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
177e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
178e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
179e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Adds the item information to the post layout list
180e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param holder The ViewHolder whose information is being saved
181e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param info The information to save
182e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
183e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void addToPostLayout(ViewHolder holder, ItemHolderInfo info) {
184e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        InfoRecord record = mLayoutHolderMap.get(holder);
185e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        if (record == null) {
186e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            record = InfoRecord.obtain();
187e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            mLayoutHolderMap.put(holder, record);
188e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
189e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        record.postInfo = info;
190e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        record.flags |= FLAG_POST;
191e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
192e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
193e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
194e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * A ViewHolder might be added by the LayoutManager just to animate its disappearance.
195e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * This list holds such items so that we can animate / recycle these ViewHolders properly.
196e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     *
197e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param holder The ViewHolder which disappeared during a layout.
198e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
199e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void addToDisappearedInLayout(ViewHolder holder) {
200e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        InfoRecord record = mLayoutHolderMap.get(holder);
201e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        if (record == null) {
202e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            record = InfoRecord.obtain();
203e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            mLayoutHolderMap.put(holder, record);
204e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
205e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        record.flags |= FLAG_DISAPPEARED;
206e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
207e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
208e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
209e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Removes a ViewHolder from disappearing list.
210e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param holder The ViewHolder to be removed from the disappearing list.
211e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
212e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void removeFromDisappearedInLayout(ViewHolder holder) {
213e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        InfoRecord record = mLayoutHolderMap.get(holder);
214e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        if (record == null) {
215e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            return;
216e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
217e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        record.flags &= ~FLAG_DISAPPEARED;
218e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
219e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
220e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void process(ProcessCallback callback) {
221e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        for (int index = mLayoutHolderMap.size() - 1; index >= 0; index --) {
222e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            final ViewHolder viewHolder = mLayoutHolderMap.keyAt(index);
223e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            final InfoRecord record = mLayoutHolderMap.removeAt(index);
224e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            if ((record.flags & FLAG_APPEAR_AND_DISAPPEAR) == FLAG_APPEAR_AND_DISAPPEAR) {
225e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                // Appeared then disappeared. Not useful for animations.
226e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                callback.unused(viewHolder);
227e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            } else if ((record.flags & FLAG_DISAPPEARED) != 0) {
228e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                // Set as "disappeared" by the LayoutManager (addDisappearingView)
229a7d7e30042bb6fbe2944b752a24fd57fd31d285fYigit Boyar                if (record.preInfo == null) {
230a7d7e30042bb6fbe2944b752a24fd57fd31d285fYigit Boyar                    // similar to appear disappear but happened between different layout passes.
231a7d7e30042bb6fbe2944b752a24fd57fd31d285fYigit Boyar                    // this can happen when the layout manager is using auto-measure
232a7d7e30042bb6fbe2944b752a24fd57fd31d285fYigit Boyar                    callback.unused(viewHolder);
233a7d7e30042bb6fbe2944b752a24fd57fd31d285fYigit Boyar                } else {
234a7d7e30042bb6fbe2944b752a24fd57fd31d285fYigit Boyar                    callback.processDisappeared(viewHolder, record.preInfo, record.postInfo);
235a7d7e30042bb6fbe2944b752a24fd57fd31d285fYigit Boyar                }
236e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            } else if ((record.flags & FLAG_APPEAR_PRE_AND_POST) == FLAG_APPEAR_PRE_AND_POST) {
237e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                // Appeared in the layout but not in the adapter (e.g. entered the viewport)
238e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
239e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            } else if ((record.flags & FLAG_PRE_AND_POST) == FLAG_PRE_AND_POST) {
240e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                // Persistent in both passes. Animate persistence
241e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                callback.processPersistent(viewHolder, record.preInfo, record.postInfo);
242e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            } else if ((record.flags & FLAG_PRE) != 0) {
243e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                // Was in pre-layout, never been added to post layout
244e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                callback.processDisappeared(viewHolder, record.preInfo, null);
245e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            } else if ((record.flags & FLAG_POST) != 0) {
246e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                // Was not in pre-layout, been added to post layout
247e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
248e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            } else if ((record.flags & FLAG_APPEAR) != 0) {
249e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                // Scrap view. RecyclerView will handle removing/recycling this.
250e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            } else if (DEBUG) {
251e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                throw new IllegalStateException("record without any reasonable flag combination:/");
252e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            }
253e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            InfoRecord.recycle(record);
254e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
255e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
256e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
257e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    /**
258e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * Removes the ViewHolder from all list
259e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     * @param holder The ViewHolder which we should stop tracking
260e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar     */
261e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void removeViewHolder(ViewHolder holder) {
262e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        for (int i = mOldChangedHolders.size() - 1; i >= 0; i--) {
263e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            if (holder == mOldChangedHolders.valueAt(i)) {
264e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                mOldChangedHolders.removeAt(i);
265e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                break;
266e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            }
267e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
268e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        final InfoRecord info = mLayoutHolderMap.remove(holder);
269e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        if (info != null) {
270e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            InfoRecord.recycle(info);
271e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
272e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
273e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
274e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    void onDetach() {
275e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        InfoRecord.drainCache();
276e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
277e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
2784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public void onViewDetached(ViewHolder viewHolder) {
2794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        removeFromDisappearedInLayout(viewHolder);
2804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
2814143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
282e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    interface ProcessCallback {
283a7d7e30042bb6fbe2944b752a24fd57fd31d285fYigit Boyar        void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo,
284e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                @Nullable ItemHolderInfo postInfo);
285e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        void processAppeared(ViewHolder viewHolder, @Nullable ItemHolderInfo preInfo,
286e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                ItemHolderInfo postInfo);
287e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        void processPersistent(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo,
288e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                @NonNull ItemHolderInfo postInfo);
289e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        void unused(ViewHolder holder);
290e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
291e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
292e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    static class InfoRecord {
293e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        // disappearing list
294e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static final int FLAG_DISAPPEARED = 1;
295e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        // appear in pre layout list
296e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static final int FLAG_APPEAR = 1 << 1;
297e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        // pre layout, this is necessary to distinguish null item info
298e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static final int FLAG_PRE = 1 << 2;
299e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        // post layout, this is necessary to distinguish null item info
300e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static final int FLAG_POST = 1 << 3;
301e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static final int FLAG_APPEAR_AND_DISAPPEAR = FLAG_APPEAR | FLAG_DISAPPEARED;
302e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static final int FLAG_PRE_AND_POST = FLAG_PRE | FLAG_POST;
303e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static final int FLAG_APPEAR_PRE_AND_POST = FLAG_APPEAR | FLAG_PRE | FLAG_POST;
304e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        int flags;
305e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        @Nullable ItemHolderInfo preInfo;
306e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        @Nullable ItemHolderInfo postInfo;
307e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static Pools.Pool<InfoRecord> sPool = new Pools.SimplePool<>(20);
308e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
309e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        private InfoRecord() {
310e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
311e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
312e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static InfoRecord obtain() {
313e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            InfoRecord record = sPool.acquire();
314e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            return record == null ? new InfoRecord() : record;
315e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
316e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
317e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static void recycle(InfoRecord record) {
318e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            record.flags = 0;
319e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            record.preInfo = null;
320e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            record.postInfo = null;
321e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            sPool.release(record);
322e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
323e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
324e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        static void drainCache() {
325e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            //noinspection StatementWithEmptyBody
326e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            while (sPool.acquire() != null);
327e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
328e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    }
329e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar}
330