Как я могу обновить свой ListFragment, когда он возвращается к макету из заднего стека?

Сначала я должен упомянуть, что я использую библиотеку ActionBarSherlock для обратной совместимости.

У меня есть активность, которая добавляетListFragment когда это впервые началось. У меня есть обычайLoader который я реализовал и следуетПример AsnycTaskLoader очень близко. мойListFragment реализуетLoaderCallbacks<Cursor> интерфейс. Все соответствующие методы обратного вызова вызываются при добавлении фрагмента (onCreateLoader() , onLoaderFinished() ) и когда он будет заменен (onLoaderReset() ).

мойonActivityCreated(Bundle) Метод выглядит так:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mAccountsDbAdapter = new AccountsDbAdapter(getActivity().getApplicationContext());

    setHasOptionsMenu(true);
    mCursorAdapter = new AccountsCursorAdapter(getActivity()
            .getApplicationContext(), R.layout.list_item_account, null,
            new String[] { DatabaseHelper.KEY_NAME },
            new int[] { R.id.account_name }, 0);

    setListAdapter(mCursorAdapter); 
    getLoaderManager().initLoader(0, null, this);
}

ПозжеListFragment заменяется другим фрагментом B. Когда пользователь нажимает кнопку «Назад», фрагмент B удаляется, а ListFragment добавляется снова. Тем не менее, список пуст и толькоandroid:empty элементы отображаются, и ни один из методов LoaderCallback не вызывается. Я могу использовать отладчик, чтобы определить, чтоgetLoaderManager().initLoader(0, null, this); на самом деле называется, но больше ничего. Когда я изменяю это наgetLoaderManager().restartLoader(0, null, this);обратные вызовы вызываются, но мой список остается пустым (хотя данные есть, представление не обновляется).

Как я могу заставить свой ListFragment обновлять себя, когда он возвращается в макет? Кто-нибудь сталкивался с этим раньше, как вы это исправили?

К вашему сведению, вот мои методы обратного вызова

    @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    return new AccountsCursorLoader(this.getActivity()
            .getApplicationContext());
}

@Override
public void onLoadFinished(Loader<Cursor> loaderCursor, Cursor cursor) {
    mCursorAdapter.swapCursor(cursor);
    mCursorAdapter.notifyDataSetChanged();
}

@Override
public void onLoaderReset(Loader<Cursor> arg0) {
    mCursorAdapter.swapCursor(null);
}

Некоторые заметки:

I cannot use the setListShown(true) methods in the example because I get an IllegalStateException that it cannot be used with a custom content view. My AccountsCursorAdapter extends a SimpleCursorAdapter and modifies only the bindView() method.

Ответы на вопрос(7)

В моем случае я обнаружил, что ListView просто не был нарисован на экране по какой-то причине. Если бы я пошел на домашний экран, а затем снова переключился на активность, все выглядело бы так, как ожидалось. Поэтому я искал метод, чтобы вызвать перерисовку экрана, и я нашел следующее:

Заставить полноэкранную активность переиздать / перерисовать резюме?

Основываясь на ответе на этот вопрос, я добавил следующий код кonActivityCreated() метод моего ListFragment:

getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 0);

С этим кодом все работает как положено. Но это все еще обходной путь, поэтому, если кто-то даст ответ на этот вопрос с лучшим решением или объяснением, я назначу ему награду.

What the Adapter sees:

Причина, по которой вы наблюдаете пустой ListView, заключается в том, чтоthe position of the Cursor that was returned is STILL pointing at the last element, Когда тыswap() курсор на адаптер, адаптер пытается перебрать с помощьюwhile(Cursor.moveToNext()) петля. Поскольку этот цикл всегда оценивает FALSE, ваш ListView дает вам иллюзию пустого курсора.

Распечатайте значенияCursor.getCount() а такжеCursor.getPosition() вonLoadFinished(), Если я прав, эти два значения должны быть равны. Это столкновение индексов создает вышеуказанную иллюзию.

Why does the Adapter see this:

Загрузчики будут повторно использовать Курсор всякий раз, когда это возможно. Если вы запрашиваете загрузчик для набора данных, который не изменился, загрузчик умный и возвращает курсор через onLoadFinished, не делаяany дополнительная работа, даже не устанавливая положение курсора в -1.

ANS ВызовCursor.moveToPosition(-1) вonLoadFinished() вручную, чтобы обойти эту проблему.

Вы пытались заставить загрузчик перезагрузиться в вашей деятельности, только после изменения базового набора данных?

Пытаться:

getLoaderManager().restartLoader(0, null, this);
Решение Вопроса

Эврика !!! Я нашел это (случайно, конечно)

TL;DR;

вAccountsListFragmentТеперь я создаю свой адаптер базы данных (AccountsDatabaseAdapter) вonCreate() метод и закрыть его вonDestroy() метод, и теперь он работает. Ранее я создавал свой адаптер вonActivityCreated() и приближаетсяonDestroyView(), Обратите внимание, что я не имею в видуListAdapter, а скорее к моей базе данныхAccountsDbAdapter.

Attempt at long explanation:

Ну, я делал это, потому что я думал, что получение контекста черезgetActivity() не будет возможно вonCreate() метод. Оказывается, вы можетеgetActivity() даже доonActivityCreated() называется.

Но я не могу объяснить, почему это сейчас работает, потому чтоLoader имеет свойDatabaseAdapter объект, который он использует для извлечения данных. Если бы я догадался, я бы сказал, что один и тот же объект базы данных возвращается для обоих адаптеров базы данных (база данных кэшируется). Что означало бы, что когда я закрою один вonDestroyView()другой также закрывается, и набор данных курсора становится недействительным, что приводит к пустому представлению списка. Загрузчик не перезагружается, потому что считает, что данные не изменились.

Но даже это объяснение не удовлетворяет меня полностью, потому что некоторые из предложенных здесь решений, которые я пробовал как принудительный перезапуск загрузчика каждый раз, не работали. (вloadInBackground() метод, новыйDatabaseAdapter создается каждый раз).

В любом случае, если у вас есть лучшее понимание того, что происходит, пожалуйста, забейте комментарии.

Спасибо всем за помощь в этом!

Поскольку вы используете пользовательский загрузчик, знаете ли вы, если у вас возникают те же проблемы при использовании родного CursorLoader? Если нет, то, возможно, вы можете сравнить ваш Loader с источником Android и посмотреть, делают ли они что-то по-другому?

https://github.com/android/platform_frameworks_base/blob/master/core/java/android/content/CursorLoader.java

Проблема может исходить отgetLoaderManager() который не будет отправлять обратный вызов в правильное место.

Если вы используете ActionBarSherlock, значит, вы на Android 2.x не так ли? Рассматривали ли вы использовать пакет поддержки Android v4?http://developer.android.com/sdk/compatibility-library.html

Вы бы тогда использовалиandroid.support.v4.app.ListFragment и получите свойLoaderManagerпозвонив по телефонуgetActivity().getSupportLoaderManager()

Пытатьсяforceload ():

getLoaderManager().getLoader( 0 ).forceLoad();

Ваш ответ на вопрос