我正在使用 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
一些功能),所以我仍在努力。
热点提示:
.commit
听起来是最终的,不是吗?听起来好像应该同步?两者都不是真的。
.commit
将事务放入待处理队列中,要真正执行它,您需要:
getSupportFragmentManager().executePendingTransactions();
以下是已发布代码轮换错误日志的链接: link error log
关于android - IllegalStateException when .replace fragment on restart,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40639507/