package com.beloo.widget.chipslayoutmanager.cache; import android.graphics.Rect; import android.os.Parcelable; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.util.Pair; import android.view.View; import java.util.Iterator; import java.util.List; import java.util.NavigableSet; import java.util.TreeSet; class ViewCacheStorage implements IViewCacheStorage { private static final String TAG = ViewCacheStorage.class.getSimpleName(); private static final int SIZE_MAX_CACHE = 1000; private RecyclerView.LayoutManager layoutManager; private NavigableSet<Integer> startsRow = new TreeSet<>(); private NavigableSet<Integer> endsRow = new TreeSet<>(); private int maxCacheSize = SIZE_MAX_CACHE; private boolean isCachingEnabled; ViewCacheStorage(RecyclerView.LayoutManager layoutManager) { this.layoutManager = layoutManager; isCachingEnabled = true; } public void setMaxCacheSize(int maxCacheSize) { this.maxCacheSize = maxCacheSize; } @Override public boolean isCachingEnabled() { return isCachingEnabled; } @Override public int getStartOfRow(int positionInRow) { Integer integer = startsRow.floor(positionInRow); if (integer == null) { integer = positionInRow; } return integer; } @Override public boolean isPositionEndsRow(int position) { return endsRow.contains(position); } @Override public boolean isPositionStartsRow(int position) { return startsRow.contains(position); } @Override public void setCachingEnabled(boolean isEnabled) { if (isCachingEnabled == isEnabled) return; Log.i(TAG, isEnabled ? "caching enabled" : "caching disabled"); isCachingEnabled = isEnabled; } //todo test max size cache reached private void checkCacheSizeReached() { if (startsRow.size() > maxCacheSize) { startsRow.remove(startsRow.first()); } if (endsRow.size() > maxCacheSize) { endsRow.remove(endsRow.first()); } } @Override public void storeRow(List<Pair<Rect, View>> row) { if (isCachingEnabled && !row.isEmpty()) { Pair<Rect, View> firstPair = row.get(0); Pair<Rect, View> secondPair = row.get(row.size()-1); int startPosition = layoutManager.getPosition(firstPair.second); int endPosition = layoutManager.getPosition(secondPair.second); checkCacheSizeReached(); startsRow.add(startPosition); endsRow.add(endPosition); } } @Override public boolean isInCache(int position) { return startsRow.ceiling(position) != null || endsRow.ceiling(position) != null; } @Override public void purge() { startsRow.clear(); endsRow.clear(); } @Override public void purgeCacheToPosition(int position) { if (isCacheEmpty()) return; Log.d(TAG, "cache purged to position " + position); Iterator<Integer> removeIterator = startsRow.headSet(position).iterator(); while (removeIterator.hasNext()) { removeIterator.next(); removeIterator.remove(); } removeIterator = endsRow.headSet(position).iterator(); while (removeIterator.hasNext()) { removeIterator.next(); removeIterator.remove(); } } @Override public Integer getLastCachePosition() { if (isCacheEmpty()) return null; return endsRow.last(); } @Override public boolean isCacheEmpty() { return endsRow.isEmpty(); } @Override public void purgeCacheFromPosition(int position) { if (isCacheEmpty()) return; Iterator<Integer> removeIterator = startsRow.tailSet(position, true).iterator(); while (removeIterator.hasNext()) { removeIterator.next(); removeIterator.remove(); } Integer previous = startsRow.lower(position); previous = previous == null? position : previous; //we should also remove previous end row cache to guarantee consistency removeIterator = endsRow.tailSet(previous, true).iterator(); while (removeIterator.hasNext()) { removeIterator.next(); removeIterator.remove(); } } @Override public Parcelable onSaveInstanceState() { return new CacheParcelableContainer(startsRow, endsRow); } public void onRestoreInstanceState(@Nullable Parcelable parcelable) { if (parcelable == null) return; if (!(parcelable instanceof CacheParcelableContainer)) throw new IllegalStateException("wrong parcelable passed"); CacheParcelableContainer container = (CacheParcelableContainer) parcelable; startsRow = container.getStartsRow(); endsRow = container.getEndsRow(); } }