【发布时间】:2016-11-29 19:03:59
【问题描述】:
我正在使用FragmentTransaction.replace() 来交换片段。
该应用程序第一次启动没有问题。
由于 savedInstanceState 之间的冲突,旋转设备时会抛出 IllegalStateException
并提交一个新的片段事务。
不涉及 AsyncTask。
一个 StackOverflow 问题建议将 setContentView() 调用
在onResumeFragments(),但这似乎没有效果。与onPostResume() 相同。
另一个 StackOverflow 问题说要覆盖 onConfigurationChanged()。这在这个意义上是有效的,它不会发生异常
因为 Activity 没有重新启动。但是,这可以防止具有不同肖像的片段
和横向布局从这些布局之间切换。在onConfigurationChanged() 中调用setContentView()
导致类似的错误(IllegalArgumentException: Binary XML file line #25: Duplicate id 0x12345678, tag null, or parent id with another fragment)
使用fragmentTransaction.commitAllowingStateLoss() 而不是.commit() 会导致IllegalStateException: Activity 已被销毁。
如何让它工作?
更多异常信息:
java.lang.RuntimeException: 无法启动 活动组件信息{myapp/myap.MainActivity}:
android.view.InflateException:二进制 XML 文件第 25 行:错误 膨胀类片段 myapp.MainActivity.onResumeFragments(MainActivity.java:450)
引起:java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at > android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1533) 在 myapp.fragments.FragmentChange.onFragmentChange(FragmentChange.java:128) 在 myapp.MainActivity.onNavigationDrawerItemSelected(MainActivity.java:490) 在 myapp.fragments.NavigationDrawerFragment.selectItem(NavigationDrawerFragment.java:197) 在 myapp.fragments.NavigationDrawerFragment.onCreate(NavigationDrawerFragment.java:78) 在 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();
主活动:
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
}
}
}
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);
}
}
片段变化
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:
【问题讨论】:
-
我不是要贬低你的问题,但你的问题已经被问过无数次了;授予我没有查看您的代码(感谢您发布它,顺便说一句),但我相信您会从阅读更多有关 FragmentManager、Fragments 和 Lifecycle 工作原理的信息中受益。这让人头疼,很奇怪,它有这么多的错误,以至于谷歌在谷歌 I/O 期间专门做了一个完整的会议(称为什么片段?)(我建议你看一下,这很有趣)。然后重新访问您的代码以减少崩溃的可能性。 :)
-
感谢您的回复。我知道以前关于 IllegalStateException 的问题。我已经尝试了这些建议,但还没有任何效果。我现在已经看了视频,但我比以前不知道了。
-
很抱歉您没有找到相关的视频或有帮助的视频。场景总是相似的:当你旋转一个活动时,它会被销毁。在此发生之前,必须调用 onSaveInstance(以便稍后重新创建它)。片段是这些奇怪的东西,它们以某种方式有自己的生命周期,有点与活动相关,但并非总是如此,你试图对没有活动的片段进行操作(被破坏/被重新创建),或者(如果你覆盖某些方法)你'在保存状态后尝试对片段进行操作。我有一个问题要问你,但下一个评论,因为它不适合
-
所以让我们看看,一旦用户点击导航抽屉,您想要替换片段,或者您想要在发生这种情况时更改现有片段的布局。您的片段是否有一个公共的空无参数构造函数? (需要)
标签: android android-fragments illegalstateexception