Фрагменты, ContentProviders и курсоры при изменении ориентации

Пожалуйста, помогите мне понять, что здесь происходит.

У меня есть два фрагмента (A и B) на вкладках, читающих данные из разных таблиц через CursorLoader и aContentProvider в базе данных Sqlite. С разными URI я могу изменить, какую таблицу запрашивает ContentProvider.

I работает, как и ожидалось, при переключении между вкладками A и B, если я не переключаюсь на B, не поворачиваю и не переключаюсь обратно на A, возвращается неправильный курсор. Курсор из фрагмента B возвращается вместо курсора для фрагмента A, что приводит к сбою listView во фрагменте A. Каким-то образом кажется, что курсор повторно используется при вращении.

Почему это происходит и как я могу предотвратить возврат неправильного курсора?

Это то, что у меня есть как во фрагменте A, так и во фрагменте B. Безуспешно пытался определить идентификатор загрузчика.

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

Мой ContentProvider выглядит так:

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;

}

person jannej    schedule 24.11.2013    source источник
comment
1. Почему вы перезапускаете Loader в onResume()? При использовании CursorLoader данные автоматически обновляются. 2. Используете ли вы Loader в Activity? Если да, то почему?   -  person Paul Burke    schedule 25.11.2013
comment
1. Хм. Хороший вопрос. В основном я следую этому руководству: sunil-android.blogspot .se/2013/04/ 2. Я не использую загрузчик в Activity, а только запускаю загрузчик onCreateView() в каждом фрагменте следующим образом: developer.android.com/training/load-data-background/   -  person jannej    schedule 25.11.2013
comment
Ты еще там? Я разместил ответ.   -  person Paul Burke    schedule 27.11.2013
comment
Извините за мое отсутствие. Кажется, я нашел причину своих проблем. Фрагменты инициализировались дважды при вращении из-за saveState в основной активности (много вопросов по этому поводу здесь) и так далее. Но все же у вас есть некоторые важные моменты, которые помогли в правильном направлении. Спасибо.   -  person jannej    schedule 27.11.2013


Ответы (1)


При использовании CursorLoader автоматически отслеживаются изменения данных, поэтому вам обязательно следует удалить вызов restartLoader в вашем onResume(). Если реализовано правильно, вам нужно будет вызывать только initLoader в onActivityCreated из Fragment.

Идентификаторы LoaderManager привязаны только к Fragment, поэтому вам следует использовать идентификатор static constant. Если Loaders обрабатываются сами в Fragments, совершенно нормально, если каждый Fragment будет иметь один и тот же идентификатор Loader (даже если ими управляет один и тот же Activity).

Итак, в каждом Fragment:

private static final int LOADER_ID = 0;

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

    // ...

    getLoaderManager().initLoader(LOADER_ID, null, this);
}
person Paul Burke    schedule 25.11.2013