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

Commit ca614f78 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix a bug where we could lose a loader content change.

If AsyncTaskLoader starts a background update due to a
content change, and that update is cancelled, we drop the
data when it finally arrives and forget that the content changed.
If we later come back to the loader, we then end up showing
stale data because we don't know that we still need to update
due to the old content change.

This change adds a couple new APIs to Loader to deal with the
time between when you ask for whether there is a content change
and finally either commit the data or cancel the update.
AsyncTaskLoader is changed to make use of this so that it doesn't
lose changes.

Change-Id: I3866236b1c22bb9138f2d9f6032b126aeaee2e6e
parent 5d122d96
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -6159,6 +6159,7 @@ package android.content {
    ctor public Loader(android.content.Context);
    method public void abandon();
    method public boolean cancelLoad();
    method public void commitContentChanged();
    method public java.lang.String dataToString(D);
    method public void deliverCancellation();
    method public void deliverResult(D);
@@ -6179,6 +6180,7 @@ package android.content {
    method public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
    method public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
    method public void reset();
    method public void rollbackContentChanged();
    method public final void startLoading();
    method public void stopLoading();
    method public boolean takeContentChanged();
+2 −0
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
        onCanceled(data);
        if (mCancellingTask == task) {
            if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
            rollbackContentChanged();
            mLastLoadCompleteTime = SystemClock.uptimeMillis();
            mCancellingTask = null;
            if (DEBUG) Slog.v(TAG, "Delivering cancellation");
@@ -248,6 +249,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
                // This cursor has been abandoned; just cancel the new data.
                onCanceled(data);
            } else {
                commitContentChanged();
                mLastLoadCompleteTime = SystemClock.uptimeMillis();
                mTask = null;
                if (DEBUG) Slog.v(TAG, "Delivering result");
+37 −5
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ public class Loader<D> {
    boolean mAbandoned = false;
    boolean mReset = true;
    boolean mContentChanged = false;
    boolean mProcessingChange = false;

    /**
     * An implementation of a ContentObserver that takes care of connecting
@@ -439,6 +440,7 @@ public class Loader<D> {
        mStarted = false;
        mAbandoned = false;
        mContentChanged = false;
        mProcessingChange = false;
    }

    /**
@@ -458,9 +460,34 @@ public class Loader<D> {
    public boolean takeContentChanged() {
        boolean res = mContentChanged;
        mContentChanged = false;
        mProcessingChange |= res;
        return res;
    }

    /**
     * Commit that you have actually fully processed a content change that
     * was returned by {@link #takeContentChanged}.  This is for use with
     * {@link #rollbackContentChanged()} to handle situations where a load
     * is cancelled.  Call this when you have completely processed a load
     * without it being cancelled.
     */
    public void commitContentChanged() {
        mProcessingChange = false;
    }

    /**
     * Report that you have abandoned the processing of a content change that
     * was returned by {@link #takeContentChanged()} and would like to rollback
     * to the state where there is again a pending content change.  This is
     * to handle the case where a data load due to a content change has been
     * canceled before its data was delivered back to the loader.
     */
    public void rollbackContentChanged() {
        if (mProcessingChange) {
            mContentChanged = true;
        }
    }

    /**
     * Called when {@link ForceLoadContentObserver} detects a change.  The
     * default implementation checks to see if the loader is currently started;
@@ -512,9 +539,14 @@ public class Loader<D> {
    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
        writer.print(prefix); writer.print("mId="); writer.print(mId);
                writer.print(" mListener="); writer.println(mListener);
        if (mStarted || mContentChanged || mProcessingChange) {
            writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
                    writer.print(" mContentChanged="); writer.print(mContentChanged);
                writer.print(" mAbandoned="); writer.print(mAbandoned);
                    writer.print(" mProcessingChange="); writer.println(mProcessingChange);
        }
        if (mAbandoned || mReset) {
            writer.print(prefix); writer.print("mAbandoned="); writer.print(mAbandoned);
                    writer.print(" mReset="); writer.println(mReset);
        }
    }
}
 No newline at end of file