ViewPager + FragmentStatePagerAdapter + изменение ориентации

У меня есть небольшая проблема: у меня есть ViewPager с некоторыми страницами, и я использую FragmentStatePagerAdapter для обработки данных. В портрете у меня есть, например, 20 страниц для ViewPager и в ландшафте у меня всего 10 страниц для ViewPager. Поэтому при изменении ориентации я создаю новый адаптер с разными данными.

Вот небольшое объяснение, почему: я показываю одно изображение в портрете и два в пейзаже, но всегда все в расчете. Если у меня есть 10 картин, чтобы показать, у меня есть 10 в портрете и 5 в ландшафте (всегда два).

Но теперь у меня странная ошибка: Когда я нахожусь в Пейзаже по индексу 5 и поверните устройство, текущая страница ViewPager будет установлена ​​на 10. Если я верну его снова, я на странице 5. Если я проведу теперь ViewPage на стр. 10, то метод getID элемента никогда не вызывал, и ViewPage показывает мне один портретный портрет, а не два для пейзажа. Как это может произойти? Есть ли кеш в адаптере или ViewPager? В onCreate Activity все новое созданное, адаптер, а также данные (только строки с контуром) для ViewPager. Итак, любая идея, как исправить эту действительно страшную "особенность"?

Вот какой код:

OnCreate:

    mViewPagerAdapter = new ReaderPageViewAdapter(getSupportFragmentManager(), getBaseContext(), mCurrentDocument.mPages, getResources()
                .getConfiguration().orientation);
    mPageReader = (ReaderViewPager) findViewById(R.id.pager);
    mPageReader.setAdapter(mViewPagerAdapter);

адаптер getItem:

    public Fragment getItem(final int index) {
        final PageInfo pageInfo = mPages.get(index);
        final PageFragment pageFragment = (PageFragment) PageFragment
                .instantiate(mContext, pageInfo.mClss.getName(), pageInfo.mArgs);
        return pageFragment;
    }

Если вам нужно что-то еще, просто скажите мне. Благодаря

Ответ 1

Вы можете переопределить FragmentActivity onSaveInstanceState() и не вызывать метод super.onSaveInstanceState() в этом методе.

@Override
protected void onSaveInstanceState(final Bundle outState) {
    // super.onSaveInstanceState(outState);
}

Не используйте mViewPager.setSaveEnabled(false);

у него получилось большое memoryLeak. После каждого изменения ориентации он помещает фрагменты в массив FragmentManager и никогда не очищает его. Таким образом, он увеличивается до более чем 100 мб памяти после многократного изменения ориентации. Использование метода onSaveInstanceState является лучшим способом, я думаю.

Ответ 2

Я также столкнулся с этой проблемой, и я нашел причину.

При повороте экрана на экране FragmentManager будут сохранены все фрагменты вашей активности, которые будут удалены. Если вы используете FragmentStatePagerAdapter, вы можете использовать FragmentManager.getFragments() для проверки количества фрагментов.

Пример: активность имеет 4 фрагмента, после изменения ориентации в 4 раза. Размер списка FragmentManager.getFragments() будет 20!

Я нашел несколько решений:

  • Не называйте super.onSaveInstanceState() вашей деятельности, но это не очень хорошее решение. Фрагменты не могут сохранить состояние и восстановить.

  • Используйте FragmentPagerAdapter вместо FragmentStatePagerAdapter. Но после изменения ориентации фрагменты, которые ViewPager размещались, были пустым (у кого-то еще такая же проблема?). Но я могу удалить все фрагменты в Activity.onCreate, чтобы исправить это. например:

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FragmentManager fm = getSupportFragmentManager();
        List<Fragment> fragments = fm.getFragments();
        if (fragments != null) {
            FragmentTransaction transaction = fm.beginTransaction();
            for (Fragment fragment : fragments) {
                transaction.detach(fragment).remove(fragment);
            }
            transaction.commitNowAllowingStateLoss();
        }
        ...
    

    Но вызов Fragment.onCreateView() дважды.

Я все еще ищу идеальное решение: D

Edit:
Я, наконец, решил проблему, потому что мой ViewPager добавляет после onStart. Когда вы запускаете onStart, The FragmentManager попытается восстановить состояние фрагментов. Я прорисовывался в FragmentManager, Имею этот код:

com/android/support/support-fragment/24.2.1/support-fragment-24.2.1-sources.jar!/android/support/v4/app/FragmentManager.java

Проверьте выделенную строку, f.mContainerId на самом деле это мой идентификатор ViewPager. Затем он попытается добавить представление фрагментов в ViewPager. В моем случае ViewPager еще не добавлен, поэтому он будет закрыт, но состояние фрагментов ATTACHED. И в FragmentPagerAdapter.instantiateItem(). Если фрагмент был добавлен, он просто делает attach фрагмент, но фрагмент уже прикреплен, поэтому его ничего не делать: (

Я добавляю ViewPager в макет операции XML, его исправленный.

Счастливое кодирование: D