/* * Copyright (C) 2015 Simon Vig Therkildsen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.simonvt.cathode.ui.adapter; import java.util.ArrayList; import java.util.List; import timber.log.Timber; public class AdapterNotifier { private class Item { long id; int viewType; long lastModified; public Item(long id, int viewType, long lastModified) { this.id = id; this.viewType = viewType; this.lastModified = lastModified; } } private BaseAdapter adapter; private List<Item> items; public AdapterNotifier(BaseAdapter adapter) { this.adapter = adapter; } private int indexOf(List<Item> items, long id, int viewType) { for (int i = 0, count = items.size(); i < count; i++) { Item item = items.get(i); if (id == item.id && viewType == item.viewType) { return i; } } return -1; } public void notifyChanged() { List<Item> oldItems = items; final int itemCount = adapter.getItemCount(); List<Item> newItems = new ArrayList<>(); for (int position = 0; position < itemCount; position++) { newItems.add(new Item(adapter.getItemId(position), adapter.getItemViewType(position), adapter.getLastModified(position))); } if (oldItems == null) { notifyItemRangeInserted(0, itemCount); } else { final int oldItemCount = oldItems.size(); final int newItemCount = newItems.size(); for (int i = oldItemCount - 1; i >= 0; i--) { Item item = oldItems.get(i); final int newPos = indexOf(newItems, item.id, item.viewType); if (newPos == -1) { notifyItemRemoved(i); oldItems.remove(i); } } // Fill oldItems, in case one is moved to the end of the list later. if (oldItems.size() < newItemCount) { for (int i = oldItems.size(); i < newItemCount; i++) { oldItems.add(new Item(Long.MIN_VALUE, Integer.MIN_VALUE, Long.MIN_VALUE)); } } for (int newPos = 0; newPos < newItemCount; newPos++) { Item newItem = newItems.get(newPos); final int oldPos = indexOf(oldItems, newItem.id, newItem.viewType); if (oldPos == -1) { notifyItemInserted(newPos); oldItems.add(newPos, new Item(Long.MIN_VALUE, Integer.MIN_VALUE, Long.MIN_VALUE)); } else if (newPos != oldPos) { notifyItemMoved(oldPos, newPos); oldItems.remove(oldPos); oldItems.add(newPos, new Item(Long.MIN_VALUE, Integer.MIN_VALUE, Long.MIN_VALUE)); } if (oldPos != -1) { Item oldItem = oldItems.get(oldPos); if (newItem.lastModified != oldItem.lastModified) { notifyItemChanged(newPos); } } } } items = newItems; } public final void notifyItemChanged(int position) { Timber.d("notifyItemChanged: %d", position); adapter.notifyItemChanged(position); } public final void notifyItemRangeChanged(int positionStart, int itemCount) { adapter.notifyItemRangeChanged(positionStart, itemCount); } public final void notifyItemInserted(int position) { Timber.d("notifyItemInserted: %d", position); adapter.notifyItemRangeInserted(position, 1); } public final void notifyItemMoved(int fromPosition, int toPosition) { Timber.d("notifyItemMoved: %d - %d", fromPosition, toPosition); adapter.notifyItemMoved(fromPosition, toPosition); } public final void notifyItemRangeInserted(int positionStart, int itemCount) { Timber.d("notifyItemRangeInserted: %d", positionStart); adapter.notifyItemRangeInserted(positionStart, itemCount); } public final void notifyItemRemoved(int position) { Timber.d("notifyItemRemoved: %d", position); adapter.notifyItemRangeRemoved(position, 1); } public final void notifyItemRangeRemoved(int positionStart, int itemCount) { Timber.d("notifyItemRangeRemoved: %d", positionStart); adapter.notifyItemRangeRemoved(positionStart, itemCount); } }