IllegalStateException: Can not perform this action after onSaveInstanceState
Android FragmentManager использует пакет savedInstanceState
для отслеживания того, какие фрагменты в данный момент отображаются пользователю.Если состояние сохраняется, и вы пытаетесь выполнить фрагментную транзакцию, система падает, потому что транзакция никогда не будет видна пользователю.
В более новых версиях библиотеки поддержки предлагается метод isStateSaved()
для FragmentManager, который выможно использовать, чтобы проверить, действительно ли вы находитесь в безопасном окне, чтобы показать диалоговое окно.
@Override
public void displayError(int messageId) {
FragmentManager fm = getFragmentManager();
if (!fm.isStateSaved()) {
AppUtil.showErrorDialog(fm, R.string.app_name);
}
}
Однако это все равно оставляет проблему.Если AsyncTask завершает работу и пытается показать ошибку, когда состояние уже сохранено, пользователь никогда не увидит ошибку.
Вы можете получить запись приложения, в которой попытался показать ошибку, а затем также выполните проверку, когда ваше приложение возобновляет работу, чтобы увидеть, должно ли оно показывать ошибку сейчас.Нам нужно место для сохранения информации, которую мы пытались показать в диалоговом окне, и это не может быть просто boolean
для действия / фрагмента (потому что это может привести к той же проблеме сохранения состояния).Я рекомендую SharedPreferences
для хранения информации.
Добавьте этот код к вашему фрагменту:
private static final String SHOW_DIALOG = "SHOW_DIALOG";
private SharedPreferences getSharedPreferences() {
return getActivity().getPreferences(Context.MODE_PRIVATE);
}
И затем используйте этот код, чтобы отобразить диалоговое окно:
@Override
public void displayError(int messageId) {
FragmentManager fm = getFragmentManager();
if (!fm.isStateSaved()) {
AppUtil.showErrorDialog(getFragmentManager(), R.string.app_name);
} else {
getSharedPreferences()
.edit()
.putBoolean(SHOW_DIALOG, true)
.apply();
}
}
И этот код для отображения диалогового окна при возобновлении работы приложения:
@Override
public void onResume() {
super.onResume();
SharedPreferences prefs = getSharedPreferences();
boolean triedToShowInBackground = prefs.getBoolean(SHOW_DIALOG, false);
if (triedToShowInBackground) {
AppUtil.showErrorDialog(getFragmentManager(), R.string.app_name);
prefs.edit().remove(SHOW_DIALOG).apply();
}
}