Внутренний фрагмент ViewPager, как сохранить состояние?

В моем приложении активность фрагмента содержит два фрагмента: фрагмент A и фрагмент B. Фрагмент B - это пейджер представления, содержащий 3 фрагмента.

enter image description here

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

if(getSupportFragmentManager().findFragmentByTag(MAIN_TAB_FRAGMENT) == null) {
    getSupportFragmentManager().beginTransaction().replace(R.id.container, new MainTabFragment(), MAIN_TAB_FRAGMENT).commit();
}

Код для фрагмента B:

public class MainTabFragment extends Fragment {

    private PagerSlidingTabStrip mSlidingTabLayout;
    private LfPagerAdapter adapter;
    private ViewPager mViewPager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_tab, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {

        this.adapter = new LfPagerAdapter(getChildFragmentManager());

        this.mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
        this.mViewPager.setAdapter(adapter);

        this.mSlidingTabLayout = (PagerSlidingTabStrip) view.findViewById(R.id.sliding_tabs);
        this.mSlidingTabLayout.setViewPager(this.mViewPager);
    }
}

Код адаптера:

public class LfPagerAdapter extends FragmentPagerAdapter {

    private static final int NUM_ITEMS = 3;

    private FragmentManager fragmentManager;

    public LfPagerAdapter(FragmentManager fm) {
        super(fm);
        this.fragmentManager = fm;
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
        Log.d("TEST","TEST");
        switch (position) {
            case 1:
                return FragmentC.newInstance();
            case 2:
                return FragmentD.newInstance();
            default:
                return FragmentE.newInstance();
        }
    }
}

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

Очевидно, это вызывается при каждом повороте:

this.adapter = new LfPagerAdapter(getChildFragmentManager());

что приведет к воссозданию всего пейджера, верно? В результате

getItem(int position)

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

return FragmentC.newInstance();

Я попытался решить это с помощью

if(this.adapter == null)
    this.adapter = new LfPagerAdapter(getChildFragmentManager());

в onViewCreated, но результатом было то, что при вращении фрагменты внутри пейджера, где удалены.

Любые идеи о том, как правильно сохранить состояние внутри пейджера?

Ответ 1

Вам нужно будет сделать 2 вещи, чтобы решить проблему:

1) Вместо onViewCreated вы должны использовать метод onCreate для создания экземпляра LfPagerAdapter;

то есть:.

    public class MainTabFragment extends Fragment {

    private PagerSlidingTabStrip mSlidingTabLayout;
    private LfPagerAdapter adapter;
    private ViewPager mViewPager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        this.adapter = new LfPagerAdapter(getChildFragmentManager());
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_tab, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {


        this.mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
        this.mViewPager.setAdapter(adapter);

        this.mSlidingTabLayout = (PagerSlidingTabStrip) view.findViewById(R.id.sliding_tabs);
        this.mSlidingTabLayout.setViewPager(this.mViewPager);
    }
}

2) Вам нужно расширить FragmentStatePagerAdapter вместо FragmentPagerAdapter

Ответ 2

Android автоматически обновит вашу активность при настройке без этой строки android:configChanges="keyboardHidden|orientation|screenSize" в вашем манифестах, чтобы вы могли обрабатывать onConfiguration самостоятельно.

Единственный способ использовать onSaveInstanceState() в вашей деятельностиFragement для сохранения состояния viewPager (например, текущей позиции) и фрагментов, где вам нужно сохранить материал

Пример того, как вы можете сохранить текущую позицию viewpager и восстановить ее onConfiguration изменить

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
            int position = mViewPager.getCurrentItem();
            outState.Int("Key", position );
    }

    @Override //then restore in on onCreate();
    public void onCreated(Bundle savedInstanceState) {
        super.onCreated(savedInstanceState);
        // do stuff
        if (savedInstanceState != null) {
              int  position= savedInstanceState.getInt("Key");
            mViewPager.setCurrentItem(position)
        }
    }

Конечно, это очень простой пример.

Ps: для восстановления во фрагменте используйте метод onActivityCreated() вместо метода onCreate().

Вот еще один пример того, как сохранить состояние: Нажмите меня!

Ответ 3

Запишите этот внутренний тег активности в manifest.xml: -

android:configChanges="orientation|screenSize"

Это позволит сохранить состояние фрагмента.