如何从savedInstanceState恢复ViewPager

Sha*_*hiM 6 java performance android android-fragments android-viewpager

所以我有一个我似乎无法解决的问题.我在其中一项活动中有一个ViewPager,比如MainActivity.当活动在后台被杀死时,我正在实现保存和检索实例状态所需的所有方法.但是当活动尝试恢复其状态时,片段将被恢复,但它们不会附加到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);
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

因此,如果我导航到另一个活动然后MainActivity在后台被杀死(我使用Do not Keep Activities设置来测试它),会发生这种情况:

1)活动正确恢复,没有问题.
2)onCreateView片段被称为savedInstanceState完整的片段.
3)但是,我的Activity中的ViewPager和Adapter是null.片段似乎没有附加到适配器/ viewpager.

那我在这里错过了什么?我应该做些什么来正确恢复碎片吗?

PS:

我可以通过在我的替换中快速解决问题MainActivity:

if (savedInstanceState==null) {
    setupViewPager();
}
Run Code Online (Sandbox Code Playgroud)

只是setupViewPager();,这样就可以创建一个新的适配器和片段,无论它是第一次恢复还是启动.但这带来了重置片段状态的缺点.此外,当我这样做时,我发现每个片段有两个实例,一个是恢复的,另一个是新实例,只有实际显示的新实例.所以我不相信这是最好的方法.

Mur*_*göz 5

通过销毁,Activity您还销毁了每个实例字段。因此,您必须重新实例化ViewPagerAdapter。您必须记住两种情况。

  1. FragmentStatePagerAdapter保存/恢复FragmentsFragmentManager
  2. 您必须还原Fragments内部状态Fragment

第一点是为什么每个都有两个实例的原因Fragment。为了解决这个问题,您可以通过其ID获取存储的Fragment 。看到这个 grepcode FragmentPagerAdapter(同样适用StateAdapter

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}
Run Code Online (Sandbox Code Playgroud)

而不是每次都实例化a- 您可以从第一个实例FragmentsetupViewPager获取它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");
}
Run Code Online (Sandbox Code Playgroud)

上面是有关如何还原Fragments从中保存的以前的示例FragmentManager。您可能必须调整具有不同类型BaseFragments等等的情况。此外,您可能需要保存Fragment标题名称和总数以恢复它们。


第二点是您必须FragmentFragment自身还原当前状态。为此,您Fragment具有生命周期方法。请参阅有关此主题的SO主题,如何一劳永逸地将Fragments的实例状态保存在后向堆栈中?