Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 260c3c77 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

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
parent fba54f62
Loading
Loading
Loading
Loading
+33 −13
Original line number Diff line number Diff line
@@ -43763,19 +43763,6 @@
<parameter name="data" type="D">
</parameter>
</method>
<method name="onCancelled"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="deprecated"
 visibility="public"
>
<parameter name="data" type="D">
</parameter>
</method>
<method name="onLoadInBackground"
 return="D"
 abstract="false"
@@ -55609,6 +55596,17 @@
<parameter name="context" type="android.content.Context">
</parameter>
</constructor>
<method name="abandon"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="dataToString"
 return="java.lang.String"
 abstract="false"
@@ -55687,6 +55685,17 @@
 visibility="public"
>
</method>
<method name="isAbandoned"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isReset"
 return="boolean"
 abstract="false"
@@ -55709,6 +55718,17 @@
 visibility="public"
>
</method>
<method name="onAbandon"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="protected"
>
</method>
<method name="onContentChanged"
 return="void"
 abstract="false"
+33 −13
Original line number Diff line number Diff line
@@ -43763,19 +43763,6 @@
<parameter name="data" type="D">
</parameter>
</method>
<method name="onCancelled"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="deprecated"
 visibility="public"
>
<parameter name="data" type="D">
</parameter>
</method>
<method name="onLoadInBackground"
 return="D"
 abstract="false"
@@ -55609,6 +55596,17 @@
<parameter name="context" type="android.content.Context">
</parameter>
</constructor>
<method name="abandon"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="dataToString"
 return="java.lang.String"
 abstract="false"
@@ -55687,6 +55685,17 @@
 visibility="public"
>
</method>
<method name="isAbandoned"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isReset"
 return="boolean"
 abstract="false"
@@ -55709,6 +55718,17 @@
 visibility="public"
>
</method>
<method name="onAbandon"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="protected"
>
</method>
<method name="onContentChanged"
 return="void"
 abstract="false"
+2 −0
Original line number Diff line number Diff line
@@ -587,6 +587,7 @@ class LoaderManagerImpl extends LoaderManager {
                    if (DEBUG) Log.v(TAG, "  Removing last inactive loader: " + info);
                    inactive.mDeliveredData = false;
                    inactive.destroy();
                    info.mLoader.abandon();
                    mInactiveLoaders.put(id, info);
                } else {
                    // We already have an inactive loader for this ID that we are
@@ -617,6 +618,7 @@ class LoaderManagerImpl extends LoaderManager {
                // Keep track of the previous instance of this loader so we can destroy
                // it when the new one completes.
                if (DEBUG) Log.v(TAG, "  Making last loader inactive: " + info);
                info.mLoader.abandon();
                mInactiveLoaders.put(id, info);
            }
        }
+9 −9
Original line number Diff line number Diff line
@@ -169,11 +169,6 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
     * to properly dispose of the result.
     */
    public void onCanceled(D data) {
        onCancelled(data);
    }

    @Deprecated
    public void onCancelled(D data) {
    }

    void executePendingTask() {
@@ -213,6 +208,10 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
        if (mTask != task) {
            if (DEBUG) Slog.v(TAG, "Load complete of old task, trying to cancel");
            dispatchOnCancelled(task, data);
        } else {
            if (isAbandoned()) {
                // This cursor has been abandoned; just cancel the new data.
                onCanceled(data);
            } else {
                mLastLoadCompleteTime = SystemClock.uptimeMillis();
                mTask = null;
@@ -220,6 +219,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
                deliverResult(data);
            }
        }
    }

    /**
     */
+35 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ public class Loader<D> {
    OnLoadCompleteListener<D> mListener;
    Context mContext;
    boolean mStarted = false;
    boolean mAbandoned = false;
    boolean mReset = true;
    boolean mContentChanged = false;

@@ -150,6 +151,15 @@ public class Loader<D> {
        return mStarted;
    }

    /**
     * Return whether this loader has been abandoned.  In this state, the
     * loader <em>must not</em> report any new data, and <em>must</em> 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<D> {
    public final void startLoading() {
        mStarted = true;
        mReset = false;
        mAbandoned = false;
        onStartLoading();
    }

@@ -235,6 +246,28 @@ public class Loader<D> {
    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 <em>must</em> 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<D> {
        onReset();
        mReset = true;
        mStarted = false;
        mAbandoned = false;
        mContentChanged = false;
    }

@@ -327,6 +361,7 @@ public class Loader<D> {
                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