Cache the result of the ContactLoader across instances.
Change-Id: I2c7d1c07720118418fbefb751beeaa812e568325
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index ddebf4e..405ba6f 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -23,7 +23,7 @@
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
-import com.google.android.collect.Lists;
+import com.android.contacts.util.UriUtils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -74,11 +74,14 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ /** A short-lived cache that can be set by {@link #cacheResult()} */
+ private static Result sCachedResult = null;
+
private final Uri mRequestedUri;
private Uri mLookupUri;
private boolean mLoadGroupMetaData;
private boolean mLoadStreamItems;
- private final boolean mLoadInvitableAccountTypes;
+ private boolean mLoadInvitableAccountTypes;
private Result mContact;
private ForceLoadContentObserver mObserver;
private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
@@ -130,9 +133,9 @@
private final boolean mStarred;
private final Integer mPresence;
private final ArrayList<Entity> mEntities;
- private final ArrayList<StreamItemEntry> mStreamItems;
+ private ArrayList<StreamItemEntry> mStreamItems;
private final LongSparseArray<DataStatus> mStatuses;
- private final ArrayList<AccountType> mInvitableAccountTypes;
+ private ArrayList<AccountType> mInvitableAccountTypes;
private String mDirectoryDisplayName;
private String mDirectoryType;
@@ -166,7 +169,7 @@
mLookupKey = null;
mId = -1;
mEntities = null;
- mStreamItems = new ArrayList<StreamItemEntry>();
+ mStreamItems = null;
mStatuses = null;
mNameRawContactId = -1;
mDisplayNameSource = DisplayNameSources.UNDEFINED;
@@ -208,7 +211,7 @@
mLookupKey = lookupKey;
mId = id;
mEntities = new ArrayList<Entity>();
- mStreamItems = new ArrayList<StreamItemEntry>();
+ mStreamItems = null;
mStatuses = new LongSparseArray<DataStatus>();
mNameRawContactId = nameRawContactId;
mDisplayNameSource = displayNameSource;
@@ -219,7 +222,7 @@
mPhoneticName = phoneticName;
mStarred = starred;
mPresence = presence;
- mInvitableAccountTypes = Lists.newArrayList();
+ mInvitableAccountTypes = null;
mSendToVoicemail = sendToVoicemail;
mCustomRingtone = customRingtone;
mIsUserProfile = isUserProfile;
@@ -482,13 +485,6 @@
return result;
}
- private void addGroupMetaData(GroupMetaData group) {
- if (mGroups == null) {
- mGroups = new ArrayList<GroupMetaData>();
- }
- mGroups.add(group);
- }
-
public List<GroupMetaData> getGroupMetaData() {
return mGroups;
}
@@ -705,20 +701,39 @@
final ContentResolver resolver = getContext().getContentResolver();
final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
resolver, mLookupUri);
- Result result = loadContactEntity(resolver, uriCurrentFormat);
+ final Result cachedResult = sCachedResult;
+ sCachedResult = null;
+ // Is this the same Uri as what we had before already? In that case, reuse that result
+ final Result result;
+ final boolean resultIsCached;
+ if (cachedResult != null &&
+ UriUtils.areEqual(cachedResult.getLookupUri(), mLookupUri)) {
+ // We are using a cached result from earlier. Below, we should make sure
+ // we are not doing any more network or disc accesses
+ result = cachedResult;
+ resultIsCached = true;
+ } else {
+ result = loadContactEntity(resolver, uriCurrentFormat);
+ resultIsCached = false;
+ }
if (!result.isNotFound()) {
if (result.isDirectoryEntry()) {
- loadDirectoryMetaData(result);
+ if (!resultIsCached) {
+ loadDirectoryMetaData(result);
+ }
} else if (mLoadGroupMetaData) {
- loadGroupMetaData(result);
+ if (result.getGroupMetaData() == null) {
+ loadGroupMetaData(result);
+ }
}
- if (mLoadStreamItems) {
+ if (mLoadStreamItems && result.getStreamItems() == null) {
loadStreamItems(result);
}
- loadPhotoBinaryData(result);
+ if (!resultIsCached) loadPhotoBinaryData(result);
// Note ME profile should never have "Add connection"
- if (mLoadInvitableAccountTypes && !result.isUserProfile()) {
+ if (mLoadInvitableAccountTypes && result.getInvitableAccountTypes() == null &&
+ !result.isUserProfile()) {
loadInvitableAccountTypes(result);
}
}
@@ -858,7 +873,7 @@
}
// Set to mInvitableAccountTypes
- contactData.mInvitableAccountTypes.addAll(result.values());
+ contactData.mInvitableAccountTypes = new ArrayList<AccountType>(result.values());
}
/**
@@ -1053,7 +1068,8 @@
selection.append(")");
}
}
- Cursor cursor = getContext().getContentResolver().query(Groups.CONTENT_URI,
+ final ArrayList<GroupMetaData> groupList = new ArrayList<GroupMetaData>();
+ final Cursor cursor = getContext().getContentResolver().query(Groups.CONTENT_URI,
GroupQuery.COLUMNS, selection.toString(), selectionArgs.toArray(new String[0]),
null);
try {
@@ -1070,13 +1086,14 @@
? false
: cursor.getInt(GroupQuery.FAVORITES) != 0;
- result.addGroupMetaData(new GroupMetaData(
+ groupList.add(new GroupMetaData(
accountName, accountType, dataSet, groupId, title, defaultGroup,
favorites));
}
} finally {
cursor.close();
}
+ result.mGroups = groupList;
}
/**
@@ -1163,7 +1180,7 @@
// Set the sorted stream items on the result.
Collections.sort(streamItems);
- result.mStreamItems.addAll(streamItems);
+ result.mStreamItems = streamItems;
}
@Override
@@ -1248,6 +1265,23 @@
}
}
+ /**
+ * Fully upgrades this ContactLoader to one with all lists fully loaded. When done, the
+ * new result will be delivered
+ */
+ public void upgradeToFullContact() {
+ mLoadGroupMetaData = true;
+ mLoadInvitableAccountTypes = true;
+ mLoadStreamItems = true;
+
+ // Cache the current result, so that we only load the "missing" parts of the contact.
+ cacheResult();
+
+ // Our load parameters have changed, so let's pretend the data has changed. Its the same
+ // thing, essentially.
+ onContentChanged();
+ }
+
public boolean getLoadStreamItems() {
return mLoadStreamItems;
}
@@ -1279,4 +1313,12 @@
unregisterObserver();
mContact = null;
}
+
+ /**
+ * Caches the result, which is useful when we switch from activity to activity, using the same
+ * contact. If the next load is for a different contact, the cached result will be dropped
+ */
+ public void cacheResult() {
+ sCachedResult = mContact;
+ }
}
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index f914aa1..81aa2e8 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -113,6 +113,8 @@
private ImageButton mOpenDetailsPushLayerButton;
private ViewPager mListPager;
+ private ContactLoader mContactLoader;
+
private final ImageViewDrawableSetter mPhotoSetter = new ImageViewDrawableSetter();
/**
@@ -179,6 +181,7 @@
public void onClick(View v) {
final Intent intent = new Intent(Intent.ACTION_VIEW, mLookupUri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mContactLoader.cacheResult();
startActivity(intent);
hide(false);
}
@@ -507,6 +510,7 @@
@Override
public void run() {
mHasFinishedAnimatingIn = true;
+ mContactLoader.upgradeToFullContact();
}
});
}
@@ -518,7 +522,8 @@
if (mLookupUri == null) {
Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
}
- return new ContactLoader(getApplicationContext(), mLookupUri);
+ mContactLoader = new ContactLoader(getApplicationContext(), mLookupUri);
+ return mContactLoader;
}
};