Подтвердить что ты не робот

Java.lang.IllegalStateException: Фрагмент больше не существует для ключа f1: index 3

Я хочу понять это исключение, чтобы осуществить правильное исправление.

Есть ViewPager, и он использует FragmentStatePagerAdapter для создания экземпляров 2-х фрагментов через getItem и MyFragmentClass.newInstance(...).

Адаптер getItem выглядит так:

@Override
public Fragment getItem(int position) {
    Fragment fragment = null;

    switch(position) {
        case 0:
            fragment = MyFragment2.newInstance(par1);
            break;
        case 1:
            fragment = MyFragment2.newInstance(par2, par3);
            break;
    }
    return fragment;
}

Проблема:

Когда действие уничтожается и создается снова, адаптер снова создается, фрагменты создаются снова с помощью MyFragmentClass.newInstance(...)... но затем в этой строке:

pager.setAdapter(adapter);

Я получаю упомянутое исключение.

Я посмотрел в источнике, где выбрасывается исключение, это:

@Override
public Fragment getFragment(Bundle bundle, String key) {
    int index = bundle.getInt(key, -1);
    if (index == -1) {
        return null;
    }
    if (index >= mActive.size()) {
        throw new IllegalStateException("Fragement no longer exists for key "
                + key + ": index " + index);
    }
    Fragment f = mActive.get(index);
    if (f == null) {
        throw new IllegalStateException("Fragement no longer exists for key "
                + key + ": index " + index);
    }
    return f;
}

Таким образом, пакет передается туда с некоторым состоянием, которое ссылается на мои старые фрагменты, но это не соответствует текущему состоянию (mActive), и mActive исключение.

Я не понимаю, в чем суть этой идеи или каким образом я должен создавать фрагменты.

Я попробовал трюк, полученный из другого контекста:

pager.setOffscreenPageLimit(1);

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

Перехват исключения приводит к тому, что страницы остаются пустыми.

4b9b3361

Ответ 1

Это может помочь -

@Override
public Parcelable saveState() {
    return null;
}

Добавьте строку выше в FragmentStatePagerAdapter.

Ответ 2

Если вы не хотите, чтобы фрагменты были восстановлены, когда они за кадром, вы должны использовать FragmentPagerAdapter, а не FragmentStatePagerAdapter.

Ответ 3

Сведения о выпуске

По умолчанию FragmentStatePagerAdapter сохранит и восстановит состояние ViewPager. При восстановлении, если экземпляр фрагмента уничтожен по какой-либо причине, FragmentManger выдаст это исключение.

Решение:

Чтобы это исправить, нужно переопределить метод restoreState в нашем FragmentStatePagerAdapter и поставить блок try catch. Это предотвратит сбой, а также сохранит состояние фрагмента окна просмотра для обычного случая.

@Override
public void restoreState(Parcelable state, ClassLoader loader) {
    try {
        super.restoreState(state, loader);
    } catch (Exception e) {
        Log.e("TAG", "Error Restore State of Fragment : " + e.getMessage(), e);
    }
}

Примечание. Мы можем использовать FragmentPagerAdapter или Override saveState() и возвращать значение null, также исправляя эту проблему, но viewpager не будет сохранять свое состояние для обычного случая.

Ответ 4

У меня есть борьба по этой проблеме на целый день, но теперь я нашел решение.

private ViewPager _mViewPager;
_mViewPager.setOffscreenPageLimit(5);
//5 is how much page you have.

setOffscreenPageLimit Задайте количество страниц, которые должны быть сохранены в обе стороны текущей страницы иерархии представлений в состоянии ожидания. Страницы, выходящие за этот предел, будут воссозданы из адаптера, если это необходимо.

Ответ 5

Очень хорошо! Поскольку repeat pager.setAdapter(adapter);, когда вызов restoreState вызывает исключение:

Fragment no longer exists for key f0: index 0

мы можем вывести фрагмент RootView

    public void onDestroyView() {
    super.onDestroyView();
    if (isRecyclerRootViewAlways()) {
        mRootView = null;//<--
    }
    mMyFragmentLifecycle.onFragmentDestroyView(this);
}

Ответ 6

использование

getFragmentManager()

во фрагментном адаптере не дочерний фрагментный менеджер

PagerAdapter adapter = new PagerAdapter(getFragmentManager());

Надеюсь, это поможет.