18ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar/* 2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project 38ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * 48ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 58ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * you may not use this file except in compliance with the License. 68ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * You may obtain a copy of the License at 78ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * 88ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 98ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * 108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Unless required by applicable law or agreed to in writing, software 118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * See the License for the specific language governing permissions and 148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * limitations under the License. 158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.recyclerview.widget; 188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 191faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyarimport android.util.Log; 208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 21c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.core.util.Pools; 22c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikas 238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.ArrayList; 248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.Collections; 258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.List; 268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar/** 288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Helper class that can enqueue and process adapter update operations. 298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p> 308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * To support animations, RecyclerView presents an older version the Adapter to best represent 318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * previous state of the layout. Sometimes, this is not trivial when items are removed that were 328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * not laid out, in which case, RecyclerView has no way of providing that item's view for 338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * animations. 348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p> 358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * AdapterHelper creates an UpdateOp for each adapter data change then pre-processes them. During 368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * pre processing, AdapterHelper finds out which UpdateOps can be deferred to second layout pass 378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * and which cannot. For the UpdateOps that cannot be deferred, AdapterHelper will change them 388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * according to previously deferred operation and dispatch them before the first layout pass. It 398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * also takes care of updating deferred UpdateOps since order of operations is changed by this 408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * process. 418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p> 428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Although operations may be forwarded to LayoutManager in different orders, resulting data set 438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * is guaranteed to be the consistent. 448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarclass AdapterHelper implements OpReorderer.Callback { 468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 471e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas static final int POSITION_TYPE_INVISIBLE = 0; 488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 491e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas static final int POSITION_TYPE_NEW_OR_LAID_OUT = 1; 508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 511faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private static final boolean DEBUG = false; 521faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 531faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private static final String TAG = "AHT"; 541faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private Pools.Pool<UpdateOp> mUpdateOpPool = new Pools.SimplePool<UpdateOp>(UpdateOp.POOL_SIZE); 568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>(); 588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final ArrayList<UpdateOp> mPostponedList = new ArrayList<UpdateOp>(); 608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final Callback mCallback; 628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Runnable mOnItemProcessedCallback; 648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final boolean mDisableRecycler; 668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar final OpReorderer mOpReorderer; 684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar 69121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar private int mExistingUpdateTypes = 0; 70121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AdapterHelper(Callback callback) { 728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar this(callback, false); 738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AdapterHelper(Callback callback, boolean disableRecycler) { 768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mCallback = callback; 778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mDisableRecycler = disableRecycler; 784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mOpReorderer = new OpReorderer(this); 798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AdapterHelper addUpdateOp(UpdateOp... ops) { 828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Collections.addAll(mPendingUpdates, ops); 838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return this; 848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void reset() { 878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOpsAndClearList(mPendingUpdates); 888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOpsAndClearList(mPostponedList); 89121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes = 0; 908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void preProcess() { 934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mOpReorderer.reorderOps(mPendingUpdates); 948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPendingUpdates.size(); 958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mPendingUpdates.get(i); 978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar switch (op.cmd) { 988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.ADD: 998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar applyAdd(op); 1008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 1018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.REMOVE: 1028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar applyRemove(op); 1038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 1048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.UPDATE: 1058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar applyUpdate(op); 1068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 1071faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case UpdateOp.MOVE: 1081faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar applyMove(op); 1091faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar break; 1108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mOnItemProcessedCallback != null) { 1128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mOnItemProcessedCallback.run(); 1138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mPendingUpdates.clear(); 1168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void consumePostponedUpdates() { 1198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPostponedList.size(); 1208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 1218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mCallback.onDispatchSecondPass(mPostponedList.get(i)); 1228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOpsAndClearList(mPostponedList); 124121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes = 0; 1258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1271faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private void applyMove(UpdateOp op) { 1281faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // MOVE ops are pre-processed so at this point, we know that item is still in the adapter. 1291faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // otherwise, it would be converted into a REMOVE operation 1304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(op); 1311faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 1321faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 1338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void applyRemove(UpdateOp op) { 1348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpStart = op.positionStart; 1358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpCount = 0; 1368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpEnd = op.positionStart + op.itemCount; 1378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int type = -1; 1388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position = op.positionStart; position < tmpEnd; position++) { 1398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar boolean typeChanged = false; 140a4b6d823ff4dc52ec665fc4b6d7ddde5e18e0560Yigit Boyar RecyclerView.ViewHolder vh = mCallback.findViewHolder(position); 1411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (vh != null || canFindInPreLayout(position)) { 1428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // If a ViewHolder exists or this is a newly added item, we can defer this update 1438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // to post layout stage. 1448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // * For existing ViewHolders, we'll fake its existence in the pre-layout phase. 1458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // * For items that are added and removed in the same process cycle, they won't 1468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // have any effect in pre-layout since their add ops are already deferred to 1478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // post-layout pass. 1488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_INVISIBLE) { 1498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // Looks like we have other updates that we cannot merge with this one. 1508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // Create an UpdateOp and dispatch it to LayoutManager. 15121b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchAndUpdateViewHolders(newOp); 1538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar typeChanged = true; 1548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar type = POSITION_TYPE_NEW_OR_LAID_OUT; 1568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 1578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // This update cannot be recovered because we don't have a ViewHolder representing 1588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // this position. Instead, post it to LayoutManager immediately 1598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_NEW_OR_LAID_OUT) { 1608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // Looks like we have other updates that we cannot merge with this one. 1618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // Create UpdateOp op and dispatch it to LayoutManager. 16221b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(newOp); 1648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar typeChanged = true; 1658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar type = POSITION_TYPE_INVISIBLE; 1678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (typeChanged) { 1698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar position -= tmpCount; // also equal to tmpStart 1708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpEnd -= tmpCount; 1718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount = 1; 1728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 1738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount++; 1748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (tmpCount != op.itemCount) { // all 1 effect 1778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOp(op); 17821b345f101abc385496f42d250e580d21f1287b6Dake Gu op = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_INVISIBLE) { 1814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchAndUpdateViewHolders(op); 1828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 1834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(op); 1848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void applyUpdate(UpdateOp op) { 1888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpStart = op.positionStart; 1898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpCount = 0; 1908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpEnd = op.positionStart + op.itemCount; 1918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int type = -1; 1928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position = op.positionStart; position < tmpEnd; position++) { 193a4b6d823ff4dc52ec665fc4b6d7ddde5e18e0560Yigit Boyar RecyclerView.ViewHolder vh = mCallback.findViewHolder(position); 1941faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (vh != null || canFindInPreLayout(position)) { // deferred 1958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_INVISIBLE) { 19621b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, 19721b345f101abc385496f42d250e580d21f1287b6Dake Gu op.payload); 1984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchAndUpdateViewHolders(newOp); 1998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount = 0; 200e4fde6825bba479c9b030feb8f810694d46b2f06Yigit Boyar tmpStart = position; 2018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar type = POSITION_TYPE_NEW_OR_LAID_OUT; 2038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { // applied 2048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_NEW_OR_LAID_OUT) { 20521b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, 20621b345f101abc385496f42d250e580d21f1287b6Dake Gu op.payload); 2074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(newOp); 2088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount = 0; 209e4fde6825bba479c9b030feb8f810694d46b2f06Yigit Boyar tmpStart = position; 2108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar type = POSITION_TYPE_INVISIBLE; 2128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount++; 2148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (tmpCount != op.itemCount) { // all 1 effect 21621b345f101abc385496f42d250e580d21f1287b6Dake Gu Object payload = op.payload; 2178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOp(op); 21821b345f101abc385496f42d250e580d21f1287b6Dake Gu op = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, payload); 2198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_INVISIBLE) { 2214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchAndUpdateViewHolders(op); 2228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 2234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(op); 2248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 2274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar private void dispatchAndUpdateViewHolders(UpdateOp op) { 2288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // tricky part. 2298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // traverse all postpones and revert their changes on this op if necessary, apply updated 2308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // dispatch to them since now they are after this op. 2311faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.cmd == UpdateOp.ADD || op.cmd == UpdateOp.MOVE) { 2321faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar throw new IllegalArgumentException("should not dispatch add or move for pre layout"); 2331faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2341faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar Log.d(TAG, "dispatch (pre)" + op); 2361faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "postponed state before:"); 2371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (UpdateOp updateOp : mPostponedList) { 2381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, updateOp.toString()); 2391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "----"); 2411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 2431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // handle each pos 1 by 1 to ensure continuity. If it breaks, dispatch partial 2444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar // TODO Since move ops are pushed to end, we should not need this anymore 2451faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar int tmpStart = updatePositionWithPostponed(op.positionStart, op.cmd); 2461faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2471faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "pos:" + op.positionStart + ",updatedPos:" + tmpStart); 2481faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar int tmpCnt = 1; 2504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar int offsetPositionForPartial = op.positionStart; 2514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar final int positionMultiplier; 2524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar switch (op.cmd) { 2534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.UPDATE: 2544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar positionMultiplier = 1; 2554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 2564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.REMOVE: 2574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar positionMultiplier = 0; 2584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 2594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar default: 2604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar throw new IllegalArgumentException("op should be remove or update." + op); 2614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 2621faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (int p = 1; p < op.itemCount; p++) { 2634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar final int pos = op.positionStart + (positionMultiplier * p); 2641faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar int updatedPos = updatePositionWithPostponed(pos, op.cmd); 2651faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2661faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "pos:" + pos + ",updatedPos:" + updatedPos); 2671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2681faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar boolean continuous = false; 2691faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar switch (op.cmd) { 2701faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case UpdateOp.UPDATE: 2711faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar continuous = updatedPos == tmpStart + 1; 2721faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar break; 2731faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case UpdateOp.REMOVE: 2741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar continuous = updatedPos == tmpStart; 2751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar break; 2761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (continuous) { 2781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar tmpCnt++; 2791faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else { 2801faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // need to dispatch this separately 28121b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, op.payload); 2821faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2831faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "need to dispatch separately " + tmp); 2841faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2854b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial); 2861faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(tmp); 2874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar if (op.cmd == UpdateOp.UPDATE) { 2884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar offsetPositionForPartial += tmpCnt; 2894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 2901e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas tmpStart = updatedPos; // need to remove previously dispatched 2911faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar tmpCnt = 1; 2921faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2931faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 29421b345f101abc385496f42d250e580d21f1287b6Dake Gu Object payload = op.payload; 2951faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(op); 2961faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (tmpCnt > 0) { 29721b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, payload); 2981faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2991faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "dispatching:" + tmp); 3001faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3014b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial); 3021faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(tmp); 3031faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3041faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 3051faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "post dispatch"); 3061faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "postponed state after:"); 3071faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (UpdateOp updateOp : mPostponedList) { 3081faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, updateOp.toString()); 3091faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3101faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "----"); 3111faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3121faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3131faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 3144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar void dispatchFirstPassAndUpdateViewHolders(UpdateOp op, int offsetStart) { 3154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.onDispatchFirstPass(op); 3164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar switch (op.cmd) { 3174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.REMOVE: 3184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.offsetPositionsForRemovingInvisible(offsetStart, op.itemCount); 3194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 3204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.UPDATE: 32121b345f101abc385496f42d250e580d21f1287b6Dake Gu mCallback.markViewHoldersUpdated(offsetStart, op.itemCount, op.payload); 3224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 3234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar default: 3244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar throw new IllegalArgumentException("only remove and update ops can be dispatched" 3254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar + " in first pass"); 3264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 3274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 3284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar 3291faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private int updatePositionWithPostponed(int pos, int cmd) { 3308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPostponedList.size(); 3318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = count - 1; i >= 0; i--) { 3328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp postponed = mPostponedList.get(i); 3331faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (postponed.cmd == UpdateOp.MOVE) { 3341faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar int start, end; 3351faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (postponed.positionStart < postponed.itemCount) { 3361faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar start = postponed.positionStart; 3371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar end = postponed.itemCount; 3381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else { 3391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar start = postponed.itemCount; 3401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar end = postponed.positionStart; 3411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (pos >= start && pos <= end) { 3431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar //i'm affected 3441faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (start == postponed.positionStart) { 3451faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (cmd == UpdateOp.ADD) { 3461faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.itemCount++; 3471faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (cmd == UpdateOp.REMOVE) { 3481faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.itemCount--; 3491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3501faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // op moved to left, move it right to revert 3511faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar pos++; 3521faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else { 3531faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (cmd == UpdateOp.ADD) { 3541faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart++; 3551faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (cmd == UpdateOp.REMOVE) { 3561faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart--; 3571faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3581faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // op was moved right, move left to revert 3591faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar pos--; 3601faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3611faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (pos < postponed.positionStart) { 3621faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // postponed MV is outside the dispatched OP. if it is before, offset 3631faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (cmd == UpdateOp.ADD) { 3641faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart++; 3651faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.itemCount++; 3661faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (cmd == UpdateOp.REMOVE) { 3671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart--; 3681faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.itemCount--; 3691faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3701faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 3721faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (postponed.positionStart <= pos) { 3731faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (postponed.cmd == UpdateOp.ADD) { 3741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar pos -= postponed.itemCount; 3751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (postponed.cmd == UpdateOp.REMOVE) { 3761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar pos += postponed.itemCount; 3771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else { 3791faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (cmd == UpdateOp.ADD) { 3801faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart++; 3811faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (cmd == UpdateOp.REMOVE) { 3821faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart--; 3831faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3841faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3851faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3861faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 3871faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "dispath (step" + i + ")"); 3881faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "postponed state:" + i + ", pos:" + pos); 3891faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (UpdateOp updateOp : mPostponedList) { 3901faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, updateOp.toString()); 3911faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3921faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "----"); 3938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 3948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 3951faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (int i = mPostponedList.size() - 1; i >= 0; i--) { 3961faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar UpdateOp op = mPostponedList.get(i); 3971faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.cmd == UpdateOp.MOVE) { 3981faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.itemCount == op.positionStart || op.itemCount < 0) { 3991faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar mPostponedList.remove(i); 4001faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(op); 4011faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4021faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (op.itemCount <= 0) { 4031faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar mPostponedList.remove(i); 4041faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(op); 4051faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4061faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4071faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return pos; 4088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4101faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private boolean canFindInPreLayout(int position) { 4118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPostponedList.size(); 4128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 4138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mPostponedList.get(i); 4141faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.cmd == UpdateOp.MOVE) { 4154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar if (findPositionOffset(op.itemCount, i + 1) == position) { 4161faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return true; 4171faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4181faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (op.cmd == UpdateOp.ADD) { 4191faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // TODO optimize. 4201faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar final int end = op.positionStart + op.itemCount; 4211faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (int pos = op.positionStart; pos < end; pos++) { 4221faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (findPositionOffset(pos, i + 1) == position) { 4231faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return true; 4241faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4251faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 4298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void applyAdd(UpdateOp op) { 4324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(op); 4338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar private void postponeAndUpdateViewHolders(UpdateOp op) { 4361faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 4371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "postponing " + op); 4381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mPostponedList.add(op); 4404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar switch (op.cmd) { 4414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.ADD: 4424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount); 4434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 4444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.MOVE: 4454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.offsetPositionsForMove(op.positionStart, op.itemCount); 4464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 4474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.REMOVE: 4484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.offsetPositionsForRemovingLaidOutOrNewView(op.positionStart, 4494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar op.itemCount); 4504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 4514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.UPDATE: 45221b345f101abc385496f42d250e580d21f1287b6Dake Gu mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload); 4534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 4544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar default: 4554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar throw new IllegalArgumentException("Unknown update op type for " + op); 4564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 4578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar boolean hasPendingUpdates() { 4608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mPendingUpdates.size() > 0; 4618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 463121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar boolean hasAnyUpdateTypes(int updateTypes) { 464121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar return (mExistingUpdateTypes & updateTypes) != 0; 465121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 466121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 4678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int findPositionOffset(int position) { 4688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return findPositionOffset(position, 0); 4698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 471668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int findPositionOffset(int position, int firstPostponedItem) { 4728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int count = mPostponedList.size(); 473668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (int i = firstPostponedItem; i < count; ++i) { 4748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mPostponedList.get(i); 4751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.cmd == UpdateOp.MOVE) { 4761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.positionStart == position) { 4771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar position = op.itemCount; 4784bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar } else { 4794bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar if (op.positionStart < position) { 4804bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar position--; // like a remove 4814bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar } 4824bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar if (op.itemCount <= position) { 4834bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar position++; // like an add 4844bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar } 4851faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4861faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (op.positionStart <= position) { 4878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (op.cmd == UpdateOp.REMOVE) { 4884bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar if (position < op.positionStart + op.itemCount) { 4894bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar return -1; 4904bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar } 4911faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar position -= op.itemCount; 4928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else if (op.cmd == UpdateOp.ADD) { 4931faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar position += op.itemCount; 4948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4971faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return position; 4988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 5018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * @return True if updates should be processed. 5028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 50321b345f101abc385496f42d250e580d21f1287b6Dake Gu boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) { 5048fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar if (itemCount < 1) { 5058fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar return false; 5068fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 50721b345f101abc385496f42d250e580d21f1287b6Dake Gu mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload)); 508121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes |= UpdateOp.UPDATE; 5098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mPendingUpdates.size() == 1; 5108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 5138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * @return True if updates should be processed. 5148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 5158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar boolean onItemRangeInserted(int positionStart, int itemCount) { 5168fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar if (itemCount < 1) { 5178fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar return false; 5188fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 51921b345f101abc385496f42d250e580d21f1287b6Dake Gu mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null)); 520121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes |= UpdateOp.ADD; 5218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mPendingUpdates.size() == 1; 5228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 5258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * @return True if updates should be processed. 5268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 5278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar boolean onItemRangeRemoved(int positionStart, int itemCount) { 5288fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar if (itemCount < 1) { 5298fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar return false; 5308fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 53121b345f101abc385496f42d250e580d21f1287b6Dake Gu mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null)); 532121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes |= UpdateOp.REMOVE; 5338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mPendingUpdates.size() == 1; 5348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 5371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar * @return True if updates should be processed. 5381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar */ 5391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar boolean onItemRangeMoved(int from, int to, int itemCount) { 5401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (from == to) { 5414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar return false; // no-op 5421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 5431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (itemCount != 1) { 5441faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar throw new IllegalArgumentException("Moving more than 1 item is not supported yet"); 5451faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 54621b345f101abc385496f42d250e580d21f1287b6Dake Gu mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null)); 547121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes |= UpdateOp.MOVE; 5481faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return mPendingUpdates.size() == 1; 5491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 5501faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 5511faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar /** 5528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Skips pre-processing and applies all updates in one pass. 5538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 5548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void consumeUpdatesInOnePass() { 5558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // we still consume postponed updates (if there is) in case there was a pre-process call 5568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // w/o a matching consumePostponedUpdates. 5578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar consumePostponedUpdates(); 5588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPendingUpdates.size(); 5598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 5608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mPendingUpdates.get(i); 5618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar switch (op.cmd) { 5628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.ADD: 5638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mCallback.onDispatchSecondPass(op); 56416e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount); 5658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 5668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.REMOVE: 5678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mCallback.onDispatchSecondPass(op); 56816e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar mCallback.offsetPositionsForRemovingInvisible(op.positionStart, op.itemCount); 5698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 5708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.UPDATE: 57116e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar mCallback.onDispatchSecondPass(op); 57221b345f101abc385496f42d250e580d21f1287b6Dake Gu mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload); 5738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 5741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case UpdateOp.MOVE: 57516e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar mCallback.onDispatchSecondPass(op); 5761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar mCallback.offsetPositionsForMove(op.positionStart, op.itemCount); 5771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar break; 5788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mOnItemProcessedCallback != null) { 5808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mOnItemProcessedCallback.run(); 5818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOpsAndClearList(mPendingUpdates); 584121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes = 0; 5858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 587115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public int applyPendingUpdatesToPosition(int position) { 588115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int size = mPendingUpdates.size(); 5891e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas for (int i = 0; i < size; i++) { 590115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar UpdateOp op = mPendingUpdates.get(i); 591115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar switch (op.cmd) { 592115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar case UpdateOp.ADD: 593115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.positionStart <= position) { 594115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position += op.itemCount; 595115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 596115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar break; 597115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar case UpdateOp.REMOVE: 598115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.positionStart <= position) { 599115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int end = op.positionStart + op.itemCount; 600115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (end > position) { 601115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar return RecyclerView.NO_POSITION; 602115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 603115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position -= op.itemCount; 604115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 605115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar break; 606115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar case UpdateOp.MOVE: 607115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.positionStart == position) { 6081e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas position = op.itemCount; //position end 609115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } else { 610115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.positionStart < position) { 611115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position -= 1; 612115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 613115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.itemCount <= position) { 614115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position += 1; 615115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 616115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 617115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar break; 618115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 619115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 620115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar return position; 621115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 622115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 6234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar boolean hasUpdates() { 6244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty(); 6254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 6264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 6278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 6288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Queued operation to happen when child views are updated. 6298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 6308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static class UpdateOp { 6318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 632121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar static final int ADD = 1; 6338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 634121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar static final int REMOVE = 1 << 1; 6358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 636121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar static final int UPDATE = 1 << 2; 6378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 638121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar static final int MOVE = 1 << 3; 6391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 6408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static final int POOL_SIZE = 30; 6418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int cmd; 6438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int positionStart; 6458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 64621b345f101abc385496f42d250e580d21f1287b6Dake Gu Object payload; 64721b345f101abc385496f42d250e580d21f1287b6Dake Gu 6481faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // holds the target position if this is a MOVE 6498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int itemCount; 6508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 65121b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp(int cmd, int positionStart, int itemCount, Object payload) { 6528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar this.cmd = cmd; 6538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar this.positionStart = positionStart; 6548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar this.itemCount = itemCount; 65521b345f101abc385496f42d250e580d21f1287b6Dake Gu this.payload = payload; 6568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar String cmdToString() { 6598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar switch (cmd) { 6608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case ADD: 6618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "add"; 6628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case REMOVE: 6638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "rm"; 6648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UPDATE: 6658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "up"; 6661faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case MOVE: 6671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return "mv"; 6688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "??"; 6708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 6738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public String toString() { 67421b345f101abc385496f42d250e580d21f1287b6Dake Gu return Integer.toHexString(System.identityHashCode(this)) 67521b345f101abc385496f42d250e580d21f1287b6Dake Gu + "[" + cmdToString() + ",s:" + positionStart + "c:" + itemCount 6761e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas + ",p:" + payload + "]"; 6778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 6808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public boolean equals(Object o) { 6818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (this == o) { 6828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return true; 6838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (o == null || getClass() != o.getClass()) { 6858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 6868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = (UpdateOp) o; 6898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (cmd != op.cmd) { 6918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 6928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar if (cmd == MOVE && Math.abs(itemCount - positionStart) == 1) { 6944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar // reverse of this is also true 6954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar if (itemCount == op.positionStart && positionStart == op.itemCount) { 6964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar return true; 6974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 6984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 6998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (itemCount != op.itemCount) { 7008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 7018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (positionStart != op.positionStart) { 7038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 7048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 70521b345f101abc385496f42d250e580d21f1287b6Dake Gu if (payload != null) { 70621b345f101abc385496f42d250e580d21f1287b6Dake Gu if (!payload.equals(op.payload)) { 70721b345f101abc385496f42d250e580d21f1287b6Dake Gu return false; 70821b345f101abc385496f42d250e580d21f1287b6Dake Gu } 70921b345f101abc385496f42d250e580d21f1287b6Dake Gu } else if (op.payload != null) { 71021b345f101abc385496f42d250e580d21f1287b6Dake Gu return false; 71121b345f101abc385496f42d250e580d21f1287b6Dake Gu } 7128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return true; 7148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 7178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public int hashCode() { 7188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int result = cmd; 7198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar result = 31 * result + positionStart; 7208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar result = 31 * result + itemCount; 7218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return result; 7228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar @Override 72621b345f101abc385496f42d250e580d21f1287b6Dake Gu public UpdateOp obtainUpdateOp(int cmd, int positionStart, int itemCount, Object payload) { 7278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mUpdateOpPool.acquire(); 7288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (op == null) { 72921b345f101abc385496f42d250e580d21f1287b6Dake Gu op = new UpdateOp(cmd, positionStart, itemCount, payload); 7308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 7318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar op.cmd = cmd; 7328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar op.positionStart = positionStart; 7338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar op.itemCount = itemCount; 73421b345f101abc385496f42d250e580d21f1287b6Dake Gu op.payload = payload; 7358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return op; 7378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar @Override 7404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar public void recycleUpdateOp(UpdateOp op) { 7418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (!mDisableRecycler) { 74221b345f101abc385496f42d250e580d21f1287b6Dake Gu op.payload = null; 7438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mUpdateOpPool.release(op); 7448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void recycleUpdateOpsAndClearList(List<UpdateOp> ops) { 7488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = ops.size(); 7498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 7508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOp(ops.get(i)); 7518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ops.clear(); 7538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 7568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Contract between AdapterHelper and RecyclerView. 7578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 758a4b6d823ff4dc52ec665fc4b6d7ddde5e18e0560Yigit Boyar interface Callback { 7598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 760a4b6d823ff4dc52ec665fc4b6d7ddde5e18e0560Yigit Boyar RecyclerView.ViewHolder findViewHolder(int position); 7618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void offsetPositionsForRemovingInvisible(int positionStart, int itemCount); 7638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount); 7658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 76621b345f101abc385496f42d250e580d21f1287b6Dake Gu void markViewHoldersUpdated(int positionStart, int itemCount, Object payloads); 7678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onDispatchFirstPass(UpdateOp updateOp); 7698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onDispatchSecondPass(UpdateOp updateOp); 7718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void offsetPositionsForAdd(int positionStart, int itemCount); 7731faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 7741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar void offsetPositionsForMove(int from, int to); 7758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7764bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar} 777