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

Commit 2978e5ad authored by Fred Quintana's avatar Fred Quintana Committed by Android (Google) Code Review
Browse files

Merge "handle a race condition where a cursor receives an inflight onChange...

Merge "handle a race condition where a cursor receives an inflight onChange after the cursor has been closed"
parents aaf12770 866647f9
Loading
Loading
Loading
Loading
+17 −9
Original line number Original line Diff line number Diff line
@@ -33,7 +33,7 @@ import java.util.Observable;
 * The cursor data is accessed by row key and column name via getValue().
 * The cursor data is accessed by row key and column name via getValue().
 */
 */
public class ContentQueryMap extends Observable {
public class ContentQueryMap extends Observable {
    private Cursor mCursor;
    private volatile Cursor mCursor;
    private String[] mColumnNames;
    private String[] mColumnNames;
    private int mKeyColumn;
    private int mKeyColumn;


@@ -71,7 +71,7 @@ public class ContentQueryMap extends Observable {
        // ContentProvider then read it once into the cache. Otherwise the cache will be filled 
        // ContentProvider then read it once into the cache. Otherwise the cache will be filled 
        // automatically.
        // automatically.
        if (!keepUpdated) {
        if (!keepUpdated) {
            readCursorIntoCache();
            readCursorIntoCache(cursor);
        }
        }
    }
    }


@@ -128,27 +128,35 @@ public class ContentQueryMap extends Observable {


    /** Requeries the cursor and reads the contents into the cache */
    /** Requeries the cursor and reads the contents into the cache */
    public void requery() {
    public void requery() {
        final Cursor cursor = mCursor;
        if (cursor == null) {
            // If mCursor is null then it means there was a requery() in flight
            // while another thread called close(), which nulls out mCursor.
            // If this happens ignore the requery() since we are closed anyways.
            return;
        }
        mDirty = false;
        mDirty = false;
        if (!mCursor.requery()) {
        if (!cursor.requery()) {
            throw new IllegalStateException("trying to requery an already closed cursor");
            // again, don't do anything if the cursor is already closed
            return;
        }
        }
        readCursorIntoCache();
        readCursorIntoCache(cursor);
        setChanged();
        setChanged();
        notifyObservers();
        notifyObservers();
    }
    }


    private synchronized void readCursorIntoCache() {
    private synchronized void readCursorIntoCache(Cursor cursor) {
        // Make a new map so old values returned by getRows() are undisturbed.
        // Make a new map so old values returned by getRows() are undisturbed.
        int capacity = mValues != null ? mValues.size() : 0;
        int capacity = mValues != null ? mValues.size() : 0;
        mValues = new HashMap<String, ContentValues>(capacity);
        mValues = new HashMap<String, ContentValues>(capacity);
        while (mCursor.moveToNext()) {
        while (cursor.moveToNext()) {
            ContentValues values = new ContentValues();
            ContentValues values = new ContentValues();
            for (int i = 0; i < mColumnNames.length; i++) {
            for (int i = 0; i < mColumnNames.length; i++) {
                if (i != mKeyColumn) {
                if (i != mKeyColumn) {
                    values.put(mColumnNames[i], mCursor.getString(i));
                    values.put(mColumnNames[i], cursor.getString(i));
                }
                }
            }
            }
            mValues.put(mCursor.getString(mKeyColumn), values);
            mValues.put(cursor.getString(mKeyColumn), values);
        }
        }
    }
    }