jannej
jannej

Reputation: 906

Fragments, ContentProviders and cursors on orientation change

Please help me understand what's happening here.

I have two fragments (A and B) in tabs reading data from different tables, via a CursorLoader and aContentProvider, in a Sqlite-database. With different URIs I can change which table the ContentProvider is quering.

I works as expected when switch between the tabs A and B, unless I switch to B, rotate and switches back to A the wrong cursor is returned. The cursor from fragment B is returned instead of a cursor for fragment A with makes the listView in fragment A to cause a crash. In some way the cursor seems to be reused on a rotation.

Why is this happening and how can I prevent that the wrong cursor is returned?

This is what I have in both fragment A and B. Tried to assing a loader id with no success.

public void onResume() {
    super.onResume();
    getLoaderManager().restartLoader(mLoaderId, null, this);
}

My ContentProvider looks like this:

public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {

    SQLiteDatabase db = dbHelper.getWritableDatabase();
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

    Cursor cursor = null;       

    switch (uriMatcher.match(uri)) {
    case ALL_NEWS:
        queryBuilder.setTables(NewsDb.SQLITE_TABLE);
        cursor = queryBuilder.query(db, projection, selection,
                selectionArgs, null, null, sortOrder);
        break;

    case SINGLE_PLACE:
        queryBuilder.setTables(PlacesDb.SQLITE_TABLE);
        String id = uri.getPathSegments().get(1);
        queryBuilder.appendWhere(PlacesDb.KEY_ID + "=" + id);
        cursor = queryBuilder.query(db, projection, selection,
                selectionArgs, null, null, sortOrder);
        break;

    default:
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }


    return cursor;

}

Upvotes: 1

Views: 548

Answers (1)

Paul Burke
Paul Burke

Reputation: 25584

When using CursorLoader, data changes are automatically observed, so you should definitely remove the restartLoader call in your onResume(). If implemented properly, you should only have to call initLoader in onActivityCreated of the Fragment.

LoaderManager IDs are only scoped to the Fragment, so you should be using a static constant ID. If the Loaders are handled in the Fragments, themselves, it's perfectly fine for every Fragment to have the same Loader ID (even if they're managed by the same Activity).

So in each Fragment:

private static final int LOADER_ID = 0;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // ...

    getLoaderManager().initLoader(LOADER_ID, null, this);
}

Upvotes: 1

Related Questions