FragmentActivity onSaveInstanceState 没有被调用

Posted

技术标签:

【中文标题】FragmentActivity onSaveInstanceState 没有被调用【英文标题】:FragmentActivity onSaveInstanceState not getting called 【发布时间】:2013-04-02 20:29:10 【问题描述】:

我已经看到了一些关于onSaveInstanceState 没有被Fragments 调用的类似问题,但在我的情况下Fragments 工作正常,主要的FragmentActivity 有问题。

相关代码看起来相当简单:

public class MyFActivity extends FragmentActivity implements ActionBar.TabListener  
    String[] allValues; // data to save

    @Override
    protected void onSaveInstanceState (Bundle outState) 
        Log.d("putting it!", allValues.toString());
        outState.putStringArray("allValues", allValues);
        super.onSaveInstanceState(outState);
    

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) 
            allValues = savedInstanceState.getStringArray("allValues");
            Log.d("getting it!", allValues.toString());
        
    

暂停活动时(使用后退按钮),永远不会调用 onSaveInstanceState,因此,在恢复应用程序时,savedInstanceState 始终是 onCreate 方法中的 null。我尝试添加这样的块:

@Override
public void onPause() 
    super.onPause();
    onSaveInstanceState(new Bundle());      

这是在https://***.com/a/14195202/362657 中建议的,但是当onSaveInstanceState 然后被调用时,savedInstanceStateonCreate 方法中仍然是null。我错过了什么?

【问题讨论】:

“暂停活动时(使用后退按钮)”通常会破坏片段,因此savedInstanceState 会丢失。当您旋转设备时,您是否在onCreate() 中看到了相应的saveInstanceState 而不是 onCreate,也许您应该使用 onResume()?如果活动只是暂停,那么 onCreate() 不应该被再次调用,onResume() 应该 嗯,这就解释了!毁了它。 【参考方案1】:

这里的问题是您误解了onSaveInstanceState 的工作原理。它旨在保存Activity/Fragment 的状态,以防操作系统因内存原因或配置更改而需要销毁它。然后当Activity/Fragment 返回/重新启动时,此状态会在onCreate 中传回。

Fragment 中,它们的所有生命周期回调都直接绑定到它们的父Activity。因此,当 Fragment 的父级 Activity 调用了 onSaveInstanceState 时,onSaveInstanceState 会在 Fragment 上被调用。

暂停活动时(使用后退按钮),永远不会调用 onSaveInstanceState,因此,在恢复应用程序时,onCreate 方法中的 savedInstanceState 始终为 null。

当按下返回时,用户正在销毁Activity,因此它的子Fragments,因此没有理由调用onSaveInstanceState,因为实例正在被销毁。当你重新打开Activity时,它是一个全新的实例,没有保存状态,所以onCreate传入的Bundlenull。这完全符合设计。但是,尝试旋转设备或点击主页按钮,然后您会看到Activity 及其子Fragments 调用了onSaveInstanceState,并在返回时传入onCreate

您添加的hack,直接在onPause 内部调用onSaveInstanceState(new Bundle());,是一种非常糟糕的做法,因为您应该永远不要直接调用生命周期回调。这样做会使您的应用程序进入非法状态。

如果您真正想要的是将数据保留在应用实例之外,我建议您考虑使用SharedPreferences 或databases 获取更高级的数据。然后,您可以将持久性数据保存在 onPause() 中或随时更改。

希望这会有所帮助。

【讨论】:

感谢您的详尽解释。我的错误印象是后退按钮将活动置于后台,而不是破坏它。 不客气,这是一个棘手的概念,并且没有像我希望看到的那样记录在案。 @dymmeh 太棒了,+1 先生 很好的解释。我不确定为什么我的片段中没有调用 onSaveInstanceState。现在我明白了。谢谢 In a Fragment, all of their lifecycle callbacks are directly tied to their parent Activity. So onSaveInstanceState gets called on the Fragment when its parent Activity has onSaveInstanceState called. 那么由单个活动托管的片段呢?从理论上讲,它们像 onSavedInstanceState 和 ... 这样的方法永远不会被调用,因为它们在同一个活动中传输,对吧?【参考方案2】:

在已接受答案的更新中:

如果您将ViewPagerFragmentStatePagerAdapter(而不是FragmentPagerAdapter)一起使用,则可能会调用片段的onSaveInstanceState

FragmentStatePagerAdapter

当有大量页面时,此版本的寻呼机更有用,更像列表视图。当页面对用户不可见时,它们的整个片段可能会被销毁,只保留该片段的已保存状态。与 FragmentPagerAdapter 相比,这允许分页器保留与每个访问的页面相关联的内存更少,但代价是在页面之间切换时可能会增加更多开销。

别忘了:

使用 FragmentPagerAdapter 时,宿主 ViewPager 必须设置有效的 ID。

【讨论】:

【参考方案3】:

不是对问题的准确答案,但可能对某人有所帮助。 就我而言,我打电话给

@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) 
  super.onSaveInstanceState(outState, outPersistentState);

我将上面的代码替换为如下,一切正常

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

【讨论】:

以上是关于FragmentActivity onSaveInstanceState 没有被调用的主要内容,如果未能解决你的问题,请参考以下文章

从 fragmentActivity 刷新片段 UI

Activity 和 FragmentActivity 的区别

如何在 FragmentActivity 上设置工具栏?

Android - 活动与 FragmentActivity? [复制]

Fragment 和 FragmentActivity 有啥区别?

Activity、AppCompatActivity、FragmentActivity 和 ActionBarActivity:啥时候使用?