Как восстановить ViewPager из savedInstanceState

Итак, у меня проблема, которую я не могу решить. У меня есть ViewPager в одном из моих занятий, скажем MainActivity. Я реализую все необходимые методы для сохранения и извлечения состояния экземпляра, когда действие убивается в фоновом режиме. Но когда activity пытается восстановить свое состояние, фрагменты восстанавливаются, но они не прикреплены к viewpager, поэтому все, что я получаю, это белый экран.

вот код, соответствующий :

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //..
    if (savedInstanceState==null) {
        setupViewPager();
    }
}

private void setupViewPager() {
    mAdapter = new ViewPagerAdapter(getSupportFragmentManager());
    mAdapter.addFrag(FirstFragment.newInstance(mFeedItem), "INFO");
    //Note: mFeedItem is obtained from the intent and I have verified
    //      that it is properly restored.
    mAdapter.addFrag(SecondFragment.newInstance(mFeedItem), "SERVICES");
    mViewPager.setAdapter(mAdapter);
    mTabLayout.setupWithViewPager(mViewPager);
}

ViewPagerAdapter.java

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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

    public void addFrag(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

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

FirstFragment.java

public static FirstFragment newInstance(Workshop item) {
    FirstFragment f = new FirstFragment();
    f.mItem = item;
    return f;
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("feed_item",Workshop.packToGson(mItem));
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_item_detail_info, container, false);
    if (savedInstanceState!=null) {
        mItem = Workshop.extractGson(savedInstanceState.getString("feed_item"));
    }
    return v;
}

поэтому, если я перейду к другому действию, а затем MainActivity убит в фоновом режиме ( я использую не держите деятельность настройка для проверки этого), это происходит:

1) Активность восстанавливается должным образом, никаких проблем нет.
2) The onCreateView из фрагментов называются, с savedInstanceState нетронутыми.
3) но, ViewPager и адаптер в моей деятельности являются null. Фрагменты, похоже, не прикрепляются обратно к адаптеру/viewpager.

так что я упускаю здесь? Я должен что-то сделать, чтобы восстановить фрагменты?

PS:

я могу быстро решить проблему, заменив это в моем MainActivity:

if (savedInstanceState==null) {
    setupViewPager();
}

С setupViewPager();, так что новый адаптер и фрагменты создаются независимо от того, восстанавливается ли он или запускается в первый раз. Но это связано с недостатком сброса состояния фрагментов. Кроме того, когда я это делаю, я нахожу, что есть два экземпляра каждого фрагмента, один из которых восстанавливается и новый, с отображением только новых экземпляров. Поэтому я не считаю, что это лучший подход.

2 ответов


уничтожить Activity вы также уничтожаете каждое поле экземпляра. Таким образом, вы должны повторно создать экземпляр ViewPager и Adapter. Есть два сценария, которые вы должны иметь в виду.

  1. FragmentStatePagerAdapter сохраняет/восстанавливает Fragments С FragmentManager
  2. вы должны восстановить состояние Fragments внутри Fragment

первый момент-причина, по которой у вас есть два экземпляра каждого Fragment. Чтобы исправить это, вы можете получить сохраненный Фрагмент его ID. посмотреть этот grepcode FragmentPagerAdapter (то же самое для StateAdapter)

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

вместо создания Fragment на setupViewPager каждый раз - вы получаете его от FragmentManager во-первых, например,

mAdapter = new ViewPagerAdapter(getSupportFragmentManager());
int fragmentCount = 2; // save value if it's a arbitrary list of fragments
for (int index = 0; i < fragmentCount; i++) {
    FirstFragment firstFragment = (FirstFragment) getSupportFragmentManager().findFragmentByTag(makeFragmentName(R.id.view_pager, index));
    if (firstFragment == null) {
        firstFragment = FirstFragment.newInstance(mFeedItem);
    }
    mAdapter.addFrag(firstFragment, "someTitle");
}

выше приведен пример того, как восстановить предыдущие сохраненные Fragments С FragmentManager. Вероятно, вам придется настроить случаи, когда у вас есть разные типы BaseFragments и так далее. Кроме того, вы можете сохранить Fragment названия и общее количество для их восстановления.


второй момент заключается в том, что вы должны восстановить ток Fragment государство от . За что ваш Fragment есть методы жизненного цикла. См. эту тему SO об этом раз и навсегда, Как правильно сохранить состояние экземпляра фрагментов в задней стеке?


FragmentStatePagerAdapter имеет метод saveState () и restoreState () для сохранения и восстановления его состояния..

https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html#saveState()

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

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

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
        setupViewPager(savedInstanceState);
    }
}

private void setupViewPager(Bundle savedInstanceState) {
    mAdapter = new ViewPagerAdapter(getSupportFragmentManager());

    if (savedInstanceState != null) {
        Parcelable parcelable = savedInstanceState.getParcelable("Adapter");
        mAdapter.restoreState(parcelable, getClassLoader());
    } else {
        mAdapter.addFrag(FirstFragment.newInstance(mFeedItem), "INFO");
        //Note: mFeedItem is obtained from the intent and I have verified
        //      that it is properly restored.
        mAdapter.addFrag(SecondFragment.newInstance(mFeedItem), "SERVICES");
    }
    mViewPager.setAdapter(mAdapter);
    mTabLayout.setupWithViewPager(mViewPager);
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    Parcelable parcelable = mAdapter.saveState();
    outState.putParcelable("Adapter", parcelable);
}