如何从savedInstanceState恢复ViewPager [英] How to Restore ViewPager from savedInstanceState

查看:70
本文介绍了如何从savedInstanceState恢复ViewPager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个我似乎无法解决的问题.我的一项活动中有一个 ViewPager,比如 MainActivity.当活动在后台被终止时,我正在实施所有必需的方法来保存和检索实例状态.但是当 Activity 尝试恢复其状态时,片段被恢复但它们没有附加到 viewpager 所以我得到的只是一个白屏.

So I have a problem that I can't seem to solve. I have a ViewPager in one of my activities, say MainActivity. I am implementing all the required methods to save and retrieve instance state when the activity gets killed in the background. But when the activity tries to restore its state, the fragments are restored but they are not attached to the viewpager so all I get is a white screen.

相关代码如下:

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 在后台被杀死(我正在使用 Don't Keep Activities 设置来测试这个),会发生这种情况:

So if I navigate to another activity and then the MainActivity gets killed in the background ( I am using the Don’t Keep Activities setting to test this), this happens:

1) Activity 恢复正常,没有问题.
2) 调用片段的onCreateView,保持savedInstanceState不变.
3) 但是,我的 Activity 中的 ViewPager 和 Adapter 是 null.这些片段似乎没有连接回适配器/viewpager.

1) The Activity gets restored properly, no issues there.
2) The onCreateView of the fragments are called, with the savedInstanceState intact.
3) But, the ViewPager and Adapter in my Activity are null. The fragments dont seem to get attached back to the adapter/viewpager.

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

So what am I missing here? Am I supposed to do anything to properly restore the fragments?

通过在我的 MainActivity 中替换它,我能够快速解决问题:

I am able to solve the issue quickly by replacing this in my MainActivity:

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

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

with just setupViewPager();, so that a new adapter and fragments are created irrespective of whether it is restoring or launching for the first time. But that comes with the drawback of resetting the state of the fragments. Also, when I do that, I find that there are two instances of each fragment, one which is restored and a new one, with only the new instances actually displayed. So I dont believe that it is the best approach.

推荐答案

通过销毁 Activity 您也可以销毁每个实例字段.所以你必须重新实例化ViewPagerAdapter.您必须记住两种情况.

By destroying the Activity you also destroy every instance field. So you have to re-instantiate the ViewPager and Adapter. There are two scenarios you have to keep in mind.

  1. FragmentStatePagerAdapter 使用 FragmentManager
  2. 保存/恢复 Fragments
  3. 你必须恢复Fragment
  4. Fragments的状态

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

The first point is the reason why you have two instances of each Fragment. In order to fix this you can get the stored Fragment by its ID. See this grepcode FragmentPagerAdapter (same goes for StateAdapter)

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

不是每次都在 setupViewPager 中实例化一个 Fragment - 你首先从 FragmentManager 获取它,例如

Instead of instantiating a Fragment in setupViewPager every time - you get it from the FragmentManager first e.g.

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");
}

以上是如何从FragmentManager中恢复之前保存的Fragments的例子.您可能需要调整具有不同类型的 BaseFragments 等的情况.此外,您可能希望保存 Fragment 标题名称和总计数以恢复它们.

The above is an example on how to restore previous saved Fragments from the FragmentManager. You probably have to adjust the cases where you have different types of BaseFragments and so on. Furthermore you might want to save the Fragment title names and the total count to restore them.

第二点是你必须从 Fragment 本身恢复当前的 Fragment 状态.为此,您的 Fragment 具有生命周期方法.请参阅有关该主题的 SO 主题 归根结底,如何正确地将 Fragment 的实例状态保存在 back stack 中?

The second point is that you have to restore the current Fragment state from the Fragment itself. For that your Fragment has the lifecycle methods. See this SO topic about that Once for all, how to correctly save instance state of Fragments in back stack?

这篇关于如何从savedInstanceState恢复ViewPager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆