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