Как viewPager запазва състоянията на фрагменти при промяна на ориентацията?

Този въпрос има някои прилики с:

Фрагментът във ViewPager на Fragment не се презарежда при промяна на ориентацията

Разликата обаче е, че искам да знам как действително се запазват състоянията на фрагментите, тъй като наблюдавам случващи се много странни неща.

Моите наблюдения са следните:

Настройване на ViewPager с FragmentPagerAdapter:

  class HomeAdapter extends FragmentPagerAdapter
{
    HomeAdapter(FragmentManager manager)
    {
        super(manager);
    }

    @Override
    public Fragment getItem(int i) {
        try {
            return (Fragment) mTabs.get(i).getFragmentClass().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mTabs.get(position).getTitle();
    }

    @Override
    public int getCount() {
        return mTabs.size();
    }
}

В моята дейност onCreate извиквам:

setContentView(R.layout.activity_home);
    mTabs = new ArrayList<>();
    mTabs.add(new SlidingTabItem("A", FragmentA.class));
    mTabs.add(new SlidingTabItem("B", FragmentB.class));

    mViewPager = (ViewPager) findViewById(R.id.viewpager);
    mViewPager.setAdapter(new HomeAdapter(getSupportFragmentManager()));

    mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tabs);
    mSlidingTabLayout.setViewPager(mViewPager);

Сега, когато ориентацията на устройството се промени, viewPager пресъздава всичко до променения текст в полетата editText вътре във фрагментите.

За да изясня, това всъщност е поведението, което ИСКАМ, но не го разбирам.

Проверих източника на viewPager и FragmentPagerAdapter. Разбрах, че FragmentPagerAdapter търси FragmentManager, ако вече съществува фрагмент на тази позиция. Ако го направи, той извиква FragmentTransaction.attach(), за да го прикачи отново.

Той също така премахва фрагментите с помощта на FragmentManager.detach()

Доколкото разбирам, това запазва FragmentState във FragmentManager. Но КЪДЕ и КОГА това всъщност се възстановява.

Опитах се да се закача във всеки един метод на жизнения цикъл в моя фрагмент, който съдържа savedInstanceState и да извикам super.X с null като savedInstanceState, но изгледът пак ще бъде възстановен по същия начин.

Възстановеният фрагмент също изглежда игнорира промените в изгледа, направени в onCreateView. Опитах следното:

mMajor = (EditText) contentView.findViewById(R.id.major);
mMajor.setText("123");

който работи при първото създаване на фрагмента. Въпреки това, въпреки че onCreateView всъщност се извиква втори път, тази директива очевидно не прави нищо, тъй като основният editText не се нулира на "123".

Интересното е, че извикването на mMajor.getText().toString() връща нещо като:

[ 01-31 18:29:54.634 18540:29583 I/ActivityManager ]

което също не разбирам. Това ли е защото изгледът не е напълно създаден в този момент?

Така че основният ми въпрос остава. Кога фрагментът всъщност пресъздава своя екземпляр и защо извиква методи на жизнения цикъл, въпреки че не се интересува от резултата и има ли някакъв начин да се открие това, без да се задава променлива на екземпляр при първото създаване на фрагмент?


person Blackclaws    schedule 31.01.2015    source източник


Отговори (1)


Когато Fragments бъдат отделени от ViewPager, те ще преминат през жизнения цикъл на изключване (onPause(), onSaveInstanceState(), onStop(), onDestroyView(), onDetach() и т.н.)

Въпреки това, ViewPager (по-конкретно FragmentStatePagerAdapter) ще премине и ще запази ръчно състоянието на фрагмента в собственото си запазено състояние (извиква FragmentManager.saveFragmentInstanceState(fragment) при отделяне на фрагментите). Вероятно това е причината, поради която замяната на методите, извикващи super.*(null), не го засяга.

Причината, поради която промените във вашия изглед се отменят, е, че onCreateView() се случва преди onViewStateRestored(), в който момент ще възстанови запазеното състояние и ще презапише вашите промени. Така или иначе наистина не трябва да настройвате състоянието на изгледа си в този метод -- просто върнете изгледа.

Ако искате да знаете дали за първи път се създава фрагмент, достатъчно е да проверите if (savedInstanceState == null). Ако е така, това е първото изстрелване. В противен случай той се пресъздава от запазено състояние.

person Kevin Coppock    schedule 31.01.2015