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
Ответ 3
Просто вы используете в viewPager.setonpagechangelistener и реализуете требуемый код, применяя ваше приложение,
http://developer.android.com/reference/android/support/v4/view/ViewPager.html