17149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas/* 27149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * Copyright (C) 2017 The Android Open Source Project 37149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * 47149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * Licensed under the Apache License, Version 2.0 (the "License"); 57149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * you may not use this file except in compliance with the License. 67149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * You may obtain a copy of the License at 77149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * 87149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * http://www.apache.org/licenses/LICENSE-2.0 97149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * 107149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * Unless required by applicable law or agreed to in writing, software 117149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * distributed under the License is distributed on an "AS IS" BASIS, 127149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * See the License for the specific language governing permissions and 147149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * limitations under the License. 157149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 167149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 177149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikaspackage com.android.internal.widget; 187149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 197149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikasimport android.util.Log; 207149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikasimport android.util.Pools; 217149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 227149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikasimport java.util.ArrayList; 237149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikasimport java.util.Collections; 247149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikasimport java.util.List; 257149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 267149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas/** 277149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * Helper class that can enqueue and process adapter update operations. 287149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * <p> 297149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * To support animations, RecyclerView presents an older version the Adapter to best represent 307149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * previous state of the layout. Sometimes, this is not trivial when items are removed that were 317149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * not laid out, in which case, RecyclerView has no way of providing that item's view for 327149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * animations. 337149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * <p> 347149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * AdapterHelper creates an UpdateOp for each adapter data change then pre-processes them. During 357149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * pre processing, AdapterHelper finds out which UpdateOps can be deferred to second layout pass 367149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * and which cannot. For the UpdateOps that cannot be deferred, AdapterHelper will change them 377149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * according to previously deferred operation and dispatch them before the first layout pass. It 387149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * also takes care of updating deferred UpdateOps since order of operations is changed by this 397149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * process. 407149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * <p> 417149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * Although operations may be forwarded to LayoutManager in different orders, resulting data set 427149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * is guaranteed to be the consistent. 437149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 447149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikasclass AdapterHelper implements OpReorderer.Callback { 457149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 467149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas static final int POSITION_TYPE_INVISIBLE = 0; 477149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 487149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas static final int POSITION_TYPE_NEW_OR_LAID_OUT = 1; 497149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 507149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private static final boolean DEBUG = false; 517149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 527149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private static final String TAG = "AHT"; 537149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 547149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private Pools.Pool<UpdateOp> mUpdateOpPool = new Pools.SimplePool<UpdateOp>(UpdateOp.POOL_SIZE); 557149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 567149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>(); 577149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 587149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final ArrayList<UpdateOp> mPostponedList = new ArrayList<UpdateOp>(); 597149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 607149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final Callback mCallback; 617149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 627149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Runnable mOnItemProcessedCallback; 637149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 647149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final boolean mDisableRecycler; 657149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 667149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final OpReorderer mOpReorderer; 677149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 687149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private int mExistingUpdateTypes = 0; 697149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 707149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas AdapterHelper(Callback callback) { 717149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas this(callback, false); 727149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 737149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 747149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas AdapterHelper(Callback callback, boolean disableRecycler) { 757149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback = callback; 767149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mDisableRecycler = disableRecycler; 777149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mOpReorderer = new OpReorderer(this); 787149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 797149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 807149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas AdapterHelper addUpdateOp(UpdateOp... ops) { 817149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Collections.addAll(mPendingUpdates, ops); 827149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return this; 837149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 847149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 857149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void reset() { 867149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOpsAndClearList(mPendingUpdates); 877149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOpsAndClearList(mPostponedList); 887149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mExistingUpdateTypes = 0; 897149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 907149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 917149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void preProcess() { 927149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mOpReorderer.reorderOps(mPendingUpdates); 937149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int count = mPendingUpdates.size(); 947149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = 0; i < count; i++) { 957149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp op = mPendingUpdates.get(i); 967149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas switch (op.cmd) { 977149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.ADD: 987149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas applyAdd(op); 997149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 1007149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.REMOVE: 1017149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas applyRemove(op); 1027149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 1037149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.UPDATE: 1047149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas applyUpdate(op); 1057149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 1067149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.MOVE: 1077149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas applyMove(op); 1087149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 1097149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1107149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (mOnItemProcessedCallback != null) { 1117149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mOnItemProcessedCallback.run(); 1127149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1137149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1147149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mPendingUpdates.clear(); 1157149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1167149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 1177149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void consumePostponedUpdates() { 1187149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int count = mPostponedList.size(); 1197149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = 0; i < count; i++) { 1207149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.onDispatchSecondPass(mPostponedList.get(i)); 1217149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1227149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOpsAndClearList(mPostponedList); 1237149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mExistingUpdateTypes = 0; 1247149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1257149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 1267149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private void applyMove(UpdateOp op) { 1277149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // MOVE ops are pre-processed so at this point, we know that item is still in the adapter. 1287149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // otherwise, it would be converted into a REMOVE operation 1297149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponeAndUpdateViewHolders(op); 1307149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1317149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 1327149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private void applyRemove(UpdateOp op) { 1337149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int tmpStart = op.positionStart; 1347149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int tmpCount = 0; 1357149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int tmpEnd = op.positionStart + op.itemCount; 1367149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int type = -1; 1377149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int position = op.positionStart; position < tmpEnd; position++) { 1387149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean typeChanged = false; 1397149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas RecyclerView.ViewHolder vh = mCallback.findViewHolder(position); 1407149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (vh != null || canFindInPreLayout(position)) { 1417149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // If a ViewHolder exists or this is a newly added item, we can defer this update 1427149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // to post layout stage. 1437149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // * For existing ViewHolders, we'll fake its existence in the pre-layout phase. 1447149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // * For items that are added and removed in the same process cycle, they won't 1457149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // have any effect in pre-layout since their add ops are already deferred to 1467149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // post-layout pass. 1477149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (type == POSITION_TYPE_INVISIBLE) { 1487149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // Looks like we have other updates that we cannot merge with this one. 1497149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // Create an UpdateOp and dispatch it to LayoutManager. 1507149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1517149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas dispatchAndUpdateViewHolders(newOp); 1527149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas typeChanged = true; 1537149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1547149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas type = POSITION_TYPE_NEW_OR_LAID_OUT; 1557149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 1567149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // This update cannot be recovered because we don't have a ViewHolder representing 1577149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // this position. Instead, post it to LayoutManager immediately 1587149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (type == POSITION_TYPE_NEW_OR_LAID_OUT) { 1597149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // Looks like we have other updates that we cannot merge with this one. 1607149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // Create UpdateOp op and dispatch it to LayoutManager. 1617149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1627149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponeAndUpdateViewHolders(newOp); 1637149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas typeChanged = true; 1647149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1657149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas type = POSITION_TYPE_INVISIBLE; 1667149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1677149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (typeChanged) { 1687149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position -= tmpCount; // also equal to tmpStart 1697149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpEnd -= tmpCount; 1707149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpCount = 1; 1717149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 1727149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpCount++; 1737149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1747149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1757149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (tmpCount != op.itemCount) { // all 1 effect 1767149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOp(op); 1777149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); 1787149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1797149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (type == POSITION_TYPE_INVISIBLE) { 1807149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas dispatchAndUpdateViewHolders(op); 1817149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 1827149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponeAndUpdateViewHolders(op); 1837149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1847149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 1857149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 1867149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private void applyUpdate(UpdateOp op) { 1877149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int tmpStart = op.positionStart; 1887149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int tmpCount = 0; 1897149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int tmpEnd = op.positionStart + op.itemCount; 1907149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int type = -1; 1917149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int position = op.positionStart; position < tmpEnd; position++) { 1927149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas RecyclerView.ViewHolder vh = mCallback.findViewHolder(position); 1937149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (vh != null || canFindInPreLayout(position)) { // deferred 1947149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (type == POSITION_TYPE_INVISIBLE) { 1957149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, 1967149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op.payload); 1977149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas dispatchAndUpdateViewHolders(newOp); 1987149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpCount = 0; 1997149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpStart = position; 2007149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2017149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas type = POSITION_TYPE_NEW_OR_LAID_OUT; 2027149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { // applied 2037149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (type == POSITION_TYPE_NEW_OR_LAID_OUT) { 2047149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, 2057149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op.payload); 2067149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponeAndUpdateViewHolders(newOp); 2077149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpCount = 0; 2087149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpStart = position; 2097149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2107149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas type = POSITION_TYPE_INVISIBLE; 2117149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2127149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpCount++; 2137149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2147149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (tmpCount != op.itemCount) { // all 1 effect 2157149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Object payload = op.payload; 2167149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOp(op); 2177149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, payload); 2187149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2197149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (type == POSITION_TYPE_INVISIBLE) { 2207149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas dispatchAndUpdateViewHolders(op); 2217149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 2227149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponeAndUpdateViewHolders(op); 2237149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2247149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2257149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 2267149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private void dispatchAndUpdateViewHolders(UpdateOp op) { 2277149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // tricky part. 2287149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // traverse all postpones and revert their changes on this op if necessary, apply updated 2297149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // dispatch to them since now they are after this op. 2307149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.cmd == UpdateOp.ADD || op.cmd == UpdateOp.MOVE) { 2317149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas throw new IllegalArgumentException("should not dispatch add or move for pre layout"); 2327149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2337149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (DEBUG) { 2347149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "dispatch (pre)" + op); 2357149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "postponed state before:"); 2367149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (UpdateOp updateOp : mPostponedList) { 2377149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, updateOp.toString()); 2387149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2397149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "----"); 2407149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2417149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 2427149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // handle each pos 1 by 1 to ensure continuity. If it breaks, dispatch partial 2437149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // TODO Since move ops are pushed to end, we should not need this anymore 2447149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int tmpStart = updatePositionWithPostponed(op.positionStart, op.cmd); 2457149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (DEBUG) { 2467149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "pos:" + op.positionStart + ",updatedPos:" + tmpStart); 2477149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2487149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int tmpCnt = 1; 2497149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int offsetPositionForPartial = op.positionStart; 2507149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int positionMultiplier; 2517149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas switch (op.cmd) { 2527149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.UPDATE: 2537149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas positionMultiplier = 1; 2547149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 2557149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.REMOVE: 2567149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas positionMultiplier = 0; 2577149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 2587149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas default: 2597149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas throw new IllegalArgumentException("op should be remove or update." + op); 2607149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2617149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int p = 1; p < op.itemCount; p++) { 2627149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int pos = op.positionStart + (positionMultiplier * p); 2637149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int updatedPos = updatePositionWithPostponed(pos, op.cmd); 2647149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (DEBUG) { 2657149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "pos:" + pos + ",updatedPos:" + updatedPos); 2667149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2677149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean continuous = false; 2687149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas switch (op.cmd) { 2697149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.UPDATE: 2707149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas continuous = updatedPos == tmpStart + 1; 2717149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 2727149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.REMOVE: 2737149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas continuous = updatedPos == tmpStart; 2747149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 2757149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2767149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (continuous) { 2777149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpCnt++; 2787149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 2797149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // need to dispatch this separately 2807149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, op.payload); 2817149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (DEBUG) { 2827149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "need to dispatch separately " + tmp); 2837149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2847149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial); 2857149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOp(tmp); 2867149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.cmd == UpdateOp.UPDATE) { 2877149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas offsetPositionForPartial += tmpCnt; 2887149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2897149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpStart = updatedPos; // need to remove previously dispatched 2907149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas tmpCnt = 1; 2917149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2927149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 2937149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Object payload = op.payload; 2947149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOp(op); 2957149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (tmpCnt > 0) { 2967149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, payload); 2977149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (DEBUG) { 2987149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "dispatching:" + tmp); 2997149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3007149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial); 3017149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOp(tmp); 3027149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3037149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (DEBUG) { 3047149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "post dispatch"); 3057149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "postponed state after:"); 3067149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (UpdateOp updateOp : mPostponedList) { 3077149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, updateOp.toString()); 3087149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3097149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "----"); 3107149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3117149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3127149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 3137149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void dispatchFirstPassAndUpdateViewHolders(UpdateOp op, int offsetStart) { 3147149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.onDispatchFirstPass(op); 3157149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas switch (op.cmd) { 3167149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.REMOVE: 3177149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.offsetPositionsForRemovingInvisible(offsetStart, op.itemCount); 3187149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 3197149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.UPDATE: 3207149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.markViewHoldersUpdated(offsetStart, op.itemCount, op.payload); 3217149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 3227149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas default: 3237149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas throw new IllegalArgumentException("only remove and update ops can be dispatched" 3247149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas + " in first pass"); 3257149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3267149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3277149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 3287149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private int updatePositionWithPostponed(int pos, int cmd) { 3297149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int count = mPostponedList.size(); 3307149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = count - 1; i >= 0; i--) { 3317149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp postponed = mPostponedList.get(i); 3327149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (postponed.cmd == UpdateOp.MOVE) { 3337149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int start, end; 3347149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (postponed.positionStart < postponed.itemCount) { 3357149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas start = postponed.positionStart; 3367149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas end = postponed.itemCount; 3377149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 3387149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas start = postponed.itemCount; 3397149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas end = postponed.positionStart; 3407149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3417149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (pos >= start && pos <= end) { 3427149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas //i'm affected 3437149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (start == postponed.positionStart) { 3447149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (cmd == UpdateOp.ADD) { 3457149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.itemCount++; 3467149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (cmd == UpdateOp.REMOVE) { 3477149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.itemCount--; 3487149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3497149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // op moved to left, move it right to revert 3507149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas pos++; 3517149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 3527149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (cmd == UpdateOp.ADD) { 3537149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.positionStart++; 3547149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (cmd == UpdateOp.REMOVE) { 3557149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.positionStart--; 3567149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3577149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // op was moved right, move left to revert 3587149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas pos--; 3597149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3607149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (pos < postponed.positionStart) { 3617149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // postponed MV is outside the dispatched OP. if it is before, offset 3627149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (cmd == UpdateOp.ADD) { 3637149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.positionStart++; 3647149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.itemCount++; 3657149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (cmd == UpdateOp.REMOVE) { 3667149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.positionStart--; 3677149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.itemCount--; 3687149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3697149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3707149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 3717149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (postponed.positionStart <= pos) { 3727149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (postponed.cmd == UpdateOp.ADD) { 3737149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas pos -= postponed.itemCount; 3747149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (postponed.cmd == UpdateOp.REMOVE) { 3757149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas pos += postponed.itemCount; 3767149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3777149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 3787149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (cmd == UpdateOp.ADD) { 3797149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.positionStart++; 3807149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (cmd == UpdateOp.REMOVE) { 3817149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponed.positionStart--; 3827149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3837149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3847149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3857149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (DEBUG) { 3867149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "dispath (step" + i + ")"); 3877149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "postponed state:" + i + ", pos:" + pos); 3887149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (UpdateOp updateOp : mPostponedList) { 3897149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, updateOp.toString()); 3907149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3917149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "----"); 3927149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3937149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 3947149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = mPostponedList.size() - 1; i >= 0; i--) { 3957149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp op = mPostponedList.get(i); 3967149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.cmd == UpdateOp.MOVE) { 3977149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.itemCount == op.positionStart || op.itemCount < 0) { 3987149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mPostponedList.remove(i); 3997149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOp(op); 4007149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4017149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (op.itemCount <= 0) { 4027149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mPostponedList.remove(i); 4037149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOp(op); 4047149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4057149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4067149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return pos; 4077149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4087149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 4097149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private boolean canFindInPreLayout(int position) { 4107149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int count = mPostponedList.size(); 4117149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = 0; i < count; i++) { 4127149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp op = mPostponedList.get(i); 4137149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.cmd == UpdateOp.MOVE) { 4147149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (findPositionOffset(op.itemCount, i + 1) == position) { 4157149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return true; 4167149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4177149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (op.cmd == UpdateOp.ADD) { 4187149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // TODO optimize. 4197149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int end = op.positionStart + op.itemCount; 4207149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int pos = op.positionStart; pos < end; pos++) { 4217149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (findPositionOffset(pos, i + 1) == position) { 4227149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return true; 4237149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4247149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4257149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4267149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4277149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 4287149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4297149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 4307149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private void applyAdd(UpdateOp op) { 4317149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas postponeAndUpdateViewHolders(op); 4327149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4337149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 4347149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas private void postponeAndUpdateViewHolders(UpdateOp op) { 4357149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (DEBUG) { 4367149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Log.d(TAG, "postponing " + op); 4377149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4387149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mPostponedList.add(op); 4397149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas switch (op.cmd) { 4407149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.ADD: 4417149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount); 4427149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 4437149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.MOVE: 4447149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.offsetPositionsForMove(op.positionStart, op.itemCount); 4457149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 4467149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.REMOVE: 4477149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.offsetPositionsForRemovingLaidOutOrNewView(op.positionStart, 4487149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op.itemCount); 4497149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 4507149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.UPDATE: 4517149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload); 4527149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 4537149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas default: 4547149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas throw new IllegalArgumentException("Unknown update op type for " + op); 4557149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4567149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4577149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 4587149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean hasPendingUpdates() { 4597149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return mPendingUpdates.size() > 0; 4607149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4617149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 4627149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean hasAnyUpdateTypes(int updateTypes) { 4637149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return (mExistingUpdateTypes & updateTypes) != 0; 4647149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4657149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 4667149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int findPositionOffset(int position) { 4677149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return findPositionOffset(position, 0); 4687149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4697149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 4707149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int findPositionOffset(int position, int firstPostponedItem) { 4717149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int count = mPostponedList.size(); 4727149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = firstPostponedItem; i < count; ++i) { 4737149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp op = mPostponedList.get(i); 4747149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.cmd == UpdateOp.MOVE) { 4757149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.positionStart == position) { 4767149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position = op.itemCount; 4777149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 4787149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.positionStart < position) { 4797149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position--; // like a remove 4807149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4817149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.itemCount <= position) { 4827149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position++; // like an add 4837149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4847149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4857149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (op.positionStart <= position) { 4867149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.cmd == UpdateOp.REMOVE) { 4877149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (position < op.positionStart + op.itemCount) { 4887149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return -1; 4897149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4907149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position -= op.itemCount; 4917149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (op.cmd == UpdateOp.ADD) { 4927149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position += op.itemCount; 4937149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4947149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4957149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4967149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return position; 4977149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 4987149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 4997149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas /** 5007149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * @return True if updates should be processed. 5017149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 5027149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) { 5037149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (itemCount < 1) { 5047149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 5057149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5067149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload)); 5077149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mExistingUpdateTypes |= UpdateOp.UPDATE; 5087149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return mPendingUpdates.size() == 1; 5097149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5107149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 5117149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas /** 5127149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * @return True if updates should be processed. 5137149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 5147149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean onItemRangeInserted(int positionStart, int itemCount) { 5157149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (itemCount < 1) { 5167149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 5177149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5187149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null)); 5197149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mExistingUpdateTypes |= UpdateOp.ADD; 5207149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return mPendingUpdates.size() == 1; 5217149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5227149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 5237149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas /** 5247149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * @return True if updates should be processed. 5257149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 5267149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean onItemRangeRemoved(int positionStart, int itemCount) { 5277149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (itemCount < 1) { 5287149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 5297149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5307149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null)); 5317149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mExistingUpdateTypes |= UpdateOp.REMOVE; 5327149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return mPendingUpdates.size() == 1; 5337149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5347149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 5357149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas /** 5367149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * @return True if updates should be processed. 5377149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 5387149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean onItemRangeMoved(int from, int to, int itemCount) { 5397149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (from == to) { 5407149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; // no-op 5417149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5427149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (itemCount != 1) { 5437149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas throw new IllegalArgumentException("Moving more than 1 item is not supported yet"); 5447149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5457149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null)); 5467149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mExistingUpdateTypes |= UpdateOp.MOVE; 5477149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return mPendingUpdates.size() == 1; 5487149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5497149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 5507149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas /** 5517149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * Skips pre-processing and applies all updates in one pass. 5527149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 5537149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void consumeUpdatesInOnePass() { 5547149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // we still consume postponed updates (if there is) in case there was a pre-process call 5557149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // w/o a matching consumePostponedUpdates. 5567149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas consumePostponedUpdates(); 5577149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int count = mPendingUpdates.size(); 5587149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = 0; i < count; i++) { 5597149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp op = mPendingUpdates.get(i); 5607149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas switch (op.cmd) { 5617149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.ADD: 5627149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.onDispatchSecondPass(op); 5637149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount); 5647149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 5657149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.REMOVE: 5667149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.onDispatchSecondPass(op); 5677149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.offsetPositionsForRemovingInvisible(op.positionStart, op.itemCount); 5687149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 5697149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.UPDATE: 5707149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.onDispatchSecondPass(op); 5717149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload); 5727149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 5737149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.MOVE: 5747149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.onDispatchSecondPass(op); 5757149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mCallback.offsetPositionsForMove(op.positionStart, op.itemCount); 5767149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 5777149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5787149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (mOnItemProcessedCallback != null) { 5797149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mOnItemProcessedCallback.run(); 5807149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5817149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5827149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOpsAndClearList(mPendingUpdates); 5837149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mExistingUpdateTypes = 0; 5847149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5857149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 5867149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas public int applyPendingUpdatesToPosition(int position) { 5877149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int size = mPendingUpdates.size(); 5887149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = 0; i < size; i++) { 5897149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp op = mPendingUpdates.get(i); 5907149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas switch (op.cmd) { 5917149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.ADD: 5927149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.positionStart <= position) { 5937149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position += op.itemCount; 5947149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 5957149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 5967149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.REMOVE: 5977149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.positionStart <= position) { 5987149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int end = op.positionStart + op.itemCount; 5997149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (end > position) { 6007149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return RecyclerView.NO_POSITION; 6017149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6027149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position -= op.itemCount; 6037149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6047149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 6057149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UpdateOp.MOVE: 6067149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.positionStart == position) { 6077149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position = op.itemCount; //position end 6087149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 6097149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.positionStart < position) { 6107149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position -= 1; 6117149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6127149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op.itemCount <= position) { 6137149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas position += 1; 6147149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6157149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6167149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas break; 6177149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6187149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6197149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return position; 6207149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6217149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6227149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas boolean hasUpdates() { 6237149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty(); 6247149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6257149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6267149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas /** 6277149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * Queued operation to happen when child views are updated. 6287149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 6297149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas static class UpdateOp { 6307149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6317149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas static final int ADD = 1; 6327149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6337149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas static final int REMOVE = 1 << 1; 6347149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6357149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas static final int UPDATE = 1 << 2; 6367149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6377149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas static final int MOVE = 1 << 3; 6387149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6397149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas static final int POOL_SIZE = 30; 6407149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6417149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int cmd; 6427149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6437149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int positionStart; 6447149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6457149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas Object payload; 6467149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6477149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // holds the target position if this is a MOVE 6487149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int itemCount; 6497149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6507149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp(int cmd, int positionStart, int itemCount, Object payload) { 6517149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas this.cmd = cmd; 6527149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas this.positionStart = positionStart; 6537149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas this.itemCount = itemCount; 6547149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas this.payload = payload; 6557149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6567149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6577149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas String cmdToString() { 6587149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas switch (cmd) { 6597149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case ADD: 6607149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return "add"; 6617149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case REMOVE: 6627149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return "rm"; 6637149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case UPDATE: 6647149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return "up"; 6657149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas case MOVE: 6667149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return "mv"; 6677149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6687149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return "??"; 6697149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6707149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6717149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas @Override 6727149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas public String toString() { 6737149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return Integer.toHexString(System.identityHashCode(this)) 6747149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas + "[" + cmdToString() + ",s:" + positionStart + "c:" + itemCount 6757149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas + ",p:" + payload + "]"; 6767149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6777149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6787149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas @Override 6797149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas public boolean equals(Object o) { 6807149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (this == o) { 6817149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return true; 6827149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6837149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (o == null || getClass() != o.getClass()) { 6847149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 6857149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6867149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6877149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp op = (UpdateOp) o; 6887149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 6897149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (cmd != op.cmd) { 6907149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 6917149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6927149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (cmd == MOVE && Math.abs(itemCount - positionStart) == 1) { 6937149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas // reverse of this is also true 6947149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (itemCount == op.positionStart && positionStart == op.itemCount) { 6957149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return true; 6967149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6977149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 6987149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (itemCount != op.itemCount) { 6997149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 7007149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7017149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (positionStart != op.positionStart) { 7027149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 7037149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7047149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (payload != null) { 7057149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (!payload.equals(op.payload)) { 7067149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 7077149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7087149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else if (op.payload != null) { 7097149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return false; 7107149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7117149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7127149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return true; 7137149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7147149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7157149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas @Override 7167149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas public int hashCode() { 7177149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas int result = cmd; 7187149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas result = 31 * result + positionStart; 7197149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas result = 31 * result + itemCount; 7207149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return result; 7217149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7227149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7237149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7247149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas @Override 7257149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas public UpdateOp obtainUpdateOp(int cmd, int positionStart, int itemCount, Object payload) { 7267149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas UpdateOp op = mUpdateOpPool.acquire(); 7277149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (op == null) { 7287149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op = new UpdateOp(cmd, positionStart, itemCount, payload); 7297149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } else { 7307149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op.cmd = cmd; 7317149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op.positionStart = positionStart; 7327149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op.itemCount = itemCount; 7337149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op.payload = payload; 7347149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7357149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas return op; 7367149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7377149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7387149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas @Override 7397149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas public void recycleUpdateOp(UpdateOp op) { 7407149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas if (!mDisableRecycler) { 7417149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas op.payload = null; 7427149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas mUpdateOpPool.release(op); 7437149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7447149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7457149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7467149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void recycleUpdateOpsAndClearList(List<UpdateOp> ops) { 7477149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas final int count = ops.size(); 7487149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas for (int i = 0; i < count; i++) { 7497149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas recycleUpdateOp(ops.get(i)); 7507149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7517149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas ops.clear(); 7527149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7537149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7547149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas /** 7557149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas * Contract between AdapterHelper and RecyclerView. 7567149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas */ 7577149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas interface Callback { 7587149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7597149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas RecyclerView.ViewHolder findViewHolder(int position); 7607149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7617149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void offsetPositionsForRemovingInvisible(int positionStart, int itemCount); 7627149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7637149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount); 7647149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7657149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void markViewHoldersUpdated(int positionStart, int itemCount, Object payloads); 7667149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7677149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void onDispatchFirstPass(UpdateOp updateOp); 7687149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7697149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void onDispatchSecondPass(UpdateOp updateOp); 7707149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7717149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void offsetPositionsForAdd(int positionStart, int itemCount); 7727149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas 7737149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas void offsetPositionsForMove(int from, int to); 7747149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas } 7757149a63961c5fe6706160bc717a3b6cbb083ca54Aurimas Liutikas} 776