18ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar/* 28ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Copyright (C) 2014 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 178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarpackage android.support.v7.widget; 188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport android.support.v4.util.Pools; 201faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyarimport android.util.Log; 218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.ArrayList; 238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.Collections; 248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.List; 258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport static android.support.v7.widget.RecyclerView.*; 278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar/** 298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Helper class that can enqueue and process adapter update operations. 308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p> 318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * To support animations, RecyclerView presents an older version the Adapter to best represent 328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * previous state of the layout. Sometimes, this is not trivial when items are removed that were 338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * not laid out, in which case, RecyclerView has no way of providing that item's view for 348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * animations. 358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p> 368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * AdapterHelper creates an UpdateOp for each adapter data change then pre-processes them. During 378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * pre processing, AdapterHelper finds out which UpdateOps can be deferred to second layout pass 388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * and which cannot. For the UpdateOps that cannot be deferred, AdapterHelper will change them 398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * according to previously deferred operation and dispatch them before the first layout pass. It 408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * also takes care of updating deferred UpdateOps since order of operations is changed by this 418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * process. 428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p> 438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Although operations may be forwarded to LayoutManager in different orders, resulting data set 448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * is guaranteed to be the consistent. 458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarclass AdapterHelper implements OpReorderer.Callback { 478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final static int POSITION_TYPE_INVISIBLE = 0; 498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final static int POSITION_TYPE_NEW_OR_LAID_OUT = 1; 518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 521faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private static final boolean DEBUG = false; 531faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 541faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private static final String TAG = "AHT"; 551faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private Pools.Pool<UpdateOp> mUpdateOpPool = new Pools.SimplePool<UpdateOp>(UpdateOp.POOL_SIZE); 578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>(); 598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final ArrayList<UpdateOp> mPostponedList = new ArrayList<UpdateOp>(); 618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final Callback mCallback; 638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Runnable mOnItemProcessedCallback; 658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final boolean mDisableRecycler; 678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar final OpReorderer mOpReorderer; 694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar 70121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar private int mExistingUpdateTypes = 0; 71121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AdapterHelper(Callback callback) { 738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar this(callback, false); 748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AdapterHelper(Callback callback, boolean disableRecycler) { 778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mCallback = callback; 788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mDisableRecycler = disableRecycler; 794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mOpReorderer = new OpReorderer(this); 808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AdapterHelper addUpdateOp(UpdateOp... ops) { 838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Collections.addAll(mPendingUpdates, ops); 848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return this; 858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void reset() { 888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOpsAndClearList(mPendingUpdates); 898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOpsAndClearList(mPostponedList); 90121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes = 0; 918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void preProcess() { 944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mOpReorderer.reorderOps(mPendingUpdates); 958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPendingUpdates.size(); 968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mPendingUpdates.get(i); 988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar switch (op.cmd) { 998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.ADD: 1008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar applyAdd(op); 1018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 1028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.REMOVE: 1038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar applyRemove(op); 1048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 1058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.UPDATE: 1068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar applyUpdate(op); 1078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 1081faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case UpdateOp.MOVE: 1091faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar applyMove(op); 1101faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar break; 1118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mOnItemProcessedCallback != null) { 1138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mOnItemProcessedCallback.run(); 1148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mPendingUpdates.clear(); 1178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void consumePostponedUpdates() { 1208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPostponedList.size(); 1218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 1228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mCallback.onDispatchSecondPass(mPostponedList.get(i)); 1238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOpsAndClearList(mPostponedList); 125121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes = 0; 1268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1281faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private void applyMove(UpdateOp op) { 1291faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // MOVE ops are pre-processed so at this point, we know that item is still in the adapter. 1301faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // otherwise, it would be converted into a REMOVE operation 1314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(op); 1321faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 1331faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 1348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void applyRemove(UpdateOp op) { 1358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpStart = op.positionStart; 1368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpCount = 0; 1378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpEnd = op.positionStart + op.itemCount; 1388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int type = -1; 1398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position = op.positionStart; position < tmpEnd; position++) { 1408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar boolean typeChanged = false; 1418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ViewHolder vh = mCallback.findViewHolder(position); 1421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (vh != null || canFindInPreLayout(position)) { 1438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // If a ViewHolder exists or this is a newly added item, we can defer this update 1448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // to post layout stage. 1458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // * For existing ViewHolders, we'll fake its existence in the pre-layout phase. 1468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // * For items that are added and removed in the same process cycle, they won't 1478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // have any effect in pre-layout since their add ops are already deferred to 1488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // post-layout pass. 1498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_INVISIBLE) { 1508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // Looks like we have other updates that we cannot merge with this one. 1518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // Create an UpdateOp and dispatch it to LayoutManager. 15221b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchAndUpdateViewHolders(newOp); 1548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar typeChanged = true; 1558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar type = POSITION_TYPE_NEW_OR_LAID_OUT; 1578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 1588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // This update cannot be recovered because we don't have a ViewHolder representing 1598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // this position. Instead, post it to LayoutManager immediately 1608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_NEW_OR_LAID_OUT) { 1618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // Looks like we have other updates that we cannot merge with this one. 1628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // Create UpdateOp op and dispatch it to LayoutManager. 16321b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(newOp); 1658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar typeChanged = true; 1668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar type = POSITION_TYPE_INVISIBLE; 1688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (typeChanged) { 1708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar position -= tmpCount; // also equal to tmpStart 1718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpEnd -= tmpCount; 1728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount = 1; 1738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 1748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount++; 1758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (tmpCount != op.itemCount) { // all 1 effect 1788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOp(op); 17921b345f101abc385496f42d250e580d21f1287b6Dake Gu op = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_INVISIBLE) { 1824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchAndUpdateViewHolders(op); 1838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 1844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(op); 1858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void applyUpdate(UpdateOp op) { 1898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpStart = op.positionStart; 1908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpCount = 0; 1918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int tmpEnd = op.positionStart + op.itemCount; 1928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int type = -1; 1938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position = op.positionStart; position < tmpEnd; position++) { 1948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ViewHolder vh = mCallback.findViewHolder(position); 1951faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (vh != null || canFindInPreLayout(position)) { // deferred 1968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_INVISIBLE) { 19721b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, 19821b345f101abc385496f42d250e580d21f1287b6Dake Gu op.payload); 1994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchAndUpdateViewHolders(newOp); 2008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount = 0; 201e4fde6825bba479c9b030feb8f810694d46b2f06Yigit Boyar tmpStart = position; 2028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar type = POSITION_TYPE_NEW_OR_LAID_OUT; 2048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { // applied 2058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_NEW_OR_LAID_OUT) { 20621b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, 20721b345f101abc385496f42d250e580d21f1287b6Dake Gu op.payload); 2084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(newOp); 2098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount = 0; 210e4fde6825bba479c9b030feb8f810694d46b2f06Yigit Boyar tmpStart = position; 2118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar type = POSITION_TYPE_INVISIBLE; 2138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar tmpCount++; 2158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (tmpCount != op.itemCount) { // all 1 effect 21721b345f101abc385496f42d250e580d21f1287b6Dake Gu Object payload = op.payload; 2188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOp(op); 21921b345f101abc385496f42d250e580d21f1287b6Dake Gu op = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, payload); 2208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (type == POSITION_TYPE_INVISIBLE) { 2224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchAndUpdateViewHolders(op); 2238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 2244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(op); 2258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 2278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 2284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar private void dispatchAndUpdateViewHolders(UpdateOp op) { 2298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // tricky part. 2308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // traverse all postpones and revert their changes on this op if necessary, apply updated 2318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // dispatch to them since now they are after this op. 2321faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.cmd == UpdateOp.ADD || op.cmd == UpdateOp.MOVE) { 2331faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar throw new IllegalArgumentException("should not dispatch add or move for pre layout"); 2341faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2351faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar Log.d(TAG, "dispatch (pre)" + op); 2371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "postponed state before:"); 2381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (UpdateOp updateOp : mPostponedList) { 2391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, updateOp.toString()); 2401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "----"); 2421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 2441faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // handle each pos 1 by 1 to ensure continuity. If it breaks, dispatch partial 2454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar // TODO Since move ops are pushed to end, we should not need this anymore 2461faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar int tmpStart = updatePositionWithPostponed(op.positionStart, op.cmd); 2471faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2481faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "pos:" + op.positionStart + ",updatedPos:" + tmpStart); 2491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2501faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar int tmpCnt = 1; 2514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar int offsetPositionForPartial = op.positionStart; 2524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar final int positionMultiplier; 2534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar switch (op.cmd) { 2544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.UPDATE: 2554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar positionMultiplier = 1; 2564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 2574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.REMOVE: 2584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar positionMultiplier = 0; 2594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 2604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar default: 2614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar throw new IllegalArgumentException("op should be remove or update." + op); 2624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 2631faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (int p = 1; p < op.itemCount; p++) { 2644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar final int pos = op.positionStart + (positionMultiplier * p); 2651faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar int updatedPos = updatePositionWithPostponed(pos, op.cmd); 2661faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "pos:" + pos + ",updatedPos:" + updatedPos); 2681faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2691faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar boolean continuous = false; 2701faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar switch (op.cmd) { 2711faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case UpdateOp.UPDATE: 2721faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar continuous = updatedPos == tmpStart + 1; 2731faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar break; 2741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case UpdateOp.REMOVE: 2751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar continuous = updatedPos == tmpStart; 2761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar break; 2771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (continuous) { 2791faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar tmpCnt++; 2801faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else { 2811faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // need to dispatch this separately 28221b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, op.payload); 2831faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 2841faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "need to dispatch separately " + tmp); 2851faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial); 2871faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(tmp); 2884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar if (op.cmd == UpdateOp.UPDATE) { 2894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar offsetPositionForPartial += tmpCnt; 2904b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 2911faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar tmpStart = updatedPos;// need to remove previously dispatched 2921faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar tmpCnt = 1; 2931faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 2941faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 29521b345f101abc385496f42d250e580d21f1287b6Dake Gu Object payload = op.payload; 2961faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(op); 2971faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (tmpCnt > 0) { 29821b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, payload); 2991faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 3001faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "dispatching:" + tmp); 3011faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial); 3031faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(tmp); 3041faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3051faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 3061faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "post dispatch"); 3071faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "postponed state after:"); 3081faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (UpdateOp updateOp : mPostponedList) { 3091faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, updateOp.toString()); 3101faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3111faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "----"); 3121faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3131faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3141faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 3154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar void dispatchFirstPassAndUpdateViewHolders(UpdateOp op, int offsetStart) { 3164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.onDispatchFirstPass(op); 3174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar switch (op.cmd) { 3184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.REMOVE: 3194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.offsetPositionsForRemovingInvisible(offsetStart, op.itemCount); 3204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 3214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.UPDATE: 32221b345f101abc385496f42d250e580d21f1287b6Dake Gu mCallback.markViewHoldersUpdated(offsetStart, op.itemCount, op.payload); 3234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 3244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar default: 3254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar throw new IllegalArgumentException("only remove and update ops can be dispatched" 3264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar + " in first pass"); 3274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 3284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 3294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar 3301faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private int updatePositionWithPostponed(int pos, int cmd) { 3318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPostponedList.size(); 3328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = count - 1; i >= 0; i--) { 3338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp postponed = mPostponedList.get(i); 3341faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (postponed.cmd == UpdateOp.MOVE) { 3351faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar int start, end; 3361faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (postponed.positionStart < postponed.itemCount) { 3371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar start = postponed.positionStart; 3381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar end = postponed.itemCount; 3391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else { 3401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar start = postponed.itemCount; 3411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar end = postponed.positionStart; 3421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (pos >= start && pos <= end) { 3441faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar //i'm affected 3451faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (start == postponed.positionStart) { 3461faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (cmd == UpdateOp.ADD) { 3471faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.itemCount++; 3481faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (cmd == UpdateOp.REMOVE) { 3491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.itemCount--; 3501faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3511faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // op moved to left, move it right to revert 3521faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar pos++; 3531faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else { 3541faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (cmd == UpdateOp.ADD) { 3551faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart++; 3561faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (cmd == UpdateOp.REMOVE) { 3571faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart--; 3581faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3591faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // op was moved right, move left to revert 3601faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar pos--; 3611faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3621faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (pos < postponed.positionStart) { 3631faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // postponed MV is outside the dispatched OP. if it is before, offset 3641faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (cmd == UpdateOp.ADD) { 3651faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart++; 3661faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.itemCount++; 3671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (cmd == UpdateOp.REMOVE) { 3681faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart--; 3691faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.itemCount--; 3701faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3711faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 3731faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (postponed.positionStart <= pos) { 3741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (postponed.cmd == UpdateOp.ADD) { 3751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar pos -= postponed.itemCount; 3761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (postponed.cmd == UpdateOp.REMOVE) { 3771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar pos += postponed.itemCount; 3781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3791faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else { 3801faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (cmd == UpdateOp.ADD) { 3811faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart++; 3821faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (cmd == UpdateOp.REMOVE) { 3831faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar postponed.positionStart--; 3841faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3851faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3861faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3871faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 3881faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "dispath (step" + i + ")"); 3891faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "postponed state:" + i + ", pos:" + pos); 3901faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (UpdateOp updateOp : mPostponedList) { 3911faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, updateOp.toString()); 3921faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 3931faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "----"); 3948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 3958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 3961faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (int i = mPostponedList.size() - 1; i >= 0; i--) { 3971faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar UpdateOp op = mPostponedList.get(i); 3981faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.cmd == UpdateOp.MOVE) { 3991faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.itemCount == op.positionStart || op.itemCount < 0) { 4001faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar mPostponedList.remove(i); 4011faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(op); 4021faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4031faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (op.itemCount <= 0) { 4041faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar mPostponedList.remove(i); 4051faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar recycleUpdateOp(op); 4061faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4071faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4081faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return pos; 4098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4111faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar private boolean canFindInPreLayout(int position) { 4128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPostponedList.size(); 4138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 4148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mPostponedList.get(i); 4151faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.cmd == UpdateOp.MOVE) { 4164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar if (findPositionOffset(op.itemCount, i + 1) == position) { 4171faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return true; 4181faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4191faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (op.cmd == UpdateOp.ADD) { 4201faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // TODO optimize. 4211faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar final int end = op.positionStart + op.itemCount; 4221faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar for (int pos = op.positionStart; pos < end; pos++) { 4231faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (findPositionOffset(pos, i + 1) == position) { 4241faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return true; 4251faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4261faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 4308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void applyAdd(UpdateOp op) { 4334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar postponeAndUpdateViewHolders(op); 4348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar private void postponeAndUpdateViewHolders(UpdateOp op) { 4371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (DEBUG) { 4381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar Log.d(TAG, "postponing " + op); 4391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mPostponedList.add(op); 4414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar switch (op.cmd) { 4424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.ADD: 4434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount); 4444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 4454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.MOVE: 4464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.offsetPositionsForMove(op.positionStart, op.itemCount); 4474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 4484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.REMOVE: 4494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar mCallback.offsetPositionsForRemovingLaidOutOrNewView(op.positionStart, 4504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar op.itemCount); 4514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 4524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar case UpdateOp.UPDATE: 45321b345f101abc385496f42d250e580d21f1287b6Dake Gu mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload); 4544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar break; 4554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar default: 4564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar throw new IllegalArgumentException("Unknown update op type for " + op); 4574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 4588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar boolean hasPendingUpdates() { 4618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mPendingUpdates.size() > 0; 4628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 464121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar boolean hasAnyUpdateTypes(int updateTypes) { 465121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar return (mExistingUpdateTypes & updateTypes) != 0; 466121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 467121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 4688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int findPositionOffset(int position) { 4698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return findPositionOffset(position, 0); 4708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 472668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int findPositionOffset(int position, int firstPostponedItem) { 4738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int count = mPostponedList.size(); 474668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (int i = firstPostponedItem; i < count; ++i) { 4758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mPostponedList.get(i); 4761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.cmd == UpdateOp.MOVE) { 4771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (op.positionStart == position) { 4781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar position = op.itemCount; 4794bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar } else { 4804bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar if (op.positionStart < position) { 4814bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar position--; // like a remove 4824bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar } 4834bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar if (op.itemCount <= position) { 4844bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar position++; // like an add 4854bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar } 4861faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 4871faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } else if (op.positionStart <= position) { 4888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (op.cmd == UpdateOp.REMOVE) { 4894bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar if (position < op.positionStart + op.itemCount) { 4904bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar return -1; 4914bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar } 4921faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar position -= op.itemCount; 4938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else if (op.cmd == UpdateOp.ADD) { 4941faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar position += op.itemCount; 4958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4981faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return position; 4998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 5028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * @return True if updates should be processed. 5038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 50421b345f101abc385496f42d250e580d21f1287b6Dake Gu boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) { 5058fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar if (itemCount < 1) { 5068fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar return false; 5078fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 50821b345f101abc385496f42d250e580d21f1287b6Dake Gu mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload)); 509121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes |= UpdateOp.UPDATE; 5108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mPendingUpdates.size() == 1; 5118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 5148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * @return True if updates should be processed. 5158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 5168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar boolean onItemRangeInserted(int positionStart, int itemCount) { 5178fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar if (itemCount < 1) { 5188fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar return false; 5198fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 52021b345f101abc385496f42d250e580d21f1287b6Dake Gu mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null)); 521121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes |= UpdateOp.ADD; 5228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mPendingUpdates.size() == 1; 5238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 5268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * @return True if updates should be processed. 5278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 5288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar boolean onItemRangeRemoved(int positionStart, int itemCount) { 5298fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar if (itemCount < 1) { 5308fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar return false; 5318fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 53221b345f101abc385496f42d250e580d21f1287b6Dake Gu mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null)); 533121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes |= UpdateOp.REMOVE; 5348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mPendingUpdates.size() == 1; 5358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 5381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar * @return True if updates should be processed. 5391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar */ 5401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar boolean onItemRangeMoved(int from, int to, int itemCount) { 5411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (from == to) { 5424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar return false; // no-op 5431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 5441faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar if (itemCount != 1) { 5451faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar throw new IllegalArgumentException("Moving more than 1 item is not supported yet"); 5461faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 54721b345f101abc385496f42d250e580d21f1287b6Dake Gu mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null)); 548121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes |= UpdateOp.MOVE; 5491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return mPendingUpdates.size() == 1; 5501faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar } 5511faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 5521faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar /** 5538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Skips pre-processing and applies all updates in one pass. 5548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 5558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void consumeUpdatesInOnePass() { 5568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // we still consume postponed updates (if there is) in case there was a pre-process call 5578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // w/o a matching consumePostponedUpdates. 5588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar consumePostponedUpdates(); 5598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = mPendingUpdates.size(); 5608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 5618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mPendingUpdates.get(i); 5628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar switch (op.cmd) { 5638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.ADD: 5648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mCallback.onDispatchSecondPass(op); 56516e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount); 5668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 5678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.REMOVE: 5688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mCallback.onDispatchSecondPass(op); 56916e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar mCallback.offsetPositionsForRemovingInvisible(op.positionStart, op.itemCount); 5708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 5718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UpdateOp.UPDATE: 57216e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar mCallback.onDispatchSecondPass(op); 57321b345f101abc385496f42d250e580d21f1287b6Dake Gu mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload); 5748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar break; 5751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case UpdateOp.MOVE: 57616e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar mCallback.onDispatchSecondPass(op); 5771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar mCallback.offsetPositionsForMove(op.positionStart, op.itemCount); 5781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar break; 5798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mOnItemProcessedCallback != null) { 5818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mOnItemProcessedCallback.run(); 5828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOpsAndClearList(mPendingUpdates); 585121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mExistingUpdateTypes = 0; 5868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 588115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public int applyPendingUpdatesToPosition(int position) { 589115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int size = mPendingUpdates.size(); 590115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar for (int i = 0; i < size; i ++) { 591115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar UpdateOp op = mPendingUpdates.get(i); 592115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar switch (op.cmd) { 593115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar case UpdateOp.ADD: 594115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.positionStart <= position) { 595115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position += op.itemCount; 596115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 597115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar break; 598115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar case UpdateOp.REMOVE: 599115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.positionStart <= position) { 600115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int end = op.positionStart + op.itemCount; 601115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (end > position) { 602115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar return RecyclerView.NO_POSITION; 603115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 604115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position -= op.itemCount; 605115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 606115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar break; 607115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar case UpdateOp.MOVE: 608115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.positionStart == position) { 609115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position = op.itemCount;//position end 610115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } else { 611115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.positionStart < position) { 612115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position -= 1; 613115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 614115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (op.itemCount <= position) { 615115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar position += 1; 616115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 617115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 618115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar break; 619115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 620115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 621115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar return position; 622115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 623115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 6244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar boolean hasUpdates() { 6254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty(); 6264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 6274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 6288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 6298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Queued operation to happen when child views are updated. 6308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 6318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static class UpdateOp { 6328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 633121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar static final int ADD = 1; 6348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 635121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar static final int REMOVE = 1 << 1; 6368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 637121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar static final int UPDATE = 1 << 2; 6388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 639121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar static final int MOVE = 1 << 3; 6401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 6418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static final int POOL_SIZE = 30; 6428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int cmd; 6448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int positionStart; 6468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 64721b345f101abc385496f42d250e580d21f1287b6Dake Gu Object payload; 64821b345f101abc385496f42d250e580d21f1287b6Dake Gu 6491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar // holds the target position if this is a MOVE 6508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int itemCount; 6518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 65221b345f101abc385496f42d250e580d21f1287b6Dake Gu UpdateOp(int cmd, int positionStart, int itemCount, Object payload) { 6538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar this.cmd = cmd; 6548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar this.positionStart = positionStart; 6558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar this.itemCount = itemCount; 65621b345f101abc385496f42d250e580d21f1287b6Dake Gu this.payload = payload; 6578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar String cmdToString() { 6608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar switch (cmd) { 6618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case ADD: 6628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "add"; 6638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case REMOVE: 6648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "rm"; 6658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar case UPDATE: 6668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "up"; 6671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar case MOVE: 6681faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar return "mv"; 6698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "??"; 6718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 6748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public String toString() { 67521b345f101abc385496f42d250e580d21f1287b6Dake Gu return Integer.toHexString(System.identityHashCode(this)) 67621b345f101abc385496f42d250e580d21f1287b6Dake Gu + "[" + cmdToString() + ",s:" + positionStart + "c:" + itemCount 67721b345f101abc385496f42d250e580d21f1287b6Dake Gu +",p:"+payload + "]"; 6788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 6818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public boolean equals(Object o) { 6828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (this == o) { 6838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return true; 6848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (o == null || getClass() != o.getClass()) { 6868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 6878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = (UpdateOp) o; 6908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (cmd != op.cmd) { 6928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 6938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar if (cmd == MOVE && Math.abs(itemCount - positionStart) == 1) { 6954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar // reverse of this is also true 6964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar if (itemCount == op.positionStart && positionStart == op.itemCount) { 6974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar return true; 6984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 6994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar } 7008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (itemCount != op.itemCount) { 7018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 7028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (positionStart != op.positionStart) { 7048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return false; 7058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 70621b345f101abc385496f42d250e580d21f1287b6Dake Gu if (payload != null) { 70721b345f101abc385496f42d250e580d21f1287b6Dake Gu if (!payload.equals(op.payload)) { 70821b345f101abc385496f42d250e580d21f1287b6Dake Gu return false; 70921b345f101abc385496f42d250e580d21f1287b6Dake Gu } 71021b345f101abc385496f42d250e580d21f1287b6Dake Gu } else if (op.payload != null) { 71121b345f101abc385496f42d250e580d21f1287b6Dake Gu return false; 71221b345f101abc385496f42d250e580d21f1287b6Dake Gu } 7138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return true; 7158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 7188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public int hashCode() { 7198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int result = cmd; 7208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar result = 31 * result + positionStart; 7218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar result = 31 * result + itemCount; 7228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return result; 7238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar @Override 72721b345f101abc385496f42d250e580d21f1287b6Dake Gu public UpdateOp obtainUpdateOp(int cmd, int positionStart, int itemCount, Object payload) { 7288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar UpdateOp op = mUpdateOpPool.acquire(); 7298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (op == null) { 73021b345f101abc385496f42d250e580d21f1287b6Dake Gu op = new UpdateOp(cmd, positionStart, itemCount, payload); 7318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 7328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar op.cmd = cmd; 7338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar op.positionStart = positionStart; 7348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar op.itemCount = itemCount; 73521b345f101abc385496f42d250e580d21f1287b6Dake Gu op.payload = payload; 7368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return op; 7388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar @Override 7414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar public void recycleUpdateOp(UpdateOp op) { 7428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (!mDisableRecycler) { 74321b345f101abc385496f42d250e580d21f1287b6Dake Gu op.payload = null; 7448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mUpdateOpPool.release(op); 7458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void recycleUpdateOpsAndClearList(List<UpdateOp> ops) { 7498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int count = ops.size(); 7508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < count; i++) { 7518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar recycleUpdateOp(ops.get(i)); 7528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ops.clear(); 7548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar /** 7578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Contract between AdapterHelper and RecyclerView. 7588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */ 7598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static interface Callback { 7608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ViewHolder findViewHolder(int position); 7628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void offsetPositionsForRemovingInvisible(int positionStart, int itemCount); 7648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount); 7668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 76721b345f101abc385496f42d250e580d21f1287b6Dake Gu void markViewHoldersUpdated(int positionStart, int itemCount, Object payloads); 7688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onDispatchFirstPass(UpdateOp updateOp); 7708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onDispatchSecondPass(UpdateOp updateOp); 7728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void offsetPositionsForAdd(int positionStart, int itemCount); 7741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar 7751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar void offsetPositionsForMove(int from, int to); 7768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7774bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar} 778