Properly manage lifecycle of suggestion cursor
JoinContactLoader loads two cursor in a single load, which is doable,
but not in the way the old code did.
We need to tie the second cursor to the primary cursor in order to
have the framework manage its lifecycle properly.
Bug 6216651
Change-Id: Ia25431832a5b8b94bfd1b319e3d2d4533a4d3840
diff --git a/src/com/android/contacts/list/JoinContactListFragment.java b/src/com/android/contacts/list/JoinContactListFragment.java
index f8fc4cd..1c526a5 100644
--- a/src/com/android/contacts/list/JoinContactListFragment.java
+++ b/src/com/android/contacts/list/JoinContactListFragment.java
@@ -16,6 +16,7 @@
package com.android.contacts.list;
import com.android.contacts.R;
+import com.android.contacts.list.JoinContactLoader.JoinContactLoaderResult;
import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
@@ -78,13 +79,14 @@
break;
}
case JoinContactListAdapter.PARTITION_ALL_CONTACTS: {
- Cursor suggestionsCursor = ((JoinContactLoader) loader).getSuggestionsCursor();
+ Cursor suggestionsCursor = ((JoinContactLoaderResult) data).suggestionCursor;
onContactListLoaded(suggestionsCursor, data);
break;
}
}
}
+ @Override
public void onLoaderReset(Loader<Cursor> loader) {
}
};
diff --git a/src/com/android/contacts/list/JoinContactLoader.java b/src/com/android/contacts/list/JoinContactLoader.java
index c43560e..beb5208 100644
--- a/src/com/android/contacts/list/JoinContactLoader.java
+++ b/src/com/android/contacts/list/JoinContactLoader.java
@@ -18,19 +18,46 @@
import android.content.Context;
import android.content.CursorLoader;
import android.database.Cursor;
-import android.database.MatrixCursor;
+import android.database.CursorWrapper;
import android.net.Uri;
-import android.util.Log;
/**
* A specialized loader for the Join Contacts UI. It executes two queries:
* join suggestions and (optionally) the full contact list.
+ *
+ * This loader also loads the "suggestion" cursor, which can be accessed with:
+ * {@code ((JoinContactLoaderResult) result).suggestionCursor }
*/
public class JoinContactLoader extends CursorLoader {
private String[] mProjection;
private Uri mSuggestionUri;
- private Cursor mSuggestionsCursor;
+
+ /**
+ * Actual returned class. It's guaranteed that this loader always returns an instance of this
+ * class. This class is needed to tie the lifecycle of the second cursor to that of the
+ * primary one.
+ *
+ * Note we can't change the result type of this loader itself, because CursorLoader
+ * extends AsyncTaskLoader<Cursor>, not AsyncTaskLoader<? extends Cursor>
+ */
+ public static class JoinContactLoaderResult extends CursorWrapper {
+ public final Cursor suggestionCursor;
+
+ public JoinContactLoaderResult(Cursor baseCursor, Cursor suggestionCursor) {
+ super(baseCursor);
+ this.suggestionCursor = suggestionCursor;
+ }
+
+ @Override
+ public void close() {
+ try {
+ suggestionCursor.close();
+ } finally {
+ super.close();
+ }
+ }
+ }
public JoinContactLoader(Context context) {
super(context, null, null, null, null, null);
@@ -46,16 +73,12 @@
this.mProjection = projection;
}
- public Cursor getSuggestionsCursor() {
- return mSuggestionsCursor;
- }
-
@Override
public Cursor loadInBackground() {
// First execute the suggestions query, then call super.loadInBackground
// to load the entire list
- mSuggestionsCursor = getContext().getContentResolver()
+ final Cursor suggestionsCursor = getContext().getContentResolver()
.query(mSuggestionUri, mProjection, null, null, null);
- return super.loadInBackground();
+ return new JoinContactLoaderResult(super.loadInBackground(), suggestionsCursor);
}
}
\ No newline at end of file