1a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar/* 2a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Copyright (C) 2014 The Android Open Source Project 3a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 4a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * you may not use this file except in compliance with the License. 6a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * You may obtain a copy of the License at 7a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 8a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 10a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Unless required by applicable law or agreed to in writing, software 11a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * See the License for the specific language governing permissions and 14a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * limitations under the License. 15a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 16a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 17a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyarpackage android.support.v7.util; 18a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 19a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyarimport java.lang.reflect.Array; 2012833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyarimport java.util.Arrays; 217fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheevimport java.util.Collection; 227fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheevimport java.util.Comparator; 23a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 24a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar/** 25a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * A Sorted list implementation that can keep items in order and also notify for changes in the 26a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * list 27a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * such that it can be bound to a {@link android.support.v7.widget.RecyclerView.Adapter 28a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * RecyclerView.Adapter}. 29a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 30a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * It keeps items ordered using the {@link Callback#compare(Object, Object)} method and uses 31a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * binary search to retrieve items. If the sorting criteria of your items may change, make sure you 32a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * call appropriate methods while editing them to avoid data inconsistencies. 33a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 34a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * You can control the order of items and change notifications via the {@link Callback} parameter. 35a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 36a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar@SuppressWarnings("unchecked") 37a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyarpublic class SortedList<T> { 38a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 39a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 40a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Used by {@link #indexOf(Object)} when he item cannot be found in the list. 41a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 42a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public static final int INVALID_POSITION = -1; 43a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 44a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private static final int MIN_CAPACITY = 10; 45a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private static final int CAPACITY_GROWTH = MIN_CAPACITY; 46a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private static final int INSERTION = 1; 47a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private static final int DELETION = 1 << 1; 48a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private static final int LOOKUP = 1 << 2; 49a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar T[] mData; 50a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 51a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 527fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * A copy of the previous list contents used during the merge phase of addAll. 537fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev */ 547fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private T[] mOldData; 557fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private int mOldDataStart; 567fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private int mOldDataSize; 577fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 587fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev /** 597fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * The size of the valid portion of mData during the merge phase of addAll. 607fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev */ 617fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private int mMergedSize; 627fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 637fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 647fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev /** 65a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * The callback instance that controls the behavior of the SortedList and get notified when 66a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * changes happen. 67a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 68a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private Callback mCallback; 69a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 70a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private BatchedCallback mBatchedCallback; 71a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 72a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private int mSize; 73a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private final Class<T> mTClass; 74a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 75a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 76a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Creates a new SortedList of type T. 77a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 78a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param klass The class of the contents of the SortedList. 79a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param callback The callback that controls the behavior of SortedList. 80a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 81a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public SortedList(Class<T> klass, Callback<T> callback) { 82a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar this(klass, callback, MIN_CAPACITY); 83a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 84a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 85a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 86a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Creates a new SortedList of type T. 87a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 88a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param klass The class of the contents of the SortedList. 89a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param callback The callback that controls the behavior of SortedList. 90a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param initialCapacity The initial capacity to hold items. 91a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 92a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public SortedList(Class<T> klass, Callback<T> callback, int initialCapacity) { 93a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mTClass = klass; 94a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mData = (T[]) Array.newInstance(klass, initialCapacity); 95a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback = callback; 96a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mSize = 0; 97a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 98a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 99a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 100a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * The number of items in the list. 101a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 102a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return The number of items in the list. 103a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 104a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public int size() { 105a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return mSize; 106a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 107a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 108a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 109a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Adds the given item to the list. If this is a new item, SortedList calls 110a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link Callback#onInserted(int, int)}. 111a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 112a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If the item already exists in the list and its sorting criteria is not changed, it is 113a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * replaced with the existing Item. SortedList uses 114a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link Callback#areItemsTheSame(Object, Object)} to check if two items are the same item 115a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * and uses {@link Callback#areContentsTheSame(Object, Object)} to decide whether it should 116a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * call {@link Callback#onChanged(int, int)} or not. In both cases, it always removes the 117a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * reference to the old item and puts the new item into the backing array even if 118a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link Callback#areContentsTheSame(Object, Object)} returns false. 119a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 120a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If the sorting criteria of the item is changed, SortedList won't be able to find 121a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * its duplicate in the list which will result in having a duplicate of the Item in the list. 122a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If you need to update sorting criteria of an item that already exists in the list, 123a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * use {@link #updateItemAt(int, Object)}. You can find the index of the item using 124a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link #indexOf(Object)} before you update the object. 125a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 126a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param item The item to be added into the list. 1277fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 128a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return The index of the newly added item. 129a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @see {@link Callback#compare(Object, Object)} 130a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @see {@link Callback#areItemsTheSame(Object, Object)} 131a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @see {@link Callback#areContentsTheSame(Object, Object)}} 132a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 133a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public int add(T item) { 1347fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 135a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return add(item, true); 136a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 137a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 138a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 1397fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * Adds the given items to the list. Equivalent to calling {@link SortedList#add} in a loop, 1407fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * except the callback events may be in a different order/granularity since addAll can batch 1417fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * them for better performance. 1427fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * <p> 1437fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * If allowed, may modify the input array and even take the ownership over it in order 1447fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * to avoid extra memory allocation during sorting and deduplication. 1457fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * </p> 1467fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * @param items Array of items to be added into the list. 1477fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * @param mayModifyInput If true, SortedList is allowed to modify the input. 148d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette * @see {@link SortedList#addAll(Object[] items)}. 1497fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev */ 1507fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev public void addAll(T[] items, boolean mayModifyInput) { 1517fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 1527fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (items.length == 0) { 1537fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return; 1547fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 1557fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (mayModifyInput) { 1567fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev addAllInternal(items); 1577fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } else { 1587fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev T[] copy = (T[]) Array.newInstance(mTClass, items.length); 1597fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev System.arraycopy(items, 0, copy, 0, items.length); 1607fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev addAllInternal(copy); 1617fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 1627fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 1637fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 1647fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 1657fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev /** 1667fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * Adds the given items to the list. Does not modify the input. 1677fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 1687fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * @see {@link SortedList#addAll(T[] items, boolean mayModifyInput)} 1697fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 1707fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * @param items Array of items to be added into the list. 1717fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev */ 1727fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev public void addAll(T... items) { 1737fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev addAll(items, false); 1747fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 1757fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 1767fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev /** 1777fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * Adds the given items to the list. Does not modify the input. 1787fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 1797fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * @see {@link SortedList#addAll(T[] items, boolean mayModifyInput)} 1807fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 1817fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * @param items Collection of items to be added into the list. 1827fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev */ 1837fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev public void addAll(Collection<T> items) { 1847fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev T[] copy = (T[]) Array.newInstance(mTClass, items.size()); 1857fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev addAll(items.toArray(copy), true); 1867fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 1877fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 1887fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private void addAllInternal(T[] newItems) { 1897fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev final boolean forceBatchedUpdates = !(mCallback instanceof BatchedCallback); 1907fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (forceBatchedUpdates) { 1917fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev beginBatchedUpdates(); 1927fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 1937fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 1947fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mOldData = mData; 1957fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mOldDataStart = 0; 1967fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mOldDataSize = mSize; 1977fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 1987fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev Arrays.sort(newItems, mCallback); // Arrays.sort is stable. 1997fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2007fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev final int newSize = deduplicate(newItems); 2017fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (mSize == 0) { 2027fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mData = newItems; 2037fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mSize = newSize; 2047fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mMergedSize = newSize; 2057fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mCallback.onInserted(0, newSize); 2067fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } else { 2077fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev merge(newItems, newSize); 2087fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2097fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2107fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mOldData = null; 2117fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2127fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (forceBatchedUpdates) { 2137fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev endBatchedUpdates(); 2147fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2157fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2167fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2177fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev /** 2187fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * Remove duplicate items, leaving only the last item from each group of "same" items. 2197fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * Move the remaining items to the beginning of the array. 2207fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 2217fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * @return Number of deduplicated items at the beginning of the array. 2227fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev */ 2237fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private int deduplicate(T[] items) { 2247fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (items.length == 0) { 2257fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throw new IllegalArgumentException("Input array must be non-empty"); 2267fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2277fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2287fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // Keep track of the range of equal items at the end of the output. 2297fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // Start with the range containing just the first item. 2307fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int rangeStart = 0; 2317fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int rangeEnd = 1; 2327fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2337fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev for (int i = 1; i < items.length; ++i) { 2347fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev T currentItem = items[i]; 2357fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2367fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int compare = mCallback.compare(items[rangeStart], currentItem); 2377fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (compare > 0) { 2387fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throw new IllegalArgumentException("Input must be sorted in ascending order."); 2397fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2407fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2417fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (compare == 0) { 2427fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // The range of equal items continues, update it. 2437fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev final int sameItemPos = findSameItem(currentItem, items, rangeStart, rangeEnd); 2447fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (sameItemPos != INVALID_POSITION) { 2457fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // Replace the duplicate item. 2467fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev items[sameItemPos] = currentItem; 2477fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } else { 2487fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // Expand the range. 2497fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (rangeEnd != i) { // Avoid redundant copy. 2507fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev items[rangeEnd] = currentItem; 2517fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2527fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev rangeEnd++; 2537fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2547fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } else { 2557fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // The range has ended. Reset it to contain just the current item. 2567fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (rangeEnd != i) { // Avoid redundant copy. 2577fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev items[rangeEnd] = currentItem; 2587fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2597fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev rangeStart = rangeEnd++; 2607fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2617fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2627fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return rangeEnd; 2637fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2647fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2657fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2667fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private int findSameItem(T item, T[] items, int from, int to) { 2677fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev for (int pos = from; pos < to; pos++) { 2687fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (mCallback.areItemsTheSame(items[pos], item)) { 2697fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return pos; 2707fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2717fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2727fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return INVALID_POSITION; 2737fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2747fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2757fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev /** 2767fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * This method assumes that newItems are sorted and deduplicated. 2777fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev */ 2787fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private void merge(T[] newData, int newDataSize) { 2797fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev final int mergedCapacity = mSize + newDataSize + CAPACITY_GROWTH; 2807fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mData = (T[]) Array.newInstance(mTClass, mergedCapacity); 2817fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mMergedSize = 0; 2827fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2837fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int newDataStart = 0; 2847fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev while (mOldDataStart < mOldDataSize || newDataStart < newDataSize) { 2857fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (mOldDataStart == mOldDataSize) { 2867fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // No more old items, copy the remaining new items. 2877fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int itemCount = newDataSize - newDataStart; 2887fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev System.arraycopy(newData, newDataStart, mData, mMergedSize, itemCount); 2897fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mMergedSize += itemCount; 2907fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mSize += itemCount; 2917fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mCallback.onInserted(mMergedSize - itemCount, itemCount); 2927fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev break; 2937fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 2947fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 2957fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (newDataStart == newDataSize) { 2967fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // No more new items, copy the remaining old items. 2977fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int itemCount = mOldDataSize - mOldDataStart; 2987fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev System.arraycopy(mOldData, mOldDataStart, mData, mMergedSize, itemCount); 2997fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mMergedSize += itemCount; 3007fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev break; 3017fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 3027fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 3037fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev T oldItem = mOldData[mOldDataStart]; 3047fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev T newItem = newData[newDataStart]; 3057fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int compare = mCallback.compare(oldItem, newItem); 3067fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (compare > 0) { 3077fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // New item is lower, output it. 3087fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mData[mMergedSize++] = newItem; 3097fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mSize++; 3107fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev newDataStart++; 3117fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mCallback.onInserted(mMergedSize - 1, 1); 3127fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } else if (compare == 0 && mCallback.areItemsTheSame(oldItem, newItem)) { 3137fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // Items are the same. Output the new item, but consume both. 3147fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mData[mMergedSize++] = newItem; 3157fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev newDataStart++; 3167fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mOldDataStart++; 3177fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (!mCallback.areContentsTheSame(oldItem, newItem)) { 3187fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mCallback.onChanged(mMergedSize - 1, 1); 3197fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 3207fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } else { 3217fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // Old item is lower than or equal to (but not the same as the new). Output it. 3227fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // New item with the same sort order will be inserted later. 3237fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mData[mMergedSize++] = oldItem; 3247fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev mOldDataStart++; 3257fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 3267fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 3277fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 3287fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 3297fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private void throwIfMerging() { 3307fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (mOldData != null) { 3317fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throw new IllegalStateException("Cannot call this method from within addAll"); 3327fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 3337fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 3347fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev 3357fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev /** 336a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Batches adapter updates that happen between calling this method until calling 337a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link #endBatchedUpdates()}. For example, if you add multiple items in a loop 338a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * and they are placed into consecutive indices, SortedList calls 339a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link Callback#onInserted(int, int)} only once with the proper item count. If an event 340a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * cannot be merged with the previous event, the previous event is dispatched 341a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * to the callback instantly. 342a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 343a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * After running your data updates, you <b>must</b> call {@link #endBatchedUpdates()} 344a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * which will dispatch any deferred data change event to the current callback. 345a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 346a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * A sample implementation may look like this: 347a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <pre> 348a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * mSortedList.beginBatchedUpdates(); 349a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * try { 350a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * mSortedList.add(item1) 351a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * mSortedList.add(item2) 352a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * mSortedList.remove(item3) 353a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * ... 354a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * } finally { 355a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * mSortedList.endBatchedUpdates(); 356a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * } 357a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * </pre> 358a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 359a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Instead of using this method to batch calls, you can use a Callback that extends 360a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link BatchedCallback}. In that case, you must make sure that you are manually calling 361a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link BatchedCallback#dispatchLastEvent()} right after you complete your data changes. 362a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Failing to do so may create data inconsistencies with the Callback. 363a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 364a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If the current Callback in an instance of {@link BatchedCallback}, calling this method 365a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * has no effect. 366a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 367a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void beginBatchedUpdates() { 3687fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 369a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mCallback instanceof BatchedCallback) { 370a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return; 371a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 372a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mBatchedCallback == null) { 373a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mBatchedCallback = new BatchedCallback(mCallback); 374a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 375a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback = mBatchedCallback; 376a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 377a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 378a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 379a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Ends the update transaction and dispatches any remaining event to the callback. 380a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 381a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void endBatchedUpdates() { 3827fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 383a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mCallback instanceof BatchedCallback) { 384a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar ((BatchedCallback) mCallback).dispatchLastEvent(); 385a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 386a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mCallback == mBatchedCallback) { 387a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback = mBatchedCallback.mWrappedCallback; 388a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 389a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 390a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 391a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private int add(T item, boolean notify) { 3927fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int index = findIndexOf(item, mData, 0, mSize, INSERTION); 393a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (index == INVALID_POSITION) { 394a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar index = 0; 395a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } else if (index < mSize) { 396a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar T existing = mData[index]; 397a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mCallback.areItemsTheSame(existing, item)) { 398a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mCallback.areContentsTheSame(existing, item)) { 399a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar //no change but still replace the item 400a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mData[index] = item; 401a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return index; 402a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } else { 403a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mData[index] = item; 404a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback.onChanged(index, 1); 405a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return index; 406a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 407a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 408a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 409a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar addToData(index, item); 410a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (notify) { 411a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback.onInserted(index, 1); 412a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 413a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return index; 414a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 415a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 416a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 417a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Removes the provided item from the list and calls {@link Callback#onRemoved(int, int)}. 418a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 419a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param item The item to be removed from the list. 4207fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 421a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return True if item is removed, false if item cannot be found in the list. 422a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 423a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public boolean remove(T item) { 4247fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 425a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return remove(item, true); 426a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 427a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 428a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 429a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Removes the item at the given index and calls {@link Callback#onRemoved(int, int)}. 430a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 431a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param index The index of the item to be removed. 4327fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 433a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return The removed item. 434a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 435a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public T removeItemAt(int index) { 4367fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 437a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar T item = get(index); 438a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar removeItemAtIndex(index, true); 439a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return item; 440a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 441a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 442a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private boolean remove(T item, boolean notify) { 4437fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int index = findIndexOf(item, mData, 0, mSize, DELETION); 444a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (index == INVALID_POSITION) { 445a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return false; 446a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 447a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar removeItemAtIndex(index, notify); 448a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return true; 449a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 450a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 451a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private void removeItemAtIndex(int index, boolean notify) { 452a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar System.arraycopy(mData, index + 1, mData, index, mSize - index - 1); 453a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mSize--; 454a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mData[mSize] = null; 455a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (notify) { 456a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback.onRemoved(index, 1); 457a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 458a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 459a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 460a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 461a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Updates the item at the given index and calls {@link Callback#onChanged(int, int)} and/or 462a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link Callback#onMoved(int, int)} if necessary. 463a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 464a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * You can use this method if you need to change an existing Item such that its position in the 465a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * list may change. 466a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 467a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If the new object is a different object (<code>get(index) != item</code>) and 468a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link Callback#areContentsTheSame(Object, Object)} returns <code>true</code>, SortedList 469a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * avoids calling {@link Callback#onChanged(int, int)} otherwise it calls 470a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link Callback#onChanged(int, int)}. 471a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 472a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If the new position of the item is different than the provided <code>index</code>, 473a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * SortedList 474a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * calls {@link Callback#onMoved(int, int)}. 475a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 476a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param index The index of the item to replace 477a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param item The item to replace the item at the given Index. 478a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @see #add(Object) 479a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 480a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void updateItemAt(int index, T item) { 4817fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 482a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar final T existing = get(index); 483a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar // assume changed if the same object is given back 484a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar boolean contentsChanged = existing == item || !mCallback.areContentsTheSame(existing, item); 485a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (existing != item) { 486a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar // different items, we can use comparison and may avoid lookup 487a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar final int cmp = mCallback.compare(existing, item); 488a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (cmp == 0) { 489a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mData[index] = item; 490a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (contentsChanged) { 491a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback.onChanged(index, 1); 492a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 493a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return; 494a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 495a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 496a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (contentsChanged) { 497a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback.onChanged(index, 1); 498a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 499a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar // TODO this done in 1 pass to avoid shifting twice. 500a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar removeItemAtIndex(index, false); 501a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int newIndex = add(item, false); 502a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (index != newIndex) { 503a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback.onMoved(index, newIndex); 504a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 505a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 506a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 507a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 508a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * This method can be used to recalculate the position of the item at the given index, without 509a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * triggering an {@link Callback#onChanged(int, int)} callback. 510a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 511a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If you are editing objects in the list such that their position in the list may change but 512a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * you don't want to trigger an onChange animation, you can use this method to re-position it. 513a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If the item changes position, SortedList will call {@link Callback#onMoved(int, int)} 514a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * without 515a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * calling {@link Callback#onChanged(int, int)}. 516a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 517a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * A sample usage may look like: 518a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 519a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <pre> 520a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * final int position = mSortedList.indexOf(item); 521a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * item.incrementPriority(); // assume items are sorted by priority 522a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * mSortedList.recalculatePositionOfItemAt(position); 523a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * </pre> 524a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * In the example above, because the sorting criteria of the item has been changed, 525a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * mSortedList.indexOf(item) will not be able to find the item. This is why the code above 526a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * first 527a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * gets the position before editing the item, edits it and informs the SortedList that item 528a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * should be repositioned. 529a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 530a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param index The current index of the Item whose position should be re-calculated. 531a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @see #updateItemAt(int, Object) 532a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @see #add(Object) 533a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 534a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void recalculatePositionOfItemAt(int index) { 5357fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 536a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar // TODO can be improved 537a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar final T item = get(index); 538a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar removeItemAtIndex(index, false); 539a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int newIndex = add(item, false); 540a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (index != newIndex) { 541a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mCallback.onMoved(index, newIndex); 542a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 543a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 544a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 545a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 546a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Returns the item at the given index. 547a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 548a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param index The index of the item to retrieve. 5497fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 550a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return The item at the given index. 551a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @throws java.lang.IndexOutOfBoundsException if provided index is negative or larger than the 552a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * size of the list. 553a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 554a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public T get(int index) throws IndexOutOfBoundsException { 555a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (index >= mSize || index < 0) { 556a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar throw new IndexOutOfBoundsException("Asked to get item at " + index + " but size is " 557a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar + mSize); 558a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 5597fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (mOldData != null) { 5607fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // The call is made from a callback during addAll execution. The data is split 5617fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev // between mData and mOldData. 5627fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (index >= mMergedSize) { 5637fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return mOldData[index - mMergedSize + mOldDataStart]; 5647fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 5657fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 566a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return mData[index]; 567a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 568a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 569a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 570a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Returns the position of the provided item. 571a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 572a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param item The item to query for position. 5737fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 574a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return The position of the provided item or {@link #INVALID_POSITION} if item is not in the 575a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * list. 576a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 577a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public int indexOf(T item) { 5787fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (mOldData != null) { 5797fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev int index = findIndexOf(item, mData, 0, mMergedSize, LOOKUP); 5807fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (index != INVALID_POSITION) { 5817fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return index; 5827fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 5837fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev index = findIndexOf(item, mOldData, mOldDataStart, mOldDataSize, LOOKUP); 5847fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev if (index != INVALID_POSITION) { 5857fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return index - mOldDataStart + mMergedSize; 5867fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 5877fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return INVALID_POSITION; 5887fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev } 5897fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev return findIndexOf(item, mData, 0, mSize, LOOKUP); 590a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 591a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 5927fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev private int findIndexOf(T item, T[] mData, int left, int right, int reason) { 593a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar while (left < right) { 594a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar final int middle = (left + right) / 2; 595a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar T myItem = mData[middle]; 596a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar final int cmp = mCallback.compare(myItem, item); 597a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (cmp < 0) { 598a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar left = middle + 1; 599a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } else if (cmp == 0) { 600a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mCallback.areItemsTheSame(myItem, item)) { 601a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return middle; 602a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } else { 603a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int exact = linearEqualitySearch(item, middle, left, right); 604a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (reason == INSERTION) { 605a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return exact == INVALID_POSITION ? middle : exact; 606a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } else { 607a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return exact; 608a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 609a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 610a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } else { 611a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar right = middle; 612a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 613a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 614a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return reason == INSERTION ? left : INVALID_POSITION; 615a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 616a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 617a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private int linearEqualitySearch(T item, int middle, int left, int right) { 618a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar // go left 619a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar for (int next = middle - 1; next >= left; next--) { 620a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar T nextItem = mData[next]; 621a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int cmp = mCallback.compare(nextItem, item); 622a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (cmp != 0) { 623a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar break; 624a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 625a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mCallback.areItemsTheSame(nextItem, item)) { 626a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return next; 627a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 628a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 629a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar for (int next = middle + 1; next < right; next++) { 630a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar T nextItem = mData[next]; 631a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int cmp = mCallback.compare(nextItem, item); 632a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (cmp != 0) { 633a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar break; 634a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 635a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mCallback.areItemsTheSame(nextItem, item)) { 636a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return next; 637a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 638a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 639a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return INVALID_POSITION; 640a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 641a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 642a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private void addToData(int index, T item) { 643a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (index > mSize) { 644a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar throw new IndexOutOfBoundsException( 645a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar "cannot add item to " + index + " because size is " + mSize); 646a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 647a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mSize == mData.length) { 648a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar // we are at the limit enlarge 649a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar T[] newData = (T[]) Array.newInstance(mTClass, mData.length + CAPACITY_GROWTH); 650a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar System.arraycopy(mData, 0, newData, 0, index); 651a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar newData[index] = item; 652a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar System.arraycopy(mData, index, newData, index + 1, mSize - index); 653a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mData = newData; 654a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } else { 655a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar // just shift, we fit 656a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar System.arraycopy(mData, index, mData, index + 1, mSize - index); 657a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mData[index] = item; 658a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 659a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mSize++; 660a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 661a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 662a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 66312833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar * Removes all items from the SortedList. 66412833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar */ 66512833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar public void clear() { 6667fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev throwIfMerging(); 66712833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar if (mSize == 0) { 66812833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar return; 66912833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar } 67012833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar final int prevSize = mSize; 67112833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar Arrays.fill(mData, 0, prevSize, null); 67212833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar mSize = 0; 67312833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar mCallback.onRemoved(0, prevSize); 67412833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar } 67512833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar 67612833d36969f1540dd5fc6fe32a25fa8b52a8e0bYigit Boyar /** 677a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * The class that controls the behavior of the {@link SortedList}. 678a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 679a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * It defines how items should be sorted and how duplicates should be handled. 680a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 681a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * SortedList calls the callback methods on this class to notify changes about the underlying 682a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * data. 683a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 6847fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev public static abstract class Callback<T2> implements Comparator<T2> { 685a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 686a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 687a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Similar to {@link java.util.Comparator#compare(Object, Object)}, should compare two and 688a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * return how they should be ordered. 689a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 690a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param o1 The first object to compare. 691a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param o2 The second object to compare. 6927fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 693a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return a negative integer, zero, or a positive integer as the 694a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * first argument is less than, equal to, or greater than the 695a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * second. 696a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 697a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar abstract public int compare(T2 o1, T2 o2); 698a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 699a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 700a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Called by the SortedList when an item is inserted at the given position. 701a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 702a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param position The position of the new item. 703a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param count The number of items that have been added. 704a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 705a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar abstract public void onInserted(int position, int count); 706a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 707a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 708a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Called by the SortedList when an item is removed from the given position. 709a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 710a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param position The position of the item which has been removed. 711a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param count The number of items which have been removed. 712a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 713a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar abstract public void onRemoved(int position, int count); 714a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 715a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 716a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Called by the SortedList when an item changes its position in the list. 717a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 718a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param fromPosition The previous position of the item before the move. 719a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param toPosition The new position of the item. 720a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 721a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar abstract public void onMoved(int fromPosition, int toPosition); 722a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 723a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 724a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Called by the SortedList when the item at the given position is updated. 725a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 726a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param position The position of the item which has been updated. 727a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param count The number of items which has changed. 728a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 729a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar abstract public void onChanged(int position, int count); 730a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 731a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 732a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Called by the SortedList when it wants to check whether two items have the same data 733a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * or not. SortedList uses this information to decide whether it should call 734a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * {@link #onChanged(int, int)} or not. 735a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 736a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * SortedList uses this method to check equality instead of {@link Object#equals(Object)} 737a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * so 738a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * that you can change its behavior depending on your UI. 739a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 740a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * For example, if you are using SortedList with a {@link android.support.v7.widget.RecyclerView.Adapter 741a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * RecyclerView.Adapter}, you should 742a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * return whether the items' visual representations are the same or not. 743a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 744a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param oldItem The previous representation of the object. 745a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param newItem The new object that replaces the previous one. 7467fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 747a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return True if the contents of the items are the same or false if they are different. 748a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 749a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar abstract public boolean areContentsTheSame(T2 oldItem, T2 newItem); 750a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 751a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 752a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Called by the SortedList to decide whether two object represent the same Item or not. 753a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 754a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * For example, if your items have unique ids, this method should check their equality. 755a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 756a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param item1 The first item to check. 757a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param item2 The second item to check. 7587fa39157f88d13bc417dab8db7c13e342a14cba0Vladislav Kaznacheev * 759a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @return True if the two items represent the same object or false if they are different. 760a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 761a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar abstract public boolean areItemsTheSame(T2 item1, T2 item2); 762a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 763a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 764a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 765a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * A callback implementation that can batch notify events dispatched by the SortedList. 766a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 767a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * This class can be useful if you want to do multiple operations on a SortedList but don't 768a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * want to dispatch each event one by one, which may result in a performance issue. 769a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 770a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * For example, if you are going to add multiple items to a SortedList, BatchedCallback call 771a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * convert individual <code>onInserted(index, 1)</code> calls into one 772a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <code>onInserted(index, N)</code> if items are added into consecutive indices. This change 773a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * can help RecyclerView resolve changes much more easily. 774a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * <p> 775a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * If consecutive changes in the SortedList are not suitable for batching, BatchingCallback 776a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * dispatches them as soon as such case is detected. After your edits on the SortedList is 777a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * complete, you <b>must</b> always call {@link BatchedCallback#dispatchLastEvent()} to flush 778a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * all changes to the Callback. 779a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 780a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public static class BatchedCallback<T2> extends Callback<T2> { 781a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 782a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar private final Callback<T2> mWrappedCallback; 783a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar static final int TYPE_NONE = 0; 784a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar static final int TYPE_ADD = 1; 785a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar static final int TYPE_REMOVE = 2; 786a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar static final int TYPE_CHANGE = 3; 787a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar static final int TYPE_MOVE = 4; 788a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 789a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int mLastEventType = TYPE_NONE; 790a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int mLastEventPosition = -1; 791a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int mLastEventCount = -1; 792a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 793a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 794a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Creates a new BatchedCallback that wraps the provided Callback. 795a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * 796a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * @param wrappedCallback The Callback which should received the data change callbacks. 797a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * Other method calls (e.g. {@link #compare(Object, Object)} from 798a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * the SortedList are directly forwarded to this Callback. 799a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 800a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public BatchedCallback(Callback<T2> wrappedCallback) { 801a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mWrappedCallback = wrappedCallback; 802a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 803a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 804a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar @Override 805a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public int compare(T2 o1, T2 o2) { 806a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return mWrappedCallback.compare(o1, o2); 807a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 808a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 809a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar @Override 810a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void onInserted(int position, int count) { 811a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mLastEventType == TYPE_ADD && position >= mLastEventPosition 812a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar && position <= mLastEventPosition + mLastEventCount) { 813a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventCount += count; 814a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventPosition = Math.min(position, mLastEventPosition); 815a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return; 816a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 817a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar dispatchLastEvent(); 818a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventPosition = position; 819a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventCount = count; 820a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventType = TYPE_ADD; 821a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 822a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 823a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar @Override 824a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void onRemoved(int position, int count) { 825a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mLastEventType == TYPE_REMOVE && mLastEventPosition == position) { 826a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventCount += count; 827a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return; 828a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 829a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar dispatchLastEvent(); 830a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventPosition = position; 831a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventCount = count; 832a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventType = TYPE_REMOVE; 833a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 834a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 835a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar @Override 836a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void onMoved(int fromPosition, int toPosition) { 837a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar dispatchLastEvent();//moves are not merged 838a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mWrappedCallback.onMoved(fromPosition, toPosition); 839a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 840a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 841a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar @Override 842a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void onChanged(int position, int count) { 843a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mLastEventType == TYPE_CHANGE && 844a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar !(position > mLastEventPosition + mLastEventCount 845a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar || position + count < mLastEventPosition)) { 846a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar // take potential overlap into account 847a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar int previousEnd = mLastEventPosition + mLastEventCount; 848a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventPosition = Math.min(position, mLastEventPosition); 849a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventCount = Math.max(previousEnd, position + count) - mLastEventPosition; 850a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return; 851a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 852a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar dispatchLastEvent(); 853a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventPosition = position; 854a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventCount = count; 855a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventType = TYPE_CHANGE; 856a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 857a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 858a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar @Override 859a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public boolean areContentsTheSame(T2 oldItem, T2 newItem) { 860a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return mWrappedCallback.areContentsTheSame(oldItem, newItem); 861a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 862a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 863a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar @Override 864a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public boolean areItemsTheSame(T2 item1, T2 item2) { 865a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return mWrappedCallback.areItemsTheSame(item1, item2); 866a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 867a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 868a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar 869a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar /** 870a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * This method dispatches any pending event notifications to the wrapped Callback. 871a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar * You <b>must</b> always call this method after you are done with editing the SortedList. 872a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar */ 873a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar public void dispatchLastEvent() { 874a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar if (mLastEventType == TYPE_NONE) { 875a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar return; 876a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 877a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar switch (mLastEventType) { 878a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar case TYPE_ADD: 879a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mWrappedCallback.onInserted(mLastEventPosition, mLastEventCount); 880a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar break; 881a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar case TYPE_REMOVE: 882a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mWrappedCallback.onRemoved(mLastEventPosition, mLastEventCount); 883a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar break; 884a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar case TYPE_CHANGE: 885a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mWrappedCallback.onChanged(mLastEventPosition, mLastEventCount); 886a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar break; 887a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 888a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar mLastEventType = TYPE_NONE; 889a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 890a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar } 891a3d5bb01bc01733999d84c452a27012c57ab369cYigit Boyar} 892