[英]How to Restore ViewPager from savedInstanceState
So I have a problem that I can't seem to solve. 所以我有一个我似乎无法解决的问题。 I have a ViewPager in one of my activities, say MainActivity .
我在其中一项活动中有一个ViewPager,比如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.
但是当活动尝试恢复其状态时,片段将被恢复,但它们不会附加到viewpager,所以我得到的只是一个白色屏幕。
Here is the relavant code: 这是相关代码:
MainActivity.java 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 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 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;
}
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: 因此,如果我导航到另一个活动,然后
MainActivity
在后台被杀死(我使用Do not Keep Activities设置来测试它),会发生这种情况:
1) The Activity gets restored properly, no issues there. 1)活动正确恢复,没有问题。
2) The onCreateView
of the fragments are called, with the savedInstanceState
intact. 2)调用片段的
onCreateView
,且savedInstanceState
保持不变。
3) But, the ViewPager and Adapter in my Activity are null
. 3)但是,我的Activity中的ViewPager和Adapter是
null
。 The fragments dont seem to get attached back to the adapter/viewpager. 片段似乎没有附加到适配器/ viewpager。
So what am I missing here? 那我在这里错过了什么? Am I supposed to do anything to properly restore the fragments?
我应该做些什么来正确恢复碎片吗?
I am able to solve the issue quickly by replacing this in my MainActivity
: 我可以通过在
MainActivity
替换它来快速解决问题:
if (savedInstanceState==null) {
setupViewPager();
}
with just setupViewPager();
只需
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.
所以我不相信这是最好的方法。
By destroying the Activity
you also destroy every instance field. 通过销毁
Activity
您还会销毁每个实例字段。 So you have to re-instantiate the ViewPager
and Adapter
. 所以你必须重新实例化
ViewPager
和Adapter
。 There are two scenarios you have to keep in mind. 您必须记住两种情况。
FragmentStatePagerAdapter
saves/restores Fragments
with the FragmentManager
FragmentStatePagerAdapter
保存/恢复Fragments
与FragmentManager
Fragments
inside the Fragment
Fragments
内Fragment
The first point is the reason why you have two instances of each Fragment
. 第一点是每个
Fragment
有两个实例的原因。 In order to fix this you can get the stored Fragment by its ID . 为了解决这个问题,您可以通过其ID获取存储的Fragment。 See this grepcode
FragmentPagerAdapter
(same goes for StateAdapter
) 看到这个 grepcode
FragmentPagerAdapter
(同样适用于StateAdapter
)
private static String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
Instead of instantiating a Fragment
in setupViewPager
every time - you get it from the FragmentManager
first eg 而不是每次都在
setupViewPager
中实例化Fragment
- 你首先从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");
}
The above is an example on how to restore previous saved Fragments
from the FragmentManager
. 以上是如何从
FragmentManager
恢复以前保存的Fragments
的示例。 You probably have to adjust the cases where you have different types of BaseFragments
and so on. 您可能需要调整具有不同类型
BaseFragments
,依此类推。 Furthermore you might want to save the Fragment
title names and the total count to restore them. 此外,您可能希望保存
Fragment
标题名称和总计数以还原它们。
The second point is that you have to restore the current Fragment
state from the Fragment
itself. 第二点是你必须从
Fragment
本身恢复当前的Fragment
状态。 For that your Fragment
has the lifecycle methods. 为此,您的
Fragment
具有生命周期方法。 See this SO topic about that Once for all, how to correctly save instance state of Fragments in back stack? 请参阅此SO主题关于一劳永逸,如何在后端堆栈中正确保存Fragments的实例状态?
FragmentStatePagerAdapter has method saveState() and restoreState() to save and restore it's state.. FragmentStatePagerAdapter具有saveState()和restoreState()方法来保存和恢复它的状态。
https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html#saveState() https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html#saveState()
saveState: Save any instance state associated with this adapter and its pages that should be restored if the current UI state needs to be reconstructed.
saveState:保存与此适配器关联的任何实例状态及其在需要重建当前UI状态时应恢复的页面。
So it seems that it could be possible to use these methods to archive your goal. 因此,似乎可以使用这些方法来存档您的目标。 I'm sorry, but I don't have compiler now, so I couldn't tested code below.
对不起,我现在没有编译器,所以我无法测试下面的代码。
@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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.