am 956aefb3: am 26ed04ba: Merge "Caching the FixedSizeRemoteViewsCaches across rotation" into jb-dev

* commit '956aefb3c54c5b5a33b7faca8ce5246981995f88':
  Caching the FixedSizeRemoteViewsCaches across rotation
This commit is contained in:
Adam Cohen
2012-07-25 15:05:09 -07:00
committed by Android Git Automerger
3 changed files with 215 additions and 7 deletions

View File

@@ -16,8 +16,6 @@
package android.widget;
import com.android.internal.R;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
@@ -68,6 +66,8 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.R;
import java.util.ArrayList;
import java.util.List;
@@ -1668,6 +1668,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
ss.checkedItemCount = mCheckedItemCount;
if (mRemoteAdapter != null) {
mRemoteAdapter.saveRemoteViewsCache();
}
return ss;
}
@@ -5829,6 +5833,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mDeferNotifyDataSetChanged = false;
// Otherwise, create a new RemoteViewsAdapter for binding
mRemoteAdapter = new RemoteViewsAdapter(getContext(), intent, this);
if (mRemoteAdapter.isDataReady()) {
setAdapter(mRemoteAdapter);
}
}
/**

View File

@@ -813,6 +813,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
if (mRemoteViewsAdapter != null) {
mRemoteViewsAdapter.saveRemoteViewsCache();
}
return new SavedState(superState, mWhichChild);
}
@@ -984,6 +987,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
mDeferNotifyDataSetChanged = false;
// Otherwise, create a new RemoteViewsAdapter for binding
mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this);
if (mRemoteViewsAdapter.isDataReady()) {
setAdapter(mRemoteViewsAdapter);
}
}
@Override

View File

@@ -29,12 +29,16 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.widget.RemoteViewsService.RemoteViewsFactory;
import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory;
@@ -83,6 +87,26 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
private Handler mWorkerQueue;
private Handler mMainQueue;
// We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data
// structures;
private static final HashMap<Pair<Intent.FilterComparison, Integer>, Parcel>
sCachedRemoteViewsCaches = new HashMap<Pair<Intent.FilterComparison, Integer>,
Parcel>();
private static final HashMap<Pair<Intent.FilterComparison, Integer>, Runnable>
sRemoteViewsCacheRemoveRunnables = new HashMap<Pair<Intent.FilterComparison, Integer>,
Runnable>();
private static HandlerThread sCacheRemovalThread;
private static Handler sCacheRemovalQueue;
// We keep the cache around for a duration after onSaveInstanceState for use on re-inflation.
// If a new RemoteViewsAdapter with the same intent / widget id isn't constructed within this
// duration, the cache is dropped.
private static final int REMOTE_VIEWS_CACHE_DURATION = 5000;
// Used to indicate to the AdapterView that it can use this Adapter immediately after
// construction (happens when we have a cached FixedSizeRemoteViewsCache).
private boolean mDataReady = false;
/**
* An interface for the RemoteAdapter to notify other classes when adapters
* are actually connected to/disconnected from their actual services.
@@ -331,7 +355,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
/**
* The meta-data associated with the cache in it's current state.
*/
private static class RemoteViewsMetaData {
private static class RemoteViewsMetaData implements Parcelable {
int count;
int viewTypeCount;
boolean hasStableIds;
@@ -350,6 +374,51 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
reset();
}
public RemoteViewsMetaData(Parcel src) {
count = src.readInt();
viewTypeCount = src.readInt();
hasStableIds = src.readInt() == 0 ? false : true;
mFirstViewHeight = src.readInt();
if (src.readInt() != 0) {
mUserLoadingView = new RemoteViews(src);
}
if (src.readInt() != 0) {
mFirstView = new RemoteViews(src);
}
int count = src.readInt();
for (int i = 0; i < count; i++) {
mTypeIdIndexMap.put(src.readInt(), src.readInt());
}
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(count);
dest.writeInt(viewTypeCount);
dest.writeInt(hasStableIds ? 1 : 0);
dest.writeInt(mFirstViewHeight);
dest.writeInt(mUserLoadingView != null ? 1 : 0);
if (mUserLoadingView != null) {
mUserLoadingView.writeToParcel(dest, flags);
}
dest.writeInt(mFirstView != null ? 1 : 0);
if (mFirstView != null) {
mFirstView.writeToParcel(dest, flags);
}
int count = mTypeIdIndexMap.size();
dest.writeInt(count);
for (Integer key: mTypeIdIndexMap.keySet()) {
dest.writeInt(key);
dest.writeInt(mTypeIdIndexMap.get(key));
}
}
@Override
public int describeContents() {
return 0;
}
public void set(RemoteViewsMetaData d) {
synchronized (d) {
count = d.count;
@@ -460,7 +529,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
/**
* The meta-data associated with a single item in the cache.
*/
private static class RemoteViewsIndexMetaData {
private static class RemoteViewsIndexMetaData implements Parcelable {
int typeId;
long itemId;
boolean isRequested;
@@ -469,6 +538,22 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
set(v, itemId, requested);
}
public RemoteViewsIndexMetaData(Parcel src) {
typeId = src.readInt();
itemId = src.readLong();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(typeId);
dest.writeLong(itemId);
}
@Override
public int describeContents() {
return 0;
}
public void set(RemoteViews v, long id, boolean requested) {
itemId = id;
if (v != null) {
@@ -478,12 +563,14 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
isRequested = requested;
}
}
/**
*
*/
private static class FixedSizeRemoteViewsCache {
private static class FixedSizeRemoteViewsCache implements Parcelable {
private static final String TAG = "FixedSizeRemoteViewsCache";
// The meta data related to all the RemoteViews, ie. count, is stable, etc.
@@ -545,6 +632,57 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
mLoadIndices = new HashSet<Integer>();
}
public FixedSizeRemoteViewsCache(Parcel src) {
mMaxCount = src.readInt();
mMaxCountSlack = src.readInt();
mPreloadLowerBound = src.readInt();
mPreloadUpperBound = src.readInt();
mMetaData = new RemoteViewsMetaData(src);
int count = src.readInt();
mIndexMetaData = new HashMap<Integer, RemoteViewsIndexMetaData>();
for (int i = 0; i < count; i++) {
mIndexMetaData.put(src.readInt(), new RemoteViewsIndexMetaData(src));
}
count = src.readInt();
mIndexRemoteViews = new HashMap<Integer, RemoteViews>();
for (int i = 0; i < count; i++) {
mIndexRemoteViews.put(src.readInt(), new RemoteViews(src));
}
mTemporaryMetaData = new RemoteViewsMetaData();
mRequestedIndices = new HashSet<Integer>();
mLastRequestedIndex = -1;
mLoadIndices = new HashSet<Integer>();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mMaxCount);
dest.writeInt(mMaxCountSlack);
dest.writeInt(mPreloadLowerBound);
dest.writeInt(mPreloadUpperBound);
mMetaData.writeToParcel(dest, 0);
// We write the index data and cache
int count = mIndexMetaData.size();
dest.writeInt(count);
for (Integer key: mIndexMetaData.keySet()) {
dest.writeInt(key);
mIndexMetaData.get(key).writeToParcel(dest, flags);
}
count = mIndexRemoteViews.size();
dest.writeInt(count);
for (Integer key: mIndexRemoteViews.keySet()) {
dest.writeInt(key);
mIndexRemoteViews.get(key).writeToParcel(dest, flags);
}
}
@Override
public int describeContents() {
return 0;
}
public void insert(int position, RemoteViews v, long itemId, boolean isRequested) {
// Trim the cache if we go beyond the count
if (mIndexRemoteViews.size() >= mMaxCount) {
@@ -747,11 +885,30 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
mWorkerQueue = new Handler(mWorkerThread.getLooper());
mMainQueue = new Handler(Looper.myLooper(), this);
if (sCacheRemovalThread == null) {
sCacheRemovalThread = new HandlerThread("RemoteViewsAdapter-cachePruner");
sCacheRemovalThread.start();
sCacheRemovalQueue = new Handler(sCacheRemovalThread.getLooper());
}
// Initialize the cache and the service connection on startup
mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize);
mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback);
mServiceConnection = new RemoteViewsAdapterServiceConnection(this);
requestBindService();
Pair<Intent.FilterComparison, Integer> key = new Pair<Intent.FilterComparison, Integer>
(new Intent.FilterComparison(mIntent), mAppWidgetId);
synchronized(sCachedRemoteViewsCaches) {
if (sCachedRemoteViewsCaches.containsKey(key)) {
Parcel src = sCachedRemoteViewsCaches.get(key);
src.setDataPosition(0);
mCache = new FixedSizeRemoteViewsCache(src);
mDataReady = true;
} else {
mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize);
requestBindService();
}
}
}
@Override
@@ -765,6 +922,44 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
}
public boolean isDataReady() {
return mDataReady;
}
public void saveRemoteViewsCache() {
final Pair<Intent.FilterComparison, Integer> key = new Pair<Intent.FilterComparison,
Integer> (new Intent.FilterComparison(mIntent), mAppWidgetId);
synchronized(sCachedRemoteViewsCaches) {
// If we already have a remove runnable posted for this key, remove it.
if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) {
sCacheRemovalQueue.removeCallbacks(sRemoteViewsCacheRemoveRunnables.get(key));
sRemoteViewsCacheRemoveRunnables.remove(key);
}
Parcel p = Parcel.obtain();
synchronized(mCache) {
mCache.writeToParcel(p, 0);
}
sCachedRemoteViewsCaches.put(key, p);
Runnable r = new Runnable() {
@Override
public void run() {
synchronized (sCachedRemoteViewsCaches) {
if (sCachedRemoteViewsCaches.containsKey(key)) {
sCachedRemoteViewsCaches.remove(key);
}
if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) {
sRemoteViewsCacheRemoveRunnables.remove(key);
}
}
}
};
sRemoteViewsCacheRemoveRunnables.put(key, r);
sCacheRemovalQueue.postDelayed(r, REMOTE_VIEWS_CACHE_DURATION);
}
}
private void loadNextIndexInBackground() {
mWorkerQueue.post(new Runnable() {
@Override