android - IllegalStateException when .replace fragment on restart

标签 android android-fragments illegalstateexception

我正在使用 FragmentTransaction.replace() 来交换 fragment 。 该应用程序首次启动没有问题。 由于 savedInstanceState 之间的冲突,旋转设备时抛出 IllegalStateException 并提交一个新的 fragment 事务。 不涉及 AsyncTask。

一个 StackOverflow 问题建议调用 setContentView()onResumeFragments()中,但这似乎没有效果。与 onPostResume() 相同。

另一个 StackOverflow 问题说要覆盖 onConfigurationChanged()。从这个意义上说,这是有效的,因为它不会发生异常 因为 Activity 没有重启。但是,这可以防止具有不同肖像的 fragment 和横向布局在这些布局之间切换。在 onConfigurationChanged() 中调用 setContentView() 导致类似的错误(IllegalArgumentException:二进制 XML 文件第 25 行:重复 ID 0x12345678、标记为空或父 ID 与另一个 fragment )

使用 fragmentTransaction.commitAllowingStateLoss() 而不是 .commit() 会导致 IllegalStateException: Activity has been destroyed

我如何让它工作?

更多异常信息:

java.lang.RuntimeException: Unable to start activity ComponentInfo{myapp/myap.MainActivity}:
android.view.InflateException: Binary XML file line #25: Error inflating class fragment at myapp.MainActivity.onResumeFragments(MainActivity.java:450)
Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at > android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1533) at myapp.fragments.FragmentChange.onFragmentChange(FragmentChange.java:128) at myapp.MainActivity.onNavigationDrawerItemSelected(MainActivity.java:490) at 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();

主要 Activity :

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
        }
    }
}

抽屉导航 fragment

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);
    }

}

fragment 变化

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
        ...
    }
}

大大减少的 form of the project on github 重现了 IllegalStateException:

最佳答案

一些评论:
我可以看到您已经“超越”尝试修复它(并且已经扫描了 stackoverflow 以获取许多提示)。
您的代码第一次工作(即使您在横向 b4 启动应用程序)。
旋转未能使 fragment 膨胀(第二次)(在 activity_main 中),并且还报告“保存后提交”错误(这很奇怪,我们到底是怎么得到 2 个 fatal error 的?也许在另一个线程,或“保存”正在杀死充气机,但它如何继续?)。
NavigationDrawerFragment 中有很多重要代码(通常在 Activity 中)。
分析:
您的 MainActivity扩展了 AppCompatActivity:

public class MainActivity extends AppCompatActivity implements
        NavigationDrawerFragment.NavigationDrawerCallbacks {

通常你扩展FragmentActivity:

public class MainActivity extends FragmentActivity implements
NavigationDrawerFragment.NavigationDrawerCallbacks {

这是因为您膨胀了 activity_main,它包含一个 fragment

setContentView(com.example.replacefragments.R.layout.activity_main);

继承: Activity <- FragmentActivity <- AppCompatActivity <- ActionBarActivity
'<-'在这里表示继承。
您需要特别考虑 FragmentActivity 的一个原因是,如果您想使用嵌套 fragment (一个 fragment 包含另一个 fragment ),因为在 API 级别 17 之前, native fragment 不支持它。
我认为这就是您在这里所做的(在 activity_main 中):

<fragment android:id="@+id/navigation_drawer

这是一个不错的模板应用程序,可以让您的生活更轻松:
android-sliding-menu-using-navigation-drawer/
修复它:
activity_main.xml 中的 fragment 替换为 ListView
我已经丢弃了NavigationDrawerFragment,并从上面的模板中注入(inject)了一些代码,然后从NavigationDrawerFragment中一点一点地重新引入你的代码,直到它倒下。 它现在可以旋转,但不是你或我想要的(保留 fragment 状态,NavigationDrawerFragment 一些功能),所以我仍在努力。

特性
protrait
旋转后横向
landscape after rotation

热点提示: .commit 听起来是最终的,不是吗?听起来好像应该同步?两者都不是真的。
.commit 将事务放入待处理队列中,要真正执行它,您需要:

getSupportFragmentManager().executePendingTransactions();

以下是已发布代码轮换错误日志的链接: link error log

关于android - IllegalStateException when .replace fragment on restart,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40639507/

相关文章:

Android,如何获取文件夹中所有文件的列表?

android - 应用小部件中的 AdapterViewFlipper : setPendingIntentTemplate() and setOnClickFillInIntent() not working

android - 在后台 Activity 时关闭 DialogFragment(支持库)获取 IllegalStateException

php - 通过 php 和 JSON 将 android 应用程序连接到 MySQL

android - SQLiteException 当联系人有照片时无法将 BLOB 转换为字符串。安卓

java - android: 帮助 webview 无法从 listview fragment 打开

android - 具有透明背景的 PreferenceFragment?

android - 如何禁用android map 标记点击自动中心

java - 如何在Android中使用on循环在onCreate()中启动多个线程而又未使用for循环启动线程(IllegalThreadStateException)?

java - 响应已提交 - java.lang.IllegalStateException : UT010019