Android 具有多个片段和屏幕方向的单个活动

Android 具有多个片段和屏幕方向的单个活动,android,android-fragments,screen,orientation,handle,Android,Android Fragments,Screen,Orientation,Handle,我目前正在处理安卓系统的一个问题&它在屏幕上的重新创建周期: 我有一个单一的活动和大量的片段(Support-V4)。 例如,登录它在一个带有片段的单个活动上,当登录时,然后应用程序更改其导航行为并使用多个片段,我这样做了,因为在片段a到片段B之间传递数据要比在活动a到活动B之间传递数据容易得多 所以我的问题是,当我旋转设备时,在我的第一种方法中,初始片段被加载,但是会发生什么,如果用户在第15页上旋转设备,它会返回到片段1,并提供非常糟糕的用户体验。我将所有片段设置为保留其实例,并在创建时将其

我目前正在处理安卓系统的一个问题&它在屏幕上的重新创建周期:

我有一个单一的活动和大量的片段(Support-V4)。 例如,登录它在一个带有片段的单个活动上,当登录时,然后应用程序更改其导航行为并使用多个片段,我这样做了,因为在片段a到片段B之间传递数据要比在活动a到活动B之间传递数据容易得多

所以我的问题是,当我旋转设备时,在我的第一种方法中,初始片段被加载,但是会发生什么,如果用户在第15页上旋转设备,它会返回到片段1,并提供非常糟糕的用户体验。我将所有片段设置为保留其实例,并在创建时将其添加到MainActivity上:

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
    initBackStackManager();
    initControllers();
    mayDownloadData();
    setTitle();
    if(savedInstanceState == null){
        addAreaFragment();
    }
}
现在,第一个片段在屏幕方向更改后没有加载,但是如果我尝试进行片段事务,它会说无法执行FragmentTransaction.commit()在onSaveInstanceState()之后,,是否有方法处理此问题?或者我真的需要使用多个活动,其中嵌入一个片段

多谢各位

已编辑 我忘了补充,这只发生在一个特定的片段上。。。例如,我有以下片段流:

AreaFragment -> WaiterSelectionFragment -> WaiterOptionsFragment.
如果我在区域fragment中,并且我旋转设备,我仍然可以添加/替换片段,并且没有发生任何事情,不会抛出错误。如果我在WaiterSelectionFragment上,也不会发生错误。但是,如果我在waiteroptionfragment上,就会抛出错误。WaiterSelectionFragment具有以下结构:

  • 线性布局
  • 碎片表主机
  • 里面有一些碎片,这就是它发生错误的地方。你可能想知道为什么会有碎片?很简单,客户希望该应用程序显示选项卡栏,如果我使用本机Android选项卡,则打开时选项卡会重新排列到操作栏 横向位置

    编辑2

    我使用了@AJ Macdonald提供的方法,但到目前为止运气不好。
    在Android活动中,我将当前片段保存在
    onSaveInstanceState(Bundle)
    方法中,并在
    onRestoreInstanceState(Bundle)
    方法中恢复我的片段,我恢复了我的后退按钮和当前的片段,但当我到达第三个片段时,错误仍然发生。我使用的包含4个片段,这会导致问题吗?只有在应用程序的这一部分发生。我有4个(主工作流)片段,在第一个、第二个和第三个片段上没有显示错误,仅在部分。给每个片段一个唯一的标记

    在活动的存储实例状态中存储当前片段。(如果您保留一个变量,在每次片段更改时自动更新,那么这可能是最容易做到的。)

    在活动的
    onCreate
    onRestoreInstanceState
    中,从保存的捆绑中拉出标记,并启动该类型的新片段

    public static final int FRAGMENT_A = 0;
    public static final int FRAGMENT_B = 1;
    
    private int currentFragment;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //other stuff
        if(savedInstanceState == null){
            addAreaFragment();
            currentFragment = FRAGMENT_A;
        }else{
            currentFragment = savedInstanceState.getInt("currentFragment");
            switch(currentFragment){
            case FRAGMENT_A:        
            addAreaFragment();
            break;
            case FRAGMENT_B:
            addFragmentB();
            }
        }
    }
    
    
    // when you switch fragment A for fragment B:
    currentFragment = FRAGMENT_B;
    
    
    @Override
        public void onSaveInstanceState(Bundle savedInstanceState) {
            savedInstanceState.putInt("currentFragment", currentFragment);
            super.onSaveInstanceState(savedInstanceState);
        }
    

    给每个片段一个唯一的标签

    在活动的存储实例状态中存储当前片段。(如果您保留一个变量,在每次片段更改时自动更新,那么这可能是最容易做到的。)

    在活动的
    onCreate
    onRestoreInstanceState
    中,从保存的捆绑中拉出标记,并启动该类型的新片段

    public static final int FRAGMENT_A = 0;
    public static final int FRAGMENT_B = 1;
    
    private int currentFragment;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //other stuff
        if(savedInstanceState == null){
            addAreaFragment();
            currentFragment = FRAGMENT_A;
        }else{
            currentFragment = savedInstanceState.getInt("currentFragment");
            switch(currentFragment){
            case FRAGMENT_A:        
            addAreaFragment();
            break;
            case FRAGMENT_B:
            addFragmentB();
            }
        }
    }
    
    
    // when you switch fragment A for fragment B:
    currentFragment = FRAGMENT_B;
    
    
    @Override
        public void onSaveInstanceState(Bundle savedInstanceState) {
            savedInstanceState.putInt("currentFragment", currentFragment);
            super.onSaveInstanceState(savedInstanceState);
        }
    

    建议尝试使用
    FragmentTransaction.commitAllowingStateLoss()
    代替
    FragmentTransaction.commit()
    。这应该可以阻止抛出异常,但缺点是如果再次旋转设备,UI的最新状态可能不会返回。这是一个建议,因为我不确定使用
    FragmentTabHost
    是否有任何效果。

    一个尝试的建议是使用
    FragmentTransaction.commitAllowingStateLoss()
    代替
    FragmentTransaction.commit()
    。这应该可以阻止抛出异常,但缺点是如果再次旋转设备,UI的最新状态可能不会返回。这是一个建议,因为我不确定使用
    FragmentTabHost
    的效果,如果它有任何效果的话。

    您在什么时候尝试提交事务?是在
    活动
    生命周期回调期间,如
    onPause
    onStop
    ?不是,我有一个片段使用FragmentTabHost,当设备旋转时,它用网格显示片段,用户选择一个单元格,然后添加一个新片段,它在使用FragmentTransaction时不在该点。commit()您试图在什么时候提交事务?是在
    活动
    生命周期回调期间,如
    onPause
    onStop
    ?不是,我有一个片段使用FragmentTabHost,当设备旋转时,它用网格显示片段,用户选择一个单元格,然后添加一个新片段,它在使用FragmentTransaction时不在该点。commit()我使用类名作为片段的标记。但是例如,为了启动片段B,它向vía传递了一个静态newInstance(…)方法的一些数据。如果你传递给片段B的数据是基元类型,你也可以尝试将它保存到savedInstanceState包中。我想不出任何简单的方法来处理非原始对象。我认为当活动被重新创建时,后台将会丢失。您可能能够将带有所有backbackback片段标记的ArrayList存储到bundle中。。。然后,在onCreate中,使用该列表