From 260c3c77d9b340164e055f87002c64d78da6e836 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Sun, 30 Jan 2011 16:55:55 -0800 Subject: [PATCH] Fix issue #3381489: IllegalStateException: attempt to re-open... ...an already-closed object: android.database.sqlite.SQLiteQuery It turns out there is a state we are missing -- the loader is still needed, but in the inactive list. In this case the loader needs to continue holding on to its current data, and not deliver any new data (which would result in it releasing its old data). This introduces the new state to Loader, and uses it in AsyncTaskLoader so all subclasses of that should get the new correct behavior. A further improvement would be to unregister CursorLoader's content listener when going in to this state, but that can wait for later. Change-Id: I6d30173b94f8e30b5be31d018accd328cc3388ec --- api/11.xml | 46 +++++++++++++------ api/current.xml | 46 +++++++++++++------ core/java/android/app/LoaderManager.java | 2 + .../java/android/content/AsyncTaskLoader.java | 18 ++++---- core/java/android/content/Loader.java | 35 ++++++++++++++ 5 files changed, 112 insertions(+), 35 deletions(-) diff --git a/api/11.xml b/api/11.xml index 5d428457e3c95..16984b53f2fdc 100644 --- a/api/11.xml +++ b/api/11.xml @@ -43763,19 +43763,6 @@ - - - - + + + + + + - - - - + + + + + + extends Loader { * to properly dispose of the result. */ public void onCanceled(D data) { - onCancelled(data); - } - - @Deprecated - public void onCancelled(D data) { } void executePendingTask() { @@ -214,10 +209,15 @@ public abstract class AsyncTaskLoader extends Loader { if (DEBUG) Slog.v(TAG, "Load complete of old task, trying to cancel"); dispatchOnCancelled(task, data); } else { - mLastLoadCompleteTime = SystemClock.uptimeMillis(); - mTask = null; - if (DEBUG) Slog.v(TAG, "Delivering result"); - deliverResult(data); + if (isAbandoned()) { + // This cursor has been abandoned; just cancel the new data. + onCanceled(data); + } else { + mLastLoadCompleteTime = SystemClock.uptimeMillis(); + mTask = null; + if (DEBUG) Slog.v(TAG, "Delivering result"); + deliverResult(data); + } } } diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java index d63fe6915b8c0..a9d611768b460 100644 --- a/core/java/android/content/Loader.java +++ b/core/java/android/content/Loader.java @@ -45,6 +45,7 @@ public class Loader { OnLoadCompleteListener mListener; Context mContext; boolean mStarted = false; + boolean mAbandoned = false; boolean mReset = true; boolean mContentChanged = false; @@ -150,6 +151,15 @@ public class Loader { return mStarted; } + /** + * Return whether this loader has been abandoned. In this state, the + * loader must not report any new data, and must keep + * its last reported data valid until it is finally reset. + */ + public boolean isAbandoned() { + return mAbandoned; + } + /** * Return whether this load has been reset. That is, either the loader * has not yet been started for the first time, or its {@link #reset()} @@ -177,6 +187,7 @@ public class Loader { public final void startLoading() { mStarted = true; mReset = false; + mAbandoned = false; onStartLoading(); } @@ -235,6 +246,28 @@ public class Loader { protected void onStopLoading() { } + /** + * Tell the Loader that it is being abandoned. This is called prior + * to {@link #reset} to have it retain its current data but not report + * any new data. + */ + public void abandon() { + mAbandoned = true; + onAbandon(); + } + + /** + * Subclasses implement this to take care of being abandoned. This is + * an optional intermediate state prior to {@link #onReset()} -- it means that + * the client is no longer interested in any new data from the loader, + * so the loader must not report any further updates. However, the + * loader must keep its last reported data valid until the final + * {@link #onReset()} happens. You can retrieve the current abandoned + * state with {@link #isAbandoned}. + */ + protected void onAbandon() { + } + /** * Resets the state of the Loader. The Loader should at this point free * all of its resources, since it may never be called again; however, its @@ -251,6 +284,7 @@ public class Loader { onReset(); mReset = true; mStarted = false; + mAbandoned = false; mContentChanged = false; } @@ -327,6 +361,7 @@ public class Loader { writer.print(" mListener="); writer.println(mListener); writer.print(prefix); writer.print("mStarted="); writer.print(mStarted); writer.print(" mContentChanged="); writer.print(mContentChanged); + writer.print(" mAbandoned="); writer.print(mAbandoned); writer.print(" mReset="); writer.println(mReset); } } \ No newline at end of file