Android ViewPager и сериализация фрагментов

У меня есть активность с двумя атрибутами:

  • частный фрагмент firstFragment;
  • частный фрагмент secondFragment;

В методе onCreate:

    adapter = new MyPagerAdapter(getSupportFragmentManager());
    pager = (ViewPager) findViewById(R.id.pager);
    pager.setAdapter(adapter);
    pager.setOffscreenPageLimit(6);
    pager.setSaveEnabled(true);

где MyPagerAdapter расширяет класс FragmentStatePagerAdapter. В метод getItem():

    @Override
    public Fragment getItem(int position) {

        Bundle args = new Bundle();

        switch (position) {
            case FIRST:
                secondFragment = new FirstFragment();
                secondFragment.setArguments(args);
                return secondFragment;
            case SECOND:
                secondFragment = new SecondFragment();
                secondFragment.setArguments(args);
                return secondFragment;
        }
    }

и все работает корректно.

Но когда я меняю ориентацию экрана, для личных атрибутов устанавливается значение null, и я потерял ссылку на два фрагмента. Итак, я попытался сериализовать этот фрагмент с помощью:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    getSupportFragmentManager().putFragment(outState, FirstFragment.class.getName(), firstFragment);
    getSupportFragmentManager().putFragment(outState, SecondFragment.class.getName(), secondFragment);
}

и загрузите их в метод onCreate с помощью:

    if (savedInstanceState != null) {
        firstFragment = (FirstFragment) getSupportFragmentManager().getFragment(savedInstanceState, FirstFragment.class.getName());
        secondFragment = (SecondFragment) getSupportFragmentManager().getFragment(savedInstanceState, SecondFragment.class.getName());
    }

Мои вопросы:

<сильный>1. Это правильный способ сериализованного фрагмента в изменение ориентации экрана активности?

<сильный>2. Иногда у меня возникает ошибка: "Unmarshalling unknown type code 55 at offset 448", возможно ли, что это вызвано сериализацией фрагмента?"

РЕДАКТИРОВАТЬ:

Мне нужно иметь фрагменты в качестве атрибутов активности, потому что у меня есть интерфейс прослушивателя в активности, который:

@Override
public void executeTask(String what) {
    secondFragment.executeTask(what);
}

этот метод был вызван в firstFragment. Таким образом, FirstFragment может выполнять метод SecondFragment.


person CeccoCQ    schedule 25.03.2014    source источник


Ответы (2)


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

Я не думаю, что вы должны ссылаться на Fragments в Adapter из Activity. В основном из-за того, что довольно сложно синхронизировать жизненный цикл Activity, жизненный цикл Fragment и жизненный цикл ViewPager потомков. И если появляются какие-либо ошибки, отладка может быть очень болезненной. Поверьте, был там, делал это...

Кстати, есть ли причина, по которой вам нужны ссылки на Fragments в вашем Activity?

РЕДАКТИРОВАТЬ

Я не думаю, что вы должны передавать информацию между Fragments таким образом. Как правило, FragmentManager обрабатывает (создает, удаляет) Fragments самостоятельно, и вы не можете быть уверены, что эти Fragments будут доступны в любое время.

Я думаю, что лучшим способом было бы переместить ваши данные в отдельную модель (запись базы данных, SharedPreference или класс синглтона), а затем сообщить Adapter, что данные изменились (с помощью DataObserver в Fragments или просто уведомить Adapter об обновлении дочерних данных по телефону notifyDataChanged).

ПРИМЕР

ФрагментA ---> слушатель (reloadData()) ---> Активность ---> adapter.notifyDataChanged()-----> фрагмент B обновляется

Таким образом, если вы когда-нибудь захотите добавить ThirdFragment или фактически любое количество Fragments, которые будут использовать данные, вам не придется беспокоиться об обновлении данных в любом из них - просто позвольте Adapter побеспокоиться об этом.

person aldorain    schedule 25.03.2014
comment
Это хороший обходной путь и, возможно, это правильный способ решить проблему сериализации фрагментов. Использование DataObserver для изменения загруженных данных во фрагмент и бизнес-модуль для выполнения любых других операций. - person CeccoCQ; 25.03.2014

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

     <activity android:name=".activity.MainActivity"
        android:configChanges="keyboardHidden|orientation|screenSize">
     </activity>

а затем переопределить onConfigurationChanged() в действии...

    @Override
     public void onConfigurationChanged(Configuration        newConfig)
    {
      super.onConfigurationChanged(newConfig);
    }
person Libin    schedule 25.03.2014
comment
Что вы имеете в виду под одинаковым макетом? Структура компонентов? У меня есть файл макетов в layout-normal-land и т. д. - person CeccoCQ; 25.03.2014
comment
Вы используете один и тот же макет для портретной и альбомной ориентации? тогда вы можете избежать сохранения состояния при изменении ориентации. - person Libin; 25.03.2014
comment
Нет, я использую другой xml для этого представления. - person CeccoCQ; 25.03.2014