Making requested indices the last to be pruned when we hit cache memory limits. (3368863)
- Also tweaking disconnect delay, cache size, and memory limit Change-Id: If67188dcb363e5a2fbc02736f82bfd783af02533
This commit is contained in:
@@ -48,11 +48,11 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
private static final String TAG = "RemoteViewsAdapter";
|
private static final String TAG = "RemoteViewsAdapter";
|
||||||
|
|
||||||
// The max number of items in the cache
|
// The max number of items in the cache
|
||||||
private static final int sDefaultCacheSize = 50;
|
private static final int sDefaultCacheSize = 40;
|
||||||
// The delay (in millis) to wait until attempting to unbind from a service after a request.
|
// The delay (in millis) to wait until attempting to unbind from a service after a request.
|
||||||
// This ensures that we don't stay continually bound to the service and that it can be destroyed
|
// This ensures that we don't stay continually bound to the service and that it can be destroyed
|
||||||
// if we need the memory elsewhere in the system.
|
// if we need the memory elsewhere in the system.
|
||||||
private static final int sUnbindServiceDelay = 1000;
|
private static final int sUnbindServiceDelay = 5000;
|
||||||
// Type defs for controlling different messages across the main and worker message queues
|
// Type defs for controlling different messages across the main and worker message queues
|
||||||
private static final int sDefaultMessageType = 0;
|
private static final int sDefaultMessageType = 0;
|
||||||
private static final int sUnbindServiceMessageType = 1;
|
private static final int sUnbindServiceMessageType = 1;
|
||||||
@@ -421,17 +421,19 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
private class RemoteViewsIndexMetaData {
|
private class RemoteViewsIndexMetaData {
|
||||||
int typeId;
|
int typeId;
|
||||||
long itemId;
|
long itemId;
|
||||||
|
boolean isRequested;
|
||||||
|
|
||||||
public RemoteViewsIndexMetaData(RemoteViews v, long itemId) {
|
public RemoteViewsIndexMetaData(RemoteViews v, long itemId, boolean requested) {
|
||||||
set(v, itemId);
|
set(v, itemId, requested);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(RemoteViews v, long id) {
|
public void set(RemoteViews v, long id, boolean requested) {
|
||||||
itemId = id;
|
itemId = id;
|
||||||
if (v != null)
|
if (v != null)
|
||||||
typeId = v.getLayoutId();
|
typeId = v.getLayoutId();
|
||||||
else
|
else
|
||||||
typeId = 0;
|
typeId = 0;
|
||||||
|
isRequested = requested;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,6 +463,10 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
// The set of indices that have been explicitly requested by the collection view
|
// The set of indices that have been explicitly requested by the collection view
|
||||||
private HashSet<Integer> mRequestedIndices;
|
private HashSet<Integer> mRequestedIndices;
|
||||||
|
|
||||||
|
// 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
|
// The set of indices to load, including those explicitly requested, as well as those
|
||||||
// determined by the preloading algorithm to be prefetched
|
// determined by the preloading algorithm to be prefetched
|
||||||
private HashSet<Integer> mLoadIndices;
|
private HashSet<Integer> mLoadIndices;
|
||||||
@@ -477,7 +483,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
private int mMaxCount;
|
private int mMaxCount;
|
||||||
private int mMaxCountSlack;
|
private int mMaxCountSlack;
|
||||||
private static final float sMaxCountSlackPercent = 0.75f;
|
private static final float sMaxCountSlackPercent = 0.75f;
|
||||||
private static final int sMaxMemoryUsage = 1024 * 1024;
|
private static final int sMaxMemoryLimitInBytes = 2 * 1024 * 1024;
|
||||||
|
|
||||||
public FixedSizeRemoteViewsCache(int maxCacheSize) {
|
public FixedSizeRemoteViewsCache(int maxCacheSize) {
|
||||||
mMaxCount = maxCacheSize;
|
mMaxCount = maxCacheSize;
|
||||||
@@ -489,31 +495,33 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
mIndexMetaData = new HashMap<Integer, RemoteViewsIndexMetaData>();
|
mIndexMetaData = new HashMap<Integer, RemoteViewsIndexMetaData>();
|
||||||
mIndexRemoteViews = new HashMap<Integer, RemoteViews>();
|
mIndexRemoteViews = new HashMap<Integer, RemoteViews>();
|
||||||
mRequestedIndices = new HashSet<Integer>();
|
mRequestedIndices = new HashSet<Integer>();
|
||||||
|
mLastRequestedIndex = -1;
|
||||||
mLoadIndices = new HashSet<Integer>();
|
mLoadIndices = new HashSet<Integer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insert(int position, RemoteViews v, long itemId) {
|
public void insert(int position, RemoteViews v, long itemId, boolean isRequested) {
|
||||||
// Trim the cache if we go beyond the count
|
// Trim the cache if we go beyond the count
|
||||||
if (mIndexRemoteViews.size() >= mMaxCount) {
|
if (mIndexRemoteViews.size() >= mMaxCount) {
|
||||||
mIndexRemoteViews.remove(getFarthestPositionFrom(position));
|
mIndexRemoteViews.remove(getFarthestPositionFrom(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim the cache if we go beyond the available memory size constraints
|
// Trim the cache if we go beyond the available memory size constraints
|
||||||
while (getRemoteViewsBitmapMemoryUsage() >= sMaxMemoryUsage) {
|
int pruneFromPosition = (mLastRequestedIndex > -1) ? mLastRequestedIndex : position;
|
||||||
|
while (getRemoteViewsBitmapMemoryUsage() >= sMaxMemoryLimitInBytes) {
|
||||||
// Note: This is currently the most naive mechanism for deciding what to prune when
|
// Note: This is currently the most naive mechanism for deciding what to prune when
|
||||||
// we hit the memory limit. In the future, we may want to calculate which index to
|
// we hit the memory limit. In the future, we may want to calculate which index to
|
||||||
// remove based on both its position as well as it's current memory usage, as well
|
// remove based on both its position as well as it's current memory usage, as well
|
||||||
// as whether it was directly requested vs. whether it was preloaded by our caching
|
// as whether it was directly requested vs. whether it was preloaded by our caching
|
||||||
// mechanism.
|
// mechanism.
|
||||||
mIndexRemoteViews.remove(getFarthestPositionFrom(position));
|
mIndexRemoteViews.remove(getFarthestPositionFrom(pruneFromPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the metadata cache
|
// Update the metadata cache
|
||||||
if (mIndexMetaData.containsKey(position)) {
|
if (mIndexMetaData.containsKey(position)) {
|
||||||
final RemoteViewsIndexMetaData metaData = mIndexMetaData.get(position);
|
final RemoteViewsIndexMetaData metaData = mIndexMetaData.get(position);
|
||||||
metaData.set(v, itemId);
|
metaData.set(v, itemId, isRequested);
|
||||||
} else {
|
} else {
|
||||||
mIndexMetaData.put(position, new RemoteViewsIndexMetaData(v, itemId));
|
mIndexMetaData.put(position, new RemoteViewsIndexMetaData(v, itemId, isRequested));
|
||||||
}
|
}
|
||||||
mIndexRemoteViews.put(position, v);
|
mIndexRemoteViews.put(position, v);
|
||||||
}
|
}
|
||||||
@@ -560,17 +568,31 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
// Find the index farthest away and remove that
|
// Find the index farthest away and remove that
|
||||||
int maxDist = 0;
|
int maxDist = 0;
|
||||||
int maxDistIndex = -1;
|
int maxDistIndex = -1;
|
||||||
|
int maxDistNonRequested = 0;
|
||||||
|
int maxDistIndexNonRequested = -1;
|
||||||
for (int i : mIndexRemoteViews.keySet()) {
|
for (int i : mIndexRemoteViews.keySet()) {
|
||||||
int dist = Math.abs(i-pos);
|
int dist = Math.abs(i-pos);
|
||||||
|
if (dist > maxDistNonRequested && !mIndexMetaData.get(i).isRequested) {
|
||||||
|
// maxDistNonRequested/maxDistIndexNonRequested will store the index of the
|
||||||
|
// farthest non-requested position
|
||||||
|
maxDistIndexNonRequested = i;
|
||||||
|
maxDistNonRequested = dist;
|
||||||
|
}
|
||||||
if (dist > maxDist) {
|
if (dist > maxDist) {
|
||||||
|
// maxDist/maxDistIndex will store the index of the farthest position
|
||||||
|
// regardless of whether it was directly requested or not
|
||||||
maxDistIndex = i;
|
maxDistIndex = i;
|
||||||
maxDist = dist;
|
maxDist = dist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (maxDistIndexNonRequested > -1) {
|
||||||
|
return maxDistIndexNonRequested;
|
||||||
|
}
|
||||||
return maxDistIndex;
|
return maxDistIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void queueRequestedPositionToLoad(int position) {
|
public void queueRequestedPositionToLoad(int position) {
|
||||||
|
mLastRequestedIndex = position;
|
||||||
synchronized (mLoadIndices) {
|
synchronized (mLoadIndices) {
|
||||||
mRequestedIndices.add(position);
|
mRequestedIndices.add(position);
|
||||||
mLoadIndices.add(position);
|
mLoadIndices.add(position);
|
||||||
@@ -610,7 +632,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public int getNextIndexToLoad() {
|
/** Returns the next index to load, and whether that index was directly requested or not */
|
||||||
|
public int[] getNextIndexToLoad() {
|
||||||
// We try and prioritize items that have been requested directly, instead
|
// We try and prioritize items that have been requested directly, instead
|
||||||
// of items that are loaded as a result of the caching mechanism
|
// of items that are loaded as a result of the caching mechanism
|
||||||
synchronized (mLoadIndices) {
|
synchronized (mLoadIndices) {
|
||||||
@@ -619,17 +642,17 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
Integer i = mRequestedIndices.iterator().next();
|
Integer i = mRequestedIndices.iterator().next();
|
||||||
mRequestedIndices.remove(i);
|
mRequestedIndices.remove(i);
|
||||||
mLoadIndices.remove(i);
|
mLoadIndices.remove(i);
|
||||||
return i.intValue();
|
return new int[]{i.intValue(), 1};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, preload other indices as necessary
|
// Otherwise, preload other indices as necessary
|
||||||
if (!mLoadIndices.isEmpty()) {
|
if (!mLoadIndices.isEmpty()) {
|
||||||
Integer i = mLoadIndices.iterator().next();
|
Integer i = mLoadIndices.iterator().next();
|
||||||
mLoadIndices.remove(i);
|
mLoadIndices.remove(i);
|
||||||
return i.intValue();
|
return new int[]{i.intValue(), 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return new int[]{-1, 0};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,6 +670,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
|
|
||||||
mPreloadLowerBound = 0;
|
mPreloadLowerBound = 0;
|
||||||
mPreloadUpperBound = -1;
|
mPreloadUpperBound = -1;
|
||||||
|
mLastRequestedIndex = -1;
|
||||||
mIndexRemoteViews.clear();
|
mIndexRemoteViews.clear();
|
||||||
mIndexMetaData.clear();
|
mIndexMetaData.clear();
|
||||||
synchronized (mLoadIndices) {
|
synchronized (mLoadIndices) {
|
||||||
@@ -691,12 +715,15 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
if (mServiceConnection.isConnected()) {
|
if (mServiceConnection.isConnected()) {
|
||||||
// Get the next index to load
|
// Get the next index to load
|
||||||
int position = -1;
|
int position = -1;
|
||||||
|
boolean isRequested = false;
|
||||||
synchronized (mCache) {
|
synchronized (mCache) {
|
||||||
position = mCache.getNextIndexToLoad();
|
int[] res = mCache.getNextIndexToLoad();
|
||||||
|
position = res[0];
|
||||||
|
isRequested = res[1] > 0;
|
||||||
}
|
}
|
||||||
if (position > -1) {
|
if (position > -1) {
|
||||||
// Load the item, and notify any existing RemoteViewsFrameLayouts
|
// Load the item, and notify any existing RemoteViewsFrameLayouts
|
||||||
updateRemoteViews(position);
|
updateRemoteViews(position, isRequested);
|
||||||
|
|
||||||
// Queue up for the next one to load
|
// Queue up for the next one to load
|
||||||
loadNextIndexInBackground();
|
loadNextIndexInBackground();
|
||||||
@@ -756,7 +783,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRemoteViews(final int position) {
|
private void updateRemoteViews(final int position, boolean isRequested) {
|
||||||
if (!mServiceConnection.isConnected()) return;
|
if (!mServiceConnection.isConnected()) return;
|
||||||
IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
|
IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
|
||||||
|
|
||||||
@@ -784,7 +811,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
}
|
}
|
||||||
synchronized (mCache) {
|
synchronized (mCache) {
|
||||||
// Cache the RemoteViews we loaded
|
// Cache the RemoteViews we loaded
|
||||||
mCache.insert(position, remoteViews, itemId);
|
mCache.insert(position, remoteViews, itemId, isRequested);
|
||||||
|
|
||||||
// Notify all the views that we have previously returned for this index that
|
// Notify all the views that we have previously returned for this index that
|
||||||
// there is new data for it.
|
// there is new data for it.
|
||||||
|
|||||||
Reference in New Issue
Block a user