简体   繁体   English

在 Activity 中保存片段状态

[英]Saving fragment state in Activity

I'm getting the below error when I try to save the state of my fragments in my main activity:当我尝试在主要活动中保存片段的状态时,出现以下错误:

java.lang.IllegalStateException: Fragment MarketviewFragment{c5e0f0d} is not currently in the FragmentManager
    at androidx.fragment.app.FragmentManagerImpl.putFragment(FragmentManager.java:923)
    at com.shoob.capstone.android.crypfolio.MainActivity.onSaveInstanceState(MainActivity.java:308)
    at android.app.Activity.performSaveInstanceState(Activity.java:1608)
    at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1443)
    at android.app.ActivityThread.callActivityOnSaveInstanceState(ActivityThread.java:5038)
    at android.app.ActivityThread.callActivityOnStop(ActivityThread.java:4372)
    at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:4986)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4922)
    at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1926)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:6986)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)

In my main activity, I have 4 possible fragments that get displayed only one at a time.在我的主要活动中,我有 4 个可能的片段,一次只显示一个。 I keep a reference to the fragments in the main activity and display them as needed:我保留对主要活动中的片段的引用,并根据需要显示它们:

private MarketviewFragment marketviewFragment;
private WatchlistFragment watchlistFragment;
private PortfolioFragment portfolioFragment;
private DetailsFragment detailsFragment;

I set the current displayed fragment with the below code (only one fragment displayed at a time):我使用以下代码设置当前显示的片段(一次只显示一个片段):

//fragment is an instance of one of the 4 types of fragments above
private void setFragment(Fragment fragment) {
    FragmentManager fm = getSupportFragmentManager();

    if (fm.findFragmentById(R.id.frag_main) != null) {
        fm.beginTransaction()
                .replace(R.id.frag_main, fragment)
                .commit();
    } else {
        fm.beginTransaction()
                .add(R.id.frag_main, fragment)
                .commit();
    }
}

This is how I set each fragment (one example, same for the other types):这是我设置每个片段的方式(一个示例,其他类型相同):

private void setPortfolioFragment() {
    if (portfolioFragment == null) {
        portfolioFragment = PortfolioFragment.newInstance();
    }
    setFragment(portfolioFragment);
}

Now for my question.现在我的问题。 How do I save the state of all these fragments?如何保存所有这些片段的状态? I want to save them all in a Bundle so I can restore them on recreation of the Main Activity (like on rotation).我想将它们全部保存在一个 Bundle 中,这样我就可以在重新创建 Main Activity 时恢复它们(例如在旋转时)。

The way I'm doing it now doesn't seem to work, what is the correct way to do this?我现在这样做的方式似乎不起作用,这样做的正确方法是什么?

Saving state:保存状态:

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

    if (marketviewFragment != null) {
        getSupportFragmentManager().putFragment(outState, KEY_BUNDLE_MARKETVIEW_FRAGMENT, marketviewFragment);
    }
    if (watchlistFragment != null) {
        getSupportFragmentManager().putFragment(outState, KEY_BUNDLE_WATCHLIST_FRAGMENT, watchlistFragment);
    }
    if (portfolioFragment != null) {
        getSupportFragmentManager().putFragment(outState, KEY_BUNDLE_PORTFOLIO_FRAGMENT, portfolioFragment);
    }
    if (detailsFragment != null) {
        getSupportFragmentManager().putFragment(outState, KEY_BUNDLE_DETAILS_FRAGMENT, detailsFragment);
    }

}

Restoring state:恢复状态:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (savedInstanceState != null) {
        marketviewFragment = (MarketviewFragment)getSupportFragmentManager().getFragment(savedInstanceState, KEY_BUNDLE_MARKETVIEW_FRAGMENT);
        watchlistFragment = (WatchlistFragment)getSupportFragmentManager().getFragment(savedInstanceState, KEY_BUNDLE_WATCHLIST_FRAGMENT);
        portfolioFragment = (PortfolioFragment)getSupportFragmentManager().getFragment(savedInstanceState, KEY_BUNDLE_PORTFOLIO_FRAGMENT);
        detailsFragment = (DetailsFragment)getSupportFragmentManager().getFragment(savedInstanceState, KEY_BUNDLE_DETAILS_FRAGMENT);

    }
}

You should save it every time you detach fragment.每次分离片段时都应该保存它。 also please use detach/attach instead of replace on fragmentManager也请在fragmentManager上使用分离/附加而不是replace

another thing is that FragmentManager should restore fragments on it's own.另一件事是FragmentManager应该自己恢复片段。 Personally I would do it with FragmentPagerAdapter and just switch visible one.我个人会用FragmentPagerAdapter来做,然后只切换可见的。

Best and easiest way would be to have all fragments attached to FragmentManager, and just control visibility.最好和最简单的方法是将所有片段附加到 FragmentManager,并控制可见性。 Thanks to that saving/restoring will be done automatically由于保存/恢复将自动完成

Your activity should not be handling saving state for each fragment.您的活动不应为每个片段处理保存状态。 You should let each fragment handle storing its own state by overriding onSaveInstanceState() in each fragment class:您应该通过覆盖每个片段类中的 onSaveInstanceState() 来让每个片段处理存储自己的状态:

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    // save fragment state here
}

Also, keeping hard references to all your fragments in your activity is not a great idea.此外,在您的活动中保留对所有片段的硬引用并不是一个好主意。

Edit: After looking at your question again, I understand more what you're trying to do.编辑:再次查看您的问题后,我更了解您要做什么。 You're trying to save and restore the actual instances of your fragments.您正在尝试保存和恢复片段的实际实例。 The Android OS will do this automatically for you and you're trying to get in the way of this process. Android 操作系统会自动为您执行此操作,而您正试图妨碍此过程。 Again, the fact that you are storing the fragments as instance variables is part of the problem and is making you do something you normally wouldn't need to do.同样,您将片段存储为实例变量这一事实是问题的一部分,并且让您做一些通常不需要做的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM