重启时.replace片段时出现IllegalStateException

Al *_*ath 8 android illegalstateexception android-fragments

FragmentTransaction.replace()用来交换碎片进出.该应用程序第一次启动没有问题.IllegalStateException由于savedInstanceState与提交新的片段事务之间存在冲突,因此在旋转设备时会抛出An .没有涉及AsyncTask.

一个StackOverflow问题建议将setContentView()呼叫置于其中onResumeFragments(),但这似乎没有效果.与...相同onPostResume().

另一个StackOverflow问题说要覆盖onConfigurationChanged().从某种意义上说,这是因为没有重新启动Activity,所以不会发生异常.但是,这可以防止具有不同纵向和横向布局的片段在这些布局之间切换.调用setContentView()onConfigurationChanged() 导致类似的错误(抛出:IllegalArgumentException:二进制XML文件行#25:复制ID为0x12345678,标记为空,或父ID与另一片段)

使用fragmentTransaction.commitAllowingStateLoss()而不是.commit()原因IllegalStateException:Activity已被销毁.

我如何让它工作?

更多异常信息:

了java.lang.RuntimeException:无法启动活动ComponentInfo {MYAPP/myap.MainActivity}:
android.view.InflateException:二进制XML文件行#25:myapp.MainActivity.onResumeFragments(MainActivity.java:450)错误充气类片段
引起by:java.lang.IllegalStateException:无法在myapp.fragments.FragmentChange.onFragmentChange(FragmentChange.java:128)的> android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1533)的onSaveInstanceState之后执行此操作at myapp.MainActivity.onNavigationDrawerItemSelected(MainActivity.java:490)myapp.fragments.NavigationDrawerFragment.selectItem(NavigationDrawerFragment.java:197)at myapp.fragments.NavigationDrawerFragment.onCreate(NavigationDrawerFragment.java:78)at myapp.MainActivity.onResumeFragments( MainActivity.java:450)

旋转设备时代码中的顺序是:

MainActivity.onPause()  
MainActivity.saveInstanceState()  
NavigationDrawerFragment.onSaveInstanceState()  
MainActivity.onStop()
MainActivity.onDestroy()
MainActivity.onCreate()
    super.onCreate(savedInstanceState);
MainActivity.onResumeFragments()
    setContentView()
NavigationDrawerFragment.onCreate()
MainActivity.onNavigationDrawerItemSelected()
     fragmentTransaction.commit();
Run Code Online (Sandbox Code Playgroud)

主要活动:

public class MainActivity extends AppCompatActivity implements
        NavigationDrawerFragment.NavigationDrawerCallbacks {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
    }


    @Override
    public void onNavigationDrawerItemSelected(int position) {
        ...
        FragmentChangeEvent fragmentChangeEvent = new FragmentChangeEvent(null);
        FragmentChange fragmentChange = FragmentChange.getInstance( getSupportFragmentManager());
        fragmentChange.onFragmentChange(fragmentChangeEvent);
        ...
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onResumeFragments() {
        super.onResumeFragments(); 

        // causes onNavigationDrawerItemSelected() to be called, exception thrown 
        setContentView(myapp.R.layout.activity_main);

        mNavigationDrawerFragment = (NavigationDrawerFragment)
                getSupportFragmentManager().findFragmentById(myapp.R.id.navigation_drawer);

        mNavigationDrawerFragment.setUp( // Set up the drawer
                myapp.R.id.navigation_drawer,
                (DrawerLayout) findViewById(myapp.R.id.drawer_layout));
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        if current fragment is "Individual" { // pseudocode
            setContentView(R.layout.activity_main); // causes IllegalArgumentException
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

NavigationDrawerFragment

public class NavigationDrawerFragment extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
        mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);

        if (savedInstanceState != null) {
            mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
            mFromSavedInstanceState = true;
        }

        // Select either the default item (0) or the last selected item.
        selectItem(mCurrentSelectedPosition);
    }

    private void selectItem(int position) {

        mCurrentSelectedPosition = position;
        if (mDrawerListView != null) {
            mDrawerListView.setItemChecked(position, true);
        }
        if (mDrawerLayout != null) {
            mDrawerLayout.closeDrawer(mFragmentContainerView);
        }
        if (mCallbacks != null) {
            // calls MainActivity.onNavigationDrawerItemSelected() 
            mCallbacks.onNavigationDrawerItemSelected(position);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
    }

}
Run Code Online (Sandbox Code Playgroud)

FragmentChange

public class FragmentChange implements FragmentChangeListener {

      public static FragmentChange getInstance(FragmentManager fragmentManager) {
        if (instance == null) {
            instance = new FragmentChange(fragmentManager);
        }
        return instance;
    }

    // constructor
    private FragmentChange(FragmentManager fragmentManager) {
        mFragmentManager = fragmentManager;
    }

    @Override
    public void onFragmentChange(FragmentChangeEvent fragmentChangeEvent) {
        ...
        mPosition = fragmentChangeEvent.getPosition();

        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
        Fragment fragment = EmployeesVerticalFragment.newInstance();
        fragmentTransaction.replace(myapp.R.id.container, fragment);

        fragmentTransaction.commit(); // IllegalState exception here
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

github上一个大大减少的项目形式,它重现了IllegalStateException:

rds*_*rds 1

FragmentManager 是一个

用于与Activity 内部的Fragment 对象交互的接口。

在我看来,将其保存在静态字段中并为新活动重用旧的 FragmentManager 是一个特别糟糕的主意。当新活动与旧活动的管理器交互时,这必然会导致活动被销毁。

在您的代码中,替换

FragmentChange.getInstance(getFragmentManager());
Run Code Online (Sandbox Code Playgroud)

经过

new FragmentChange(getFragmentManager());
Run Code Online (Sandbox Code Playgroud)