4

I have registered a CursorLoader, but it is not receiving updates from my ContentProvider

The sequence of events is:

  1. In a Fragment, register the CursorLoader with:

    getLoaderManager().initLoader(LOADER_FAVS_ID, null, this);
    

    Note I am using the support library version ,so this method is android.support.v4.app.Fragment.getLoaderManager()

  2. The CursorLoader is registered, and a Cursor is loaded in the onLoadFinished:

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
            Log.i(TAG, "onLoadFinished");
            switch (loader.getId()) {
            case LOADER_FAVS_ID:
                    Log.i(TAG,
                                    "cursor notification uri: " + cursor.getNotificationUri());
                    mCursorAdapter.swapCursor(cursor);
                    break;
            }
    }
    

    Which Logs cursor notification uri: content://com.myapp.mylocation/db_locations, for example. This is because I made sure to call cursor.setNotificationUri(getContext().getContentResolver(), uri); before returning the Cursor from my ContentProvider. Also note that my content provider returns a MergeCursor.

  3. Some time later, a call is made to update() in my ContentProvider, and the following lines are executed:

    Log.i(TAG,
            "Notifying uri: " + uri.toString());
    getContext().getContentResolver().notifyChange(
            uri, null);
    

    Which Logs Notifying loc uri: content://com.myapp.mylocation/db_locations, the same uri as above.

But onLoadFinished is never called, and my Cursor is never updated. I believe I have followed the advice I can find, all of which is basically this. Why else would onLoadFinished not be called after all of this?

Community
  • 1
  • 1
well
  • 647
  • 1
  • 8
  • 20

1 Answers1

5

Solved it, but since I haven't seen this documented, here's my solution.

I was returning a MergeCursor from my ContentProvider, basically just concatenating a list of cursors. I had

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                    String[] selectionArgs, String sortOrder) {
            // Generate an array of Cursors

            MergeCursor mergCursor = new MergeCursor(cursorArray);

            // notify potential listeners
            mergCursor.setNotificationUri(getContext().getContentResolver(), uri);

            return mergCursor;
    }

And my CursorLoader was never receiving the notification. However, as MergeCursor is basically just an Array of Cursor, you need to set the notification uri on each cursor in your MergeCursor.

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                    String[] selectionArgs, String sortOrder) {
            // Generate an array of Cursors

            // set the notification uris...
            for (Cursor cursor : cursorArray) {
                    cursor.setNotificationUri(getContext().getContentResolver(), uri);
            }

            MergeCursor mergCursor = new MergeCursor(cursorArray);

            return mergCursor;
    }

Now everything works as expected!

well
  • 647
  • 1
  • 8
  • 20