У меня есть приложение Live Android, и с маркета я получил следующую трассировку стека, и я понятия не имею, почему это происходит, потому что это происходит не в коде приложения, а вызвано тем или иным событием из приложения (предположение)
Я не использую фрагменты, но есть ссылка на FragmentManager. Если какое-либо тело может пролить некоторый свет на некоторые скрытые факты, чтобы избежать этого типа проблемы:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyDown(Activity.java:1962)
at android.view.KeyEvent.dispatch(KeyEvent.java:2482)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1720)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1258)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2851)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2824)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2011)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4025)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Ответы:
Это самая глупая ошибка, с которой я когда-либо сталкивался. У меня было
Fragment
приложение, отлично работающее для API <11 , иForce Closing
для API> 11 .Я действительно не мог понять, что они изменили внутри
Activity
жизненного цикла в вызовеsaveInstance
, но я вот как я решил это:Я просто не звоню
.super()
и все отлично работает. Надеюсь, это сэкономит вам время.РЕДАКТИРОВАТЬ: после некоторых дополнительных исследований, это известная ошибка в пакете поддержки.
Если вам нужно сохранить экземпляр и добавить что-то в свой,
outState
Bundle
вы можете использовать следующее:EDIT2: это также может произойти, если вы пытаетесь выполнить транзакцию после того, как ваш
Activity
ушел в фоновом режиме. Чтобы избежать этого, вы должны использоватьcommitAllowingStateLoss()
EDIT3: вышеупомянутые решения исправляли проблемы в ранних библиотеках support.v4 из того, что я помню. Но если у вас все еще есть проблемы с этим, вы ДОЛЖНЫ также прочитать блог @AlexLockwood : Потеря транзакций и активности фрагментов
Резюме из поста в блоге (но я настоятельно рекомендую вам прочитать его):
commit()
транзакции послеonPause()
до соты иonStop()
после сотыActivity
методов жизненного цикла. ИспользованиеonCreate()
,onResumeFragments()
иonPostResume()
commitAllowingStateLoss()
только в крайнем случаеисточник
commitAllowingStateLoss()
только избегает исключения. Это не защищает ваше приложение от случайной потери состояния. Смотрите этот пост в блоге .Поиск исходного кода Android о причинах этой проблемы показывает, что флаг mStateSaved в
FragmentManagerImpl
классе (экземпляр доступен в Activity) имеет значение true. Он имеет значение true, когда задний стек сохраняется (saveAllState) при вызове изActivity#onSaveInstanceState
. После этого вызовы из ActivityThread не сбрасывают этот флаг, используя доступные методы сбросаFragmentManagerImpl#noteStateNotSaved()
иdispatch()
.На мой взгляд, есть несколько доступных исправлений, в зависимости от того, что делает и использует ваше приложение:
Хорошие способы
Прежде всего: я бы рекламировал статью Алекса Локвуда . Тогда из того, что я сделал до сих пор:
Для фрагментов и действий, которым не нужно хранить информацию о состоянии, вызовите commitAllowStateLoss . Взято из документации:
Сразу после того, как транзакция зафиксирована (вы только что звонили
commit()
), позвонитеFragmentManager.executePendingTransactions()
.Не рекомендуемые способы:
Как упоминал Овидиу Латку, не звоните
super.onSaveInstanceState()
. Но это означает, что вы потеряете все состояние своей активности вместе с состоянием фрагментов.Переопределить
onBackPressed
и только там вызовfinish()
. Это должно быть нормально, если ваше приложение не использует Fragments API; какsuper.onBackPressed
там есть вызовFragmentManager#popBackStackImmediate()
.Если вы используете API Fragments и состояние вашей активности важно / важно, то вы можете попытаться позвонить с помощью Reflection API
FragmentManagerImpl#noteStateNotSaved()
. Но это взлом, или можно сказать, что это обходной путь. Мне это не нравится, но в моем случае это вполне приемлемо, поскольку у меня есть код из унаследованного приложения, в котором используется устаревший код (TabActivity
и неявноLocalActivityManager
).Ниже приведен код, который использует отражение:
Ура!
источник
Такое исключение произойдет, если вы попытаетесь выполнить переход фрагмента после вызова вашей активности фрагмента
onSaveInstanceState()
.Одна из причин, по которой это может произойти, это то, что вы оставляете
AsyncTask
(илиThread
) запущенным, когда действие прекращается.Любые переходы после
onSaveInstanceState()
вызова могут быть потеряны, если система восстановит активность для ресурсов и создаст ее позже.источник
super.onSaveInstanceState()
.Просто вызовите super.onPostResume () перед показом вашего фрагмента или переместите код в метод onPostResume () после вызова super.onPostResume (). Это решит проблему!
источник
Это также может произойти при звонке
dismiss()
фрагмента диалога после того, как экран был заблокирован \ заглушен, а состояние экземпляра диалога Activity + сохранено. Чтобы обойти этот вызов:Буквально каждый раз, когда я закрываю диалог, я все равно больше не волнуюсь о его состоянии, так что это нормально - вы фактически не теряете ни одно состояние.
источник
Краткое и рабочее решение:
Следуйте простым шагам:
Шаг 1 : Переопределить состояние onSaveInstanceState в соответствующем фрагменте. И удалите супер метод из него.
Шаг 2 : Используйте CommitAllowingStateLoss (); вместо commit (); пока фрагмент операции.
источник
Я думаю, что состояние жизненного цикла может помочь предотвратить такой сбой, начиная с поддержки Android lib v26.1.0, вы можете выполнить следующую проверку:
или вы можете попробовать:
дополнительная информация здесь https://developer.android.com/reference/android/support/v4/app/Fragment.html#isStateSaved ()
источник
это сработало для меня ... выяснил это самостоятельно ... надеюсь, это поможет вам!
1) НЕ имеет глобальной «статической» FragmentManager / FragmentTransaction.
2) onCreate, ВСЕГДА инициализируйте FragmentManager снова!
образец ниже: -
источник
Я всегда получал это, когда пытался показать фрагмент в методе onActivityForResult (), поэтому проблема была в следующем:
Я сделал следующее:
источник
Я решил проблему с onconfiguration изменился. Хитрость заключается в том, что в соответствии с жизненным циклом активности андроида, когда вы явно называете намерение (намерение камеры или любое другое); в этом случае действие приостанавливается и вызывается onsavedInstance. При повороте устройства в другое положение, отличное от того, во время которого активность была активной; выполнение операций фрагмента, таких как фиксация фрагмента, вызывает недопустимое исключение состояния. Есть много жалоб на это. Это что-то про управление жизненным циклом активности андроида и правильные вызовы методов. Чтобы решить эту проблему, я сделал это: 1-Переопределите метод onsavedInstance своей деятельности и определите текущую ориентацию экрана (книжную или альбомную), а затем установите ориентацию экрана до того, как ваша деятельность будет приостановлена. таким образом, действие блокирует поворот экрана для вашего действия, если оно было повернуто другим. 2-затем, переопределите метод действия onresume и установите режим ориентации сейчас на датчик, чтобы после вызова onsaved-метода он вызывал еще раз onconfiguration для правильной обработки вращения.
Вы можете скопировать / вставить этот код в свою деятельность, чтобы справиться с ним:
источник
У меня была такая же проблема, получение IllegalStateException, но замена всех моих вызовов commit () на commitAllowingStateLoss () не помогла.
Виновником был вызов DialogFragment.show ().
Я окружаю это
и это сделало это. ОК, я не могу показать диалог, но в этом случае все было в порядке.
Это было единственное место в моем приложении, где я сначала вызвал FragmentManager.beginTransaction (), но никогда не вызывал commit (), поэтому я не нашел его, когда искал «commit ()».
Самое смешное, что пользователь никогда не покидает приложение. Вместо этого убийца был рекламным объявлением AdMob.
источник
Мое решение этой проблемы было
Во фрагмент добавьте методы:
Может быть плохо, но не мог найти ничего лучше.
источник
Я получил эту проблему. Но я думаю, что эта проблема не связана с commit и commitAllowStateLoss.
Следующее сообщение трассировки и исключения стека относится к commit ().
Но это исключение было вызвано onBackPressed ()
Все они были вызваны checkStateLoss ()
mStateSaved будет true после onSaveInstanceState.
Эта проблема встречается редко. Я никогда не сталкивался с этой проблемой. Я не могу повторить проблему.
я нашел вопрос 25517
Это могло произойти при следующих обстоятельствах
Клавиша Back вызывается после onSaveInstanceState, но до начала нового действия.
используйте onStop () в коде
Я не уверен, в чем корень проблемы. Поэтому я использовал некрасивый способ.
источник
У меня та же проблема в моем приложении. Я решил эту проблему, просто вызвав
super.onBackPressed();
предыдущий класс и вызвавcommitAllowingStateLoss()
текущий класс с этим фрагментом.источник
commitAllowingStateLoss()
вместоcommit()
onSaveInstance будет вызываться, если пользователь поворачивает экран, чтобы он мог загружать ресурсы, связанные с новой ориентацией.
Возможно, что этот пользователь повернул экран, а затем нажал кнопку «Назад» (потому что также возможно, что этот пользователь шарил по телефону во время использования вашего приложения)
источник
Читайте http://chris-alexander.co.uk/on-engineering/dev/android-fragments-within-fragments/
статья. Проверка frag.isResumed () помогает мне в onDestroyView без использования метода onSaveInstanceState.
источник
Та же проблема от меня, и после однодневного анализа всех статей, блогов и стекового потока я нашел простое решение. Ни в коем случае не используйте saveInstanceState, это условие с одной строкой кода. По коду фрагмента:
источник
Это происходит всякий раз, когда вы пытаетесь загрузить фрагмент, но действие изменило свое состояние на onPause (). Это происходит, например, когда вы пытаетесь получить данные и загрузить их в действие, но к тому времени, когда пользователь нажал какую-то кнопку и перешел к следующему виду деятельности.
Вы можете решить это двумя способами
Для загрузки фрагмента вы можете использовать транзакциюmit.mitAllowingStateLoss () вместо транзакции транзакции (), но в итоге вы можете потерять выполненную операцию фиксации.
или
Убедитесь, что при загрузке фрагмента активность возобновлена и она не собирается приостанавливаться. Создайте логическое значение и проверьте, не переходит ли действие в состояние onPause ().
затем при загрузке фрагмента проверьте, присутствует ли активность, и загружайте только, когда активность находится на переднем плане.
источник
Спасибо @gunar, но я думаю, что есть лучший способ.
Согласно доку:
Так что используйте
commitNow
для замены:источник
Хорошо, после попытки всех вышеупомянутых решений без успеха (потому что в основном у меня нет транзакций).
В моем случае я использовал AlertDialogs и ProgressDialog в качестве фрагментов, которые иногда при ротации при запросе FragmentManager возникает ошибка.
Я нашел обходной путь, смешивающий много похожих постов:
Это трехэтапное решение, все сделано на вашей FragmentActivity (в данном случае его называют GenericActivity):
источник
Когда я использую стартовую активность в одном фрагменте, я получу это исключение;
Когда я перехожу на использование startactivityforresult, исключение исчезает :)
Поэтому простой способ исправить это - использовать API startActivityForResult :)
источник
Я получал это исключение, когда нажимал кнопку «Назад», чтобы отменить выбор намерения на фрагменте карты. Я решил эту проблему, заменив код onResume () (где я инициализировал фрагмент и выполнял транзакцию) на onStart (), и теперь приложение работает нормально. Надеюсь, поможет.
источник
Это исправлено в Android 4.2, а также в источнике библиотеки поддержки. [*]
Подробнее о причине (и способах ее устранения) см. В отчете об ошибках Google: http://code.google.com/p/android/issues/detail?id=19917.
Если вы используете библиотеку поддержки, вам не нужно беспокоиться об этой ошибке (надолго) [*]. Однако, если вы используете API напрямую (т.е. не используете FragmentManager библиотеки поддержки) и нацеливаетесь на API ниже Android 4.2, вам придется попробовать один из обходных путей.
[*] На момент написания Android SDK Manager все еще распространял старую версию с этой ошибкой.
Редактировать Я собираюсь добавить некоторые пояснения здесь, потому что я, очевидно, каким-то образом запутал того, кто отрицал этот ответ.
Есть несколько различных (но связанных) обстоятельств, которые могут вызвать это исключение . Мой ответ выше относится к конкретному случаю, обсуждаемому в вопросе, т.е. к ошибке в Android, которая впоследствии была исправлена. Если вы получаете это исключение по другой причине, это потому, что вы добавляете / удаляете фрагменты, когда этого не должно быть (после того, как состояния фрагментов были сохранены). Если вы находитесь в такой ситуации, то вам может пригодиться « Вложенные фрагменты - IllegalStateException« Не удается выполнить это действие после onSaveInstanceState » ».
источник
После небольшого исследования решение этой проблемы состоит в том, чтобы сделать ваши фрагменты коммитами в onresume.
Источник: https://wenchaojames.wordpress.com/2013/01/12/illegalstateexception-from-onactivityresult/
источник
Мой вариант использования: я использовал слушателя во фрагменте, чтобы уведомить активность, что что-то произошло. Я сделал новый фрагмент коммита на методе обратного вызова. Это отлично работает в первый раз. Но при изменении ориентации активность воссоздается с сохраненным состоянием экземпляра. В этом случае фрагмент не создается снова означает, что фрагмент имеет прослушиватель, который является старой уничтоженной активностью. В любом случае метод обратного вызова будет запущен в действии. Это идет к разрушенной деятельности, которая вызывает проблему. Решение состоит в том, чтобы сбросить слушателя во фрагменте с текущей активностью. Это решит проблему.
источник
Я обнаружил, что если другое приложение имеет тип диалога и позволяет отправлять штрихи в фоновое приложение, то почти любое фоновое приложение завершится с этой ошибкой. Я думаю, что мы должны проверять каждый раз, когда выполняется транзакция, был ли экземпляр сохранен или восстановлен.
источник
В моем случае, с тем же исключением ошибки, я поместил onBackPressed () в runnable (вы можете использовать любой вид):
Я не понимаю почему, но это работает!
источник
Вы можете вызывать фрагментManager.popBackStackImmediate (); когда активность приостановлена. Деятельность не завершена, но приостановлена и не на переднем плане. Вам нужно проверить, приостановлена ли активность перед popBackStackImmediate ().
источник
Я заметил кое-что очень интересное. У меня в приложении есть возможность открыть галерею телефона, и устройство спрашивает, какое приложение использовать, там я нажимаю на серую область вдали от диалогового окна и вижу эту проблему. Я заметил, как моя деятельность переходит от onPause, onSaveInstanceState обратно к onResume, не происходит посещение onCreateView. Я делаю транзакции в onResume. Итак, что я в итоге сделал, так это установил флаг, отменяющий onPause, но являющийся истинным onCreateView. если флаг равен true onResume, тогда делайте onCommit, иначе commitAllowingStateLoss. Я мог бы продолжать и тратить столько времени, но я хотел проверить жизненный цикл. У меня есть устройство, которое является sdkversion 23, и я не получаю эту проблему, но у меня есть другое, которое является 21, и там я вижу его.
источник
вы можете использовать FragmentActivity.onStart перед popBackStackImmediate
нравится:
http://jorryliu.blogspot.com/2014/09/illegalstateexception-can-not-perform.html
источник