ViewPager + FragmentStatePagerAdapter + изменение ориентации
У меня есть небольшая проблема: у меня есть ViewPager с некоторыми страницами, и я использую FragmentStatePagerAdapter для обработки данных. В портретном режиме у меня есть, например, 20 страниц для ViewPager, а в альбомной ориентации у меня всего 10 страниц для ViewPager. Поэтому при изменении ориентации я создаю новый адаптер с другими данными.
Вот небольшое объяснение, почему: я показываю одно изображение в портретной и два в альбомной, но всегда все в счет. Если у меня есть 10 фотографий, чтобы показать, у меня есть 10 в портретной и 5 в альбомной (всегда две).
Но теперь у меня странная ошибка: когда я нахожусь в альбомной ориентации с индексом 5 и поворачиваю устройство, текущая страница ViewPager устанавливается на 10. Если я снова включаю его, я нахожусь на странице 5. Если я проведу ViewPage сейчас на страницу 10 метод getItem адаптера никогда не вызывается, и ViewPage показывает мне одно портретное изображение, а не два для альбомной ориентации. Как это может случиться? Есть ли кеш в адаптере или ViewPager? В onCreate of 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;
}
Если вам нужно что-то еще, просто скажите мне. Спасибо
3 ответа
Вы можете переопределить FragmentActivity для onSaveInstanceState() и не вызывать super.onSaveInstanceState() в методе.
@Override
protected void onSaveInstanceState(final Bundle outState) {
// super.onSaveInstanceState(outState);
}
Не использовать mViewPager.setSaveEnabled(false);
это закончилось большой утечкой памяти. После каждого изменения ориентации он помещает фрагменты в массив FragmentManager и никогда не очищает его. Таким образом, после многократного изменения ориентации использование памяти превышает 100 МБ. Я думаю, что использование метода onSaveInstanceState - лучший способ.
У меня тоже возникла эта проблема и я нашел причину.
Когда-либо экран вращался, FragmentManager
сохранит все ваши фрагменты активности, не удалит фрагменты при использовании FragmentStatePagerAdapter
, Ты можешь использовать FragmentManager.getFragments()
проверить количество фрагментов.
Пример: у действия есть 4 фрагмента, после 4-кратного изменения ориентации, список FragmentManager.getFragments()
размер будет 20!
Я нашел несколько решений:
Не звоните
super.onSaveInstanceState()
из вас активность, но это, кажется, не очень хорошее решение, фрагменты не могут сохранить состояние и восстановить.использование
FragmentPagerAdapter
вместоFragmentStatePagerAdapter
, Но после ориентации изменились, фрагменты которыхViewPager
hosted был пустым (У кого-нибудь еще есть такая же проблема?). Но я могу удалить все фрагменты в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
Редактировать:
Я наконец решил проблему, это потому, что мой ViewPager добавить после OnStart. Когда запустить на OnStart, FragmentManager
постараюсь восстановить фрагменты состояния. Я проследил в FragmentManager
Иметь этот код:
Проверьте выделенную линию, f.mContainerId
на самом деле мой идентификатор ViewPager. Затем он попытается добавить представление фрагментов в ViewPager. В моем случае ViewPager еще не добавлен, поэтому он будет очищен, но состояние фрагментов ATTACHED
, И в FragmentPagerAdapter.instantiateItem()
, Если фрагмент был добавлен, это просто сделать attach
фрагмент, но фрагмент уже прикреплен, так что его ничего не делать:(
Я добавляю ViewPager в макет активности XML, это исправлено.
Удачного кодирования:D
Просто вы используете в viewPager.setonpagechangelistener и реализуете для кода приложения применять ваше приложение,
http://developer.android.com/reference/android/support/v4/view/ViewPager.html