【问题标题】:FragmentActivity onSaveInstanceState not getting calledFragmentActivity onSaveInstanceState 没有被调用
【发布时间】: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://stackoverflow.com/a/14195202/362657 中建议的,但是当onSaveInstanceState 然后被调用时,savedInstanceStateonCreate 方法中仍然是null。我错过了什么?

【问题讨论】:

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

标签: android android-fragmentactivity


【解决方案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());,是一种非常糟糕的做法,因为您应该永远不要直接调用生命周期回调。这样做会使您的应用程序进入非法状态。

如果您真正想要的是将数据保留在应用实例之外,我建议您考虑使用SharedPreferencesdatabases 获取更高级的数据。然后,您可以将持久性数据保存在 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);
    }
    

    【讨论】:

      猜你喜欢
      • 2015-03-28
      • 1970-01-01
      • 1970-01-01
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多