Re-architecting RemoteViewsAdapter internals due to new constraints.

- Respecting the AdapterView/Adapter contract using FrameLayout notification to update individual items
- Initial changes to allow for keeping (currently bitmap only) memory in check when loading numerous RemoteViews
- Fixing issue with leaking activities due to extra service connection references
- Fixing issue with multiple RemoteViewsAdapters being set on the same AdapterView
- Fixing small issue with StackView sometimes requesting indices out of bounds
- Removing background loading, reverting to previous message-queuing method (seems to be performant now)

Change-Id: I42313767aa791dfe35c247c97ae5d64389e6bb4c
This commit is contained in:
Winson Chung
2010-09-23 16:40:28 -07:00
parent 8cb9e9c5c7
commit 3ec9a45c36
4 changed files with 801 additions and 561 deletions

View File

@@ -4367,9 +4367,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public void setRemoteViewsAdapter(Intent intent) {
// Ensure that we don't already have a RemoteViewsAdapter that is bound to an existing
// service handling the specified intent.
Intent.FilterComparison fc = new Intent.FilterComparison(intent);
if (mRemoteAdapter != null && fc.equals(mRemoteAdapter.getRemoteViewsServiceIntent())) {
return;
if (mRemoteAdapter != null) {
Intent.FilterComparison fcNew = new Intent.FilterComparison(intent);
Intent.FilterComparison fcOld = new Intent.FilterComparison(
mRemoteAdapter.getRemoteViewsServiceIntent());
if (fcNew.equals(fcOld)) {
return;
}
}
// Otherwise, create a new RemoteViewsAdapter for binding

View File

@@ -389,7 +389,7 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
int newWindowStartUnbounded = childIndex - mActiveOffset;
int newWindowEndUnbounded = newWindowStartUnbounded + mNumActiveViews - 1;
int newWindowStart = Math.max(0, newWindowStartUnbounded);
int newWindowEnd = Math.min(mAdapter.getCount(), newWindowEndUnbounded);
int newWindowEnd = Math.min(mAdapter.getCount() - 1, newWindowEndUnbounded);
// This section clears out any items that are in our mActiveViews list
// but are outside the effective bounds of our window (this is becomes an issue
@@ -592,18 +592,18 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
*/
private SavedState(Parcel in) {
super(in);
whichChild = in.readInt();
this.whichChild = in.readInt();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(whichChild);
out.writeInt(this.whichChild);
}
@Override
public String toString() {
return "AdapterViewAnimator.SavedState{ whichChild = " + whichChild + " }";
return "AdapterViewAnimator.SavedState{ whichChild = " + this.whichChild + " }";
}
public static final Parcelable.Creator<SavedState> CREATOR
@@ -781,10 +781,13 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
public void setRemoteViewsAdapter(Intent intent) {
// Ensure that we don't already have a RemoteViewsAdapter that is bound to an existing
// service handling the specified intent.
Intent.FilterComparison fc = new Intent.FilterComparison(intent);
if (mRemoteViewsAdapter != null &&
fc.equals(mRemoteViewsAdapter.getRemoteViewsServiceIntent())) {
return;
if (mRemoteViewsAdapter != null) {
Intent.FilterComparison fcNew = new Intent.FilterComparison(intent);
Intent.FilterComparison fcOld = new Intent.FilterComparison(
mRemoteViewsAdapter.getRemoteViewsServiceIntent());
if (fcNew.equals(fcOld)) {
return;
}
}
// Otherwise, create a new RemoteViewsAdapter for binding

View File

@@ -74,6 +74,11 @@ public class RemoteViews implements Parcelable, Filter {
*/
private ArrayList<Action> mActions;
/**
* A class to keep track of memory usage by this RemoteViews
*/
private MemoryUsageCounter mMemoryUsageCounter;
/**
* This flag indicates whether this RemoteViews object is being created from a
@@ -118,6 +123,15 @@ public class RemoteViews implements Parcelable, Filter {
public int describeContents() {
return 0;
}
/**
* Overridden by each class to report on it's own memory usage
*/
public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
// We currently only calculate Bitmap memory usage, so by default, don't do anything
// here
return;
}
}
private class SetEmptyView extends Action {
@@ -525,7 +539,7 @@ public class RemoteViews implements Parcelable, Filter {
}
}
}
int viewId;
boolean targetBackground;
int alpha;
@@ -817,6 +831,35 @@ public class RemoteViews implements Parcelable, Filter {
throw new ActionException(ex);
}
}
@Override
public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
// We currently only calculate Bitmap memory usage
switch (this.type) {
case BITMAP:
if (this.value != null) {
final Bitmap b = (Bitmap) this.value;
final Bitmap.Config c = b.getConfig();
int bpp = 4;
switch (c) {
case ALPHA_8:
bpp = 1;
break;
case RGB_565:
case ARGB_4444:
bpp = 2;
break;
case ARGB_8888:
bpp = 4;
break;
}
counter.bitmapIncrement(b.getWidth() * b.getHeight() * bpp);
}
break;
default:
break;
}
}
}
/**
@@ -854,12 +897,39 @@ public class RemoteViews implements Parcelable, Filter {
}
}
@Override
public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
if (nestedViews != null) {
counter.bitmapIncrement(nestedViews.estimateBitmapMemoryUsage());
}
}
int viewId;
RemoteViews nestedViews;
public final static int TAG = 4;
}
/**
* Simple class used to keep track of memory usage in a RemoteViews.
*
*/
private class MemoryUsageCounter {
public void clear() {
mBitmapHeapMemoryUsage = 0;
}
public void bitmapIncrement(int numBytes) {
mBitmapHeapMemoryUsage += numBytes;
}
public int getBitmapHeapMemoryUsage() {
return mBitmapHeapMemoryUsage;
}
int mBitmapHeapMemoryUsage;
}
/**
* Create a new RemoteViews object that will display the views contained
* in the specified layout file.
@@ -870,6 +940,10 @@ public class RemoteViews implements Parcelable, Filter {
public RemoteViews(String packageName, int layoutId) {
mPackage = packageName;
mLayoutId = layoutId;
// setup the memory usage statistics
mMemoryUsageCounter = new MemoryUsageCounter();
recalculateMemoryUsage();
}
/**
@@ -920,6 +994,10 @@ public class RemoteViews implements Parcelable, Filter {
}
}
}
// setup the memory usage statistics
mMemoryUsageCounter = new MemoryUsageCounter();
recalculateMemoryUsage();
}
@Override
@@ -928,6 +1006,9 @@ public class RemoteViews implements Parcelable, Filter {
if (mActions != null) {
that.mActions = (ArrayList<Action>)mActions.clone();
}
// update the memory usage stats of the cloned RemoteViews
that.recalculateMemoryUsage();
return that;
}
@@ -939,7 +1020,7 @@ public class RemoteViews implements Parcelable, Filter {
return mLayoutId;
}
/**
/*
* This flag indicates whether this RemoteViews object is being created from a
* RemoteViewsService for use as a child of a widget collection. This flag is used
* to determine whether or not certain features are available, in particular,
@@ -950,6 +1031,28 @@ public class RemoteViews implements Parcelable, Filter {
mIsWidgetCollectionChild = isWidgetCollectionChild;
}
/**
* Updates the memory usage statistics.
*/
private void recalculateMemoryUsage() {
mMemoryUsageCounter.clear();
// Accumulate the memory usage for each action
if (mActions != null) {
final int count = mActions.size();
for (int i= 0; i < count; ++i) {
mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter);
}
}
}
/**
* Returns an estimate of the bitmap heap memory usage for this RemoteViews.
*/
int estimateBitmapMemoryUsage() {
return mMemoryUsageCounter.getBitmapHeapMemoryUsage();
}
/**
* Add an action to be executed on the remote side when apply is called.
*
@@ -960,6 +1063,9 @@ public class RemoteViews implements Parcelable, Filter {
mActions = new ArrayList<Action>();
}
mActions.add(a);
// update the memory usage stats
a.updateMemoryUsageEstimate(mMemoryUsageCounter);
}
/**

File diff suppressed because it is too large Load Diff