Changing hashmaps to sparseArrays and other similar conversions
Change-Id: I1905120a2dc109e8f383b973e599e2c23e005d0e
This commit is contained in:
@@ -18,6 +18,7 @@ package android.widget;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
@@ -35,6 +36,9 @@ import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
@@ -93,13 +97,10 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
|
||||
// We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data
|
||||
// structures;
|
||||
private static final HashMap<RemoteViewsCacheKey,
|
||||
FixedSizeRemoteViewsCache> sCachedRemoteViewsCaches
|
||||
= new HashMap<RemoteViewsCacheKey,
|
||||
FixedSizeRemoteViewsCache>();
|
||||
private static final HashMap<RemoteViewsCacheKey, FixedSizeRemoteViewsCache>
|
||||
sCachedRemoteViewsCaches = new HashMap<>();
|
||||
private static final HashMap<RemoteViewsCacheKey, Runnable>
|
||||
sRemoteViewsCacheRemoveRunnables
|
||||
= new HashMap<RemoteViewsCacheKey, Runnable>();
|
||||
sRemoteViewsCacheRemoveRunnables = new HashMap<>();
|
||||
|
||||
private static HandlerThread sCacheRemovalThread;
|
||||
private static Handler sCacheRemovalQueue;
|
||||
@@ -327,29 +328,21 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
* adapter that have not yet had their RemoteViews loaded.
|
||||
*/
|
||||
private class RemoteViewsFrameLayoutRefSet {
|
||||
private HashMap<Integer, LinkedList<RemoteViewsFrameLayout>> mReferences;
|
||||
private HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>
|
||||
mViewToLinkedList;
|
||||
|
||||
public RemoteViewsFrameLayoutRefSet() {
|
||||
mReferences = new HashMap<Integer, LinkedList<RemoteViewsFrameLayout>>();
|
||||
mViewToLinkedList =
|
||||
new HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>();
|
||||
}
|
||||
private final SparseArray<LinkedList<RemoteViewsFrameLayout>> mReferences =
|
||||
new SparseArray<>();
|
||||
private final HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>
|
||||
mViewToLinkedList = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Adds a new reference to a RemoteViewsFrameLayout returned by the adapter.
|
||||
*/
|
||||
public void add(int position, RemoteViewsFrameLayout layout) {
|
||||
final Integer pos = position;
|
||||
LinkedList<RemoteViewsFrameLayout> refs;
|
||||
LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(position);
|
||||
|
||||
// Create the list if necessary
|
||||
if (mReferences.containsKey(pos)) {
|
||||
refs = mReferences.get(pos);
|
||||
} else {
|
||||
if (refs == null) {
|
||||
refs = new LinkedList<RemoteViewsFrameLayout>();
|
||||
mReferences.put(pos, refs);
|
||||
mReferences.put(position, refs);
|
||||
}
|
||||
mViewToLinkedList.put(layout, refs);
|
||||
|
||||
@@ -364,10 +357,9 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
public void notifyOnRemoteViewsLoaded(int position, RemoteViews view) {
|
||||
if (view == null) return;
|
||||
|
||||
final Integer pos = position;
|
||||
if (mReferences.containsKey(pos)) {
|
||||
final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(position);
|
||||
if (refs != null) {
|
||||
// Notify all the references for that position of the newly loaded RemoteViews
|
||||
final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(pos);
|
||||
for (final RemoteViewsFrameLayout ref : refs) {
|
||||
ref.onRemoteViewsLoaded(view, mRemoteViewsOnClickHandler);
|
||||
if (mViewToLinkedList.containsKey(ref)) {
|
||||
@@ -376,7 +368,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
}
|
||||
refs.clear();
|
||||
// Remove this set from the original mapping
|
||||
mReferences.remove(pos);
|
||||
mReferences.remove(position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +409,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
int mFirstViewHeight;
|
||||
|
||||
// A mapping from type id to a set of unique type ids
|
||||
private final HashMap<Integer, Integer> mTypeIdIndexMap = new HashMap<Integer, Integer>();
|
||||
private final SparseIntArray mTypeIdIndexMap = new SparseIntArray();
|
||||
|
||||
public RemoteViewsMetaData() {
|
||||
reset();
|
||||
@@ -453,23 +445,18 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
}
|
||||
|
||||
public int getMappedViewType(int typeId) {
|
||||
if (mTypeIdIndexMap.containsKey(typeId)) {
|
||||
return mTypeIdIndexMap.get(typeId);
|
||||
} else {
|
||||
int mappedTypeId = mTypeIdIndexMap.get(typeId, -1);
|
||||
if (mappedTypeId == -1) {
|
||||
// We +1 because the loading view always has view type id of 0
|
||||
int incrementalTypeId = mTypeIdIndexMap.size() + 1;
|
||||
mTypeIdIndexMap.put(typeId, incrementalTypeId);
|
||||
return incrementalTypeId;
|
||||
mappedTypeId = mTypeIdIndexMap.size() + 1;
|
||||
mTypeIdIndexMap.put(typeId, mappedTypeId);
|
||||
}
|
||||
return mappedTypeId;
|
||||
}
|
||||
|
||||
public boolean isViewTypeInRange(int typeId) {
|
||||
int mappedType = getMappedViewType(typeId);
|
||||
if (mappedType >= viewTypeCount) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return (mappedType < viewTypeCount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -533,8 +520,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
// The meta data objects are made final so that they can be locked on independently
|
||||
// of the FixedSizeRemoteViewsCache. If we ever lock on both meta data objects, it is in
|
||||
// the order mTemporaryMetaData followed by mMetaData.
|
||||
private final RemoteViewsMetaData mMetaData;
|
||||
private final RemoteViewsMetaData mTemporaryMetaData;
|
||||
private final RemoteViewsMetaData mMetaData = new RemoteViewsMetaData();
|
||||
private final RemoteViewsMetaData mTemporaryMetaData = new RemoteViewsMetaData();
|
||||
|
||||
// The cache/mapping of position to RemoteViewsMetaData. This set is guaranteed to be
|
||||
// greater than or equal to the set of RemoteViews.
|
||||
@@ -543,22 +530,20 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
// the heavy RemoteViews around. The RemoteViews cache is trimmed to fixed constraints wrt.
|
||||
// memory and size, but this metadata cache will retain information until the data at the
|
||||
// position is guaranteed as not being necessary any more (usually on notifyDataSetChanged).
|
||||
private HashMap<Integer, RemoteViewsIndexMetaData> mIndexMetaData;
|
||||
private final SparseArray<RemoteViewsIndexMetaData> mIndexMetaData = new SparseArray<>();
|
||||
|
||||
// The cache of actual RemoteViews, which may be pruned if the cache gets too large, or uses
|
||||
// too much memory.
|
||||
private HashMap<Integer, RemoteViews> mIndexRemoteViews;
|
||||
private final SparseArray<RemoteViews> mIndexRemoteViews = new SparseArray<>();
|
||||
|
||||
// The set of indices that have been explicitly requested by the collection view
|
||||
private HashSet<Integer> mRequestedIndices;
|
||||
// An array of indices to load, Indices which are explicitely requested are set to true,
|
||||
// and those determined by the preloading algorithm to prefetch are set to false.
|
||||
private final SparseBooleanArray mIndicesToLoad = new SparseBooleanArray();
|
||||
|
||||
// We keep a reference of the last requested index to determine which item to prune the
|
||||
// farthest items from when we hit the memory limit
|
||||
private int mLastRequestedIndex;
|
||||
|
||||
// The set of indices to load, including those explicitly requested, as well as those
|
||||
// determined by the preloading algorithm to be prefetched
|
||||
private HashSet<Integer> mLoadIndices;
|
||||
|
||||
// The lower and upper bounds of the preloaded range
|
||||
private int mPreloadLowerBound;
|
||||
@@ -569,8 +554,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
// The maxCountSlack is used to determine if a new position in the cache to be loaded is
|
||||
// sufficiently ouside the old set, prompting a shifting of the "window" of items to be
|
||||
// preloaded.
|
||||
private int mMaxCount;
|
||||
private int mMaxCountSlack;
|
||||
private final int mMaxCount;
|
||||
private final int mMaxCountSlack;
|
||||
private static final float sMaxCountSlackPercent = 0.75f;
|
||||
private static final int sMaxMemoryLimitInBytes = 2 * 1024 * 1024;
|
||||
|
||||
@@ -579,17 +564,10 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
mMaxCountSlack = Math.round(sMaxCountSlackPercent * (mMaxCount / 2));
|
||||
mPreloadLowerBound = 0;
|
||||
mPreloadUpperBound = -1;
|
||||
mMetaData = new RemoteViewsMetaData();
|
||||
mTemporaryMetaData = new RemoteViewsMetaData();
|
||||
mIndexMetaData = new HashMap<Integer, RemoteViewsIndexMetaData>();
|
||||
mIndexRemoteViews = new HashMap<Integer, RemoteViews>();
|
||||
mRequestedIndices = new HashSet<Integer>();
|
||||
mLastRequestedIndex = -1;
|
||||
mLoadIndices = new HashSet<Integer>();
|
||||
}
|
||||
|
||||
public void insert(int position, RemoteViews v, long itemId,
|
||||
ArrayList<Integer> visibleWindow) {
|
||||
public void insert(int position, RemoteViews v, long itemId, int[] visibleWindow) {
|
||||
// Trim the cache if we go beyond the count
|
||||
if (mIndexRemoteViews.size() >= mMaxCount) {
|
||||
mIndexRemoteViews.remove(getFarthestPositionFrom(position, visibleWindow));
|
||||
@@ -615,8 +593,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
}
|
||||
|
||||
// Update the metadata cache
|
||||
if (mIndexMetaData.containsKey(position)) {
|
||||
final RemoteViewsIndexMetaData metaData = mIndexMetaData.get(position);
|
||||
final RemoteViewsIndexMetaData metaData = mIndexMetaData.get(position);
|
||||
if (metaData != null) {
|
||||
metaData.set(v, itemId);
|
||||
} else {
|
||||
mIndexMetaData.put(position, new RemoteViewsIndexMetaData(v, itemId));
|
||||
@@ -631,16 +609,10 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
return mTemporaryMetaData;
|
||||
}
|
||||
public RemoteViews getRemoteViewsAt(int position) {
|
||||
if (mIndexRemoteViews.containsKey(position)) {
|
||||
return mIndexRemoteViews.get(position);
|
||||
}
|
||||
return null;
|
||||
return mIndexRemoteViews.get(position);
|
||||
}
|
||||
public RemoteViewsIndexMetaData getMetaDataAt(int position) {
|
||||
if (mIndexMetaData.containsKey(position)) {
|
||||
return mIndexMetaData.get(position);
|
||||
}
|
||||
return null;
|
||||
return mIndexMetaData.get(position);
|
||||
}
|
||||
|
||||
public void commitTemporaryMetaData() {
|
||||
@@ -654,8 +626,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
private int getRemoteViewsBitmapMemoryUsage() {
|
||||
// Calculate the memory usage of all the RemoteViews bitmaps being cached
|
||||
int mem = 0;
|
||||
for (Integer i : mIndexRemoteViews.keySet()) {
|
||||
final RemoteViews v = mIndexRemoteViews.get(i);
|
||||
for (int i = mIndexRemoteViews.size() - 1; i >= 0; i--) {
|
||||
final RemoteViews v = mIndexRemoteViews.valueAt(i);
|
||||
if (v != null) {
|
||||
mem += v.estimateMemoryUsage();
|
||||
}
|
||||
@@ -663,24 +635,25 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
return mem;
|
||||
}
|
||||
|
||||
private int getFarthestPositionFrom(int pos, ArrayList<Integer> visibleWindow) {
|
||||
private int getFarthestPositionFrom(int pos, int[] visibleWindow) {
|
||||
// Find the index farthest away and remove that
|
||||
int maxDist = 0;
|
||||
int maxDistIndex = -1;
|
||||
int maxDistNotVisible = 0;
|
||||
int maxDistIndexNotVisible = -1;
|
||||
for (int i : mIndexRemoteViews.keySet()) {
|
||||
int dist = Math.abs(i-pos);
|
||||
if (dist > maxDistNotVisible && !visibleWindow.contains(i)) {
|
||||
for (int i = mIndexRemoteViews.size() - 1; i >= 0; i--) {
|
||||
int index = mIndexRemoteViews.keyAt(i);
|
||||
int dist = Math.abs(index-pos);
|
||||
if (dist > maxDistNotVisible && Arrays.binarySearch(visibleWindow, index) < 0) {
|
||||
// maxDistNotVisible/maxDistIndexNotVisible will store the index of the
|
||||
// farthest non-visible position
|
||||
maxDistIndexNotVisible = i;
|
||||
maxDistIndexNotVisible = index;
|
||||
maxDistNotVisible = dist;
|
||||
}
|
||||
if (dist >= maxDist) {
|
||||
// maxDist/maxDistIndex will store the index of the farthest position
|
||||
// regardless of whether it is visible or not
|
||||
maxDistIndex = i;
|
||||
maxDistIndex = index;
|
||||
maxDist = dist;
|
||||
}
|
||||
}
|
||||
@@ -692,9 +665,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
|
||||
public void queueRequestedPositionToLoad(int position) {
|
||||
mLastRequestedIndex = position;
|
||||
synchronized (mLoadIndices) {
|
||||
mRequestedIndices.add(position);
|
||||
mLoadIndices.add(position);
|
||||
synchronized (mIndicesToLoad) {
|
||||
mIndicesToLoad.put(position, true);
|
||||
}
|
||||
}
|
||||
public boolean queuePositionsToBePreloadedFromRequestedPosition(int position) {
|
||||
@@ -710,11 +682,13 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
synchronized (mMetaData) {
|
||||
count = mMetaData.count;
|
||||
}
|
||||
synchronized (mLoadIndices) {
|
||||
mLoadIndices.clear();
|
||||
|
||||
// Add all the requested indices
|
||||
mLoadIndices.addAll(mRequestedIndices);
|
||||
synchronized (mIndicesToLoad) {
|
||||
// Remove all indices which have not been previously requested.
|
||||
for (int i = mIndicesToLoad.size() - 1; i >= 0; i--) {
|
||||
if (!mIndicesToLoad.valueAt(i)) {
|
||||
mIndicesToLoad.removeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Add all the preload indices
|
||||
int halfMaxCount = mMaxCount / 2;
|
||||
@@ -723,43 +697,40 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
int effectiveLowerBound = Math.max(0, mPreloadLowerBound);
|
||||
int effectiveUpperBound = Math.min(mPreloadUpperBound, count - 1);
|
||||
for (int i = effectiveLowerBound; i <= effectiveUpperBound; ++i) {
|
||||
mLoadIndices.add(i);
|
||||
if (mIndexRemoteViews.indexOfKey(i) < 0 && !mIndicesToLoad.get(i)) {
|
||||
// If the index has not been requested, and has not been loaded.
|
||||
mIndicesToLoad.put(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
// But remove all the indices that have already been loaded and are cached
|
||||
mLoadIndices.removeAll(mIndexRemoteViews.keySet());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/** Returns the next index to load, and whether that index was directly requested or not */
|
||||
public int[] getNextIndexToLoad() {
|
||||
/** Returns the next index to load */
|
||||
public int getNextIndexToLoad() {
|
||||
// We try and prioritize items that have been requested directly, instead
|
||||
// of items that are loaded as a result of the caching mechanism
|
||||
synchronized (mLoadIndices) {
|
||||
synchronized (mIndicesToLoad) {
|
||||
// Prioritize requested indices to be loaded first
|
||||
if (!mRequestedIndices.isEmpty()) {
|
||||
Integer i = mRequestedIndices.iterator().next();
|
||||
mRequestedIndices.remove(i);
|
||||
mLoadIndices.remove(i);
|
||||
return new int[]{i.intValue(), 1};
|
||||
int index = mIndicesToLoad.indexOfValue(true);
|
||||
if (index < 0) {
|
||||
// Otherwise, preload other indices as necessary
|
||||
index = mIndicesToLoad.indexOfValue(false);
|
||||
}
|
||||
|
||||
// Otherwise, preload other indices as necessary
|
||||
if (!mLoadIndices.isEmpty()) {
|
||||
Integer i = mLoadIndices.iterator().next();
|
||||
mLoadIndices.remove(i);
|
||||
return new int[]{i.intValue(), 0};
|
||||
if (index < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
int key = mIndicesToLoad.keyAt(index);
|
||||
mIndicesToLoad.removeAt(index);
|
||||
return key;
|
||||
}
|
||||
|
||||
return new int[]{-1, 0};
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsRemoteViewAt(int position) {
|
||||
return mIndexRemoteViews.containsKey(position);
|
||||
return mIndexRemoteViews.indexOfKey(position) >= 0;
|
||||
}
|
||||
public boolean containsMetaDataAt(int position) {
|
||||
return mIndexMetaData.containsKey(position);
|
||||
return mIndexMetaData.indexOfKey(position) >= 0;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
@@ -772,9 +743,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
mLastRequestedIndex = -1;
|
||||
mIndexRemoteViews.clear();
|
||||
mIndexMetaData.clear();
|
||||
synchronized (mLoadIndices) {
|
||||
mRequestedIndices.clear();
|
||||
mLoadIndices.clear();
|
||||
synchronized (mIndicesToLoad) {
|
||||
mIndicesToLoad.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -927,8 +897,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
// Get the next index to load
|
||||
int position = -1;
|
||||
synchronized (mCache) {
|
||||
int[] res = mCache.getNextIndexToLoad();
|
||||
position = res[0];
|
||||
position = mCache.getNextIndexToLoad();
|
||||
}
|
||||
if (position > -1) {
|
||||
// Load the item, and notify any existing RemoteViewsFrameLayouts
|
||||
@@ -1033,7 +1002,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
}
|
||||
synchronized (mCache) {
|
||||
if (viewTypeInRange) {
|
||||
ArrayList<Integer> visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
|
||||
int[] visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
|
||||
mVisibleWindowUpperBound, cacheCount);
|
||||
// Cache the RemoteViews we loaded
|
||||
mCache.insert(position, remoteViews, itemId, visibleWindow);
|
||||
@@ -1195,7 +1164,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
// Re-request the new metadata (only after the notification to the factory)
|
||||
updateTemporaryMetaData();
|
||||
int newCount;
|
||||
ArrayList<Integer> visibleWindow;
|
||||
int[] visibleWindow;
|
||||
synchronized(mCache.getTemporaryMetaData()) {
|
||||
newCount = mCache.getTemporaryMetaData().count;
|
||||
visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
|
||||
@@ -1230,26 +1199,33 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
mNotifyDataSetChangedAfterOnServiceConnected = false;
|
||||
}
|
||||
|
||||
private ArrayList<Integer> getVisibleWindow(int lower, int upper, int count) {
|
||||
ArrayList<Integer> window = new ArrayList<Integer>();
|
||||
|
||||
/**
|
||||
* Returns a sorted array of all integers between lower and upper.
|
||||
*/
|
||||
private int[] getVisibleWindow(int lower, int upper, int count) {
|
||||
// In the case that the window is invalid or uninitialized, return an empty window.
|
||||
if ((lower == 0 && upper == 0) || lower < 0 || upper < 0) {
|
||||
return window;
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
int[] window;
|
||||
if (lower <= upper) {
|
||||
for (int i = lower; i <= upper; i++){
|
||||
window.add(i);
|
||||
window = new int[upper + 1 - lower];
|
||||
for (int i = lower, j = 0; i <= upper; i++, j++){
|
||||
window[j] = i;
|
||||
}
|
||||
} else {
|
||||
// If the upper bound is less than the lower bound it means that the visible window
|
||||
// wraps around.
|
||||
for (int i = lower; i < count; i++) {
|
||||
window.add(i);
|
||||
count = Math.max(count, lower);
|
||||
window = new int[count - lower + upper + 1];
|
||||
int j = 0;
|
||||
// Add the entries in sorted order
|
||||
for (int i = 0; i <= upper; i++, j++) {
|
||||
window[j] = i;
|
||||
}
|
||||
for (int i = 0; i <= upper; i++) {
|
||||
window.add(i);
|
||||
for (int i = lower; i < count; i++, j++) {
|
||||
window[j] = i;
|
||||
}
|
||||
}
|
||||
return window;
|
||||
|
||||
Reference in New Issue
Block a user