Я получаю пользовательские отчеты из моего приложения на рынке, за исключением следующего:
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.onKeyUp(Activity.java:2044)
at android.view.KeyEvent.dispatch(KeyEvent.java:2529)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
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:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
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.widget.TabHost.dispatchKeyEvent(TabHost.java:297)
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:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2880)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2853)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2028)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4028)
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:844)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
at dalvik.system.NativeStart.main(Native Method)
Очевидно, это как-то связано с FragmentManager, которым я не пользуюсь. В трассировке стека нет ни одного из моих собственных классов, поэтому я понятия не имею, где происходит это исключение и как его предотвратить.
Для записи: у меня есть вкладка, и на каждой вкладке есть группа действий, переключающаяся между действиями.
FragmentManager
, Honeycomb, безусловно, есть. Это происходит на настоящих сотовых планшетах? Или, может быть, кто-то запускает взломанный Honeycomb на телефоне или что-то в этом роде, и у этого взломанного издания возникают трудности?Ответы:
Пожалуйста, проверьте мой ответ здесь . В основном мне просто нужно было:
Не делайте вызов
super()
поsaveInstanceState
методе. Это все испортило ...Это известная ошибка в пакете поддержки.
Если вам нужно сохранить экземпляр и добавить что-то в свой,
outState
Bundle
вы можете использовать следующее:В конце концов, правильное решение было (как видно из комментариев) использовать:
при добавлении или выполнении того,
FragmentTransaction
что вызывалоException
.источник
popBackStackImmediate
него сразу же не удается, если состояние было сохранено. Предварительное добавление фрагмента с помощьюcommitAllowingStateLoss
не играет никакой роли. Мое тестирование показывает, что это правда. Это не влияет на это конкретное исключение. Нам нуженpopBackStackImmediateAllowingStateLoss
метод.Есть много связанных проблем с похожим сообщением об ошибке. Проверьте вторую строку этой конкретной трассировки стека. Это исключение специально связано с призывом к
FragmentManagerImpl.popBackStackImmediate
.Этот вызов метода, как
popBackStack
, всегда будет терпеть неудачу,IllegalStateException
если состояние сеанса уже было сохранено. Проверьте источник. Вы ничего не можете сделать, чтобы остановить это исключение.super.onSaveInstanceState
не поможет.commitAllowingStateLoss
помощью не поможет.Вот как я заметил проблему:
onSaveInstanceState
вызывается.popBackStackImmediate
предпринимается попытка.IllegalStateException
брошенВот что я сделал, чтобы решить это:
Поскольку невозможно избежать
IllegalStateException
обратного вызова, поймайте и проигнорируйте его.Этого достаточно, чтобы остановить сбой приложения. Но теперь пользователь восстановит приложение и увидит, что кнопка, которую, как они думали, нажали, вообще не была нажата (они думают). Фрагмент формы все еще показывает!
Чтобы исправить это, когда диалоговое окно создано, создайте некоторое состояние, чтобы указать, что процесс запущен.
И сохраните это состояние в связке.
Не забудьте загрузить его снова в
onViewCreated
Затем при возобновлении отката фрагменты, если ранее была предпринята попытка отправки. Это предотвращает возвращение пользователя к тому, что выглядит как неподтвержденная форма.
источник
popBackStackImmediate
Android вызвал сам?Проверьте, если активность,
isFinishing()
прежде чем показывать фрагмент и обратите вниманиеcommitAllowingStateLoss()
.Пример:
источник
DialogFragment
. См. Stackoverflow.com/questions/15729138/… для других хороших решений, stackoverflow.com/a/41813953/2914140 помог мне.Это октябрь 2017 года, и Google создает библиотеку поддержки Android с новым компонентом Lifecycle. Это дает новую идею для этой проблемы «Не удается выполнить это действие после onSaveInstanceState».
Короче говоря:
Более длинная версия с объяснением:
почему эта проблема выходит?
Это потому, что вы пытаетесь использовать
FragmentManager
из своей деятельности (которая будет содержать ваш фрагмент, я полагаю?), Чтобы совершить транзакцию для вашего фрагмента. Обычно это выглядит так, как будто вы пытаетесь выполнить некоторую транзакцию для предстоящего фрагмента, в то время как действия хоста уже вызываютsavedInstanceState
метод (пользователь может коснуться кнопки «Домой», поэтому операция вызываетonStop()
, в моем случае это причина)Обычно такой проблемы не должно быть - мы всегда пытаемся загрузить фрагмент в действие в самом начале, как будто
onCreate()
метод является идеальным местом для этого. Но иногда это случается , особенно когда вы не можете решить, какой фрагмент вы будете загружать для этого действия, или вы пытаетесь загрузить фрагмент изAsyncTask
блока (или что-то займет немного времени). Время до того, как транзакция фрагмента действительно произойдет, но послеonCreate()
метода действия пользователь может сделать что угодно. Если пользователь нажмет кнопку «Домой», которая активируетonSavedInstanceState()
метод действия, произойдетcan not perform this action
сбой.Если кто-то хочет глубже в этом вопросе, я предлагаю им взглянуть на этот пост в блоге . Он смотрит глубоко в слой исходного кода и многое объясняет по этому поводу. Кроме того, это дает причину того, что вы не должны использовать
commitAllowingStateLoss()
метод для обхода этого сбоя (поверьте мне, он не предлагает ничего хорошего для вашего кода)Как это исправить?
Должен ли я использовать
commitAllowingStateLoss()
метод для загрузки фрагмента? Нет, ты не должен ;Должен ли я переопределить
onSaveInstanceState
метод, игнорироватьsuper
метод внутри него? Нет, ты не должен ;Должен ли я использовать магическую
isFinishing
внутреннюю активность, чтобы проверить, находится ли активность хоста в нужный момент для транзакции фрагмента? Да, это похоже на правильный способ сделать.Посмотрите, что такое жизненный цикл может сделать компонент .
По сути, Google делает некоторую реализацию внутри
AppCompatActivity
класса (и несколько других базовых классов, которые вы должны использовать в своем проекте), что упрощает определение текущего состояния жизненного цикла . Вспомните нашу проблему: почему эта проблема возникла? Это потому, что мы делаем что-то не в то время. Поэтому мы стараемся этого не делать, и эта проблема исчезнет.Я немного кодирую для своего собственного проекта, вот что я делаю, используя
LifeCycle
. Я код в Котлин.Как я покажу выше. Я проверю состояние жизненного цикла хост-активности. С компонентом жизненного цикла в библиотеке поддержки это может быть более конкретным. Код
lifecyclecurrentState.isAtLeast(Lifecycle.State.RESUMED)
означает, если текущее состояние хотя быonResume
, не позднее его? Что гарантирует, что мой метод не будет выполняться во время какого-либо другого состояния жизни (напримерonStop
).Это все сделано?
Конечно, нет. Код, который я показал, говорит о новом способе предотвращения сбоя приложения. Но если это действительно перейти к состоянию
onStop
, эта строка кода не будет работать и, следовательно, ничего не будет отображаться на вашем экране. Когда пользователи возвращаются в приложение, они видят пустой экран, это пустое действие хоста, на котором нет фрагментов вообще. Это плохой опыт (да, немного лучше, чем крушение).Так что здесь я хотел бы, чтобы могло быть что-то более приятное: приложение не зависнет, если оно придет в состояние позже
onResume
завершено, метод транзакции, учитывающий состояние жизни; кроме того, действие будет пытаться продолжить выполнение этого фрагмента транзакции после того, как пользователь вернется в наше приложение.Я добавлю кое-что еще к этому методу:
Я поддерживаю список внутри этого
dispatcher
класса, чтобы хранить эти фрагменты, у которых нет шансов завершить транзакцию. И когда пользователь возвращается с начального экрана и обнаруживает, что еще есть фрагмент, ожидающий запуска, он переходит кresume()
методу под@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
аннотацией. Теперь я думаю, что это должно работать так, как я ожидал.источник
FragmentDispatcher
использует список для хранения ожидающих фрагментов, если будет восстановлен только один фрагмент?Вот другое решение этой проблемы.
Используя закрытую переменную-член, вы можете установить возвращаемые данные как намерение, которое затем может быть обработано после super.onResume ();
Вот так:
источник
super.onActivityResult()
.Краткое и рабочее решение:
Следуйте простым шагам
меры
Шаг 1: Переопределить
onSaveInstanceState
состояние в соответствующем фрагменте. И удалите супер метод из него.Шаг 2: Используйте
fragmentTransaction.commitAllowingStateLoss( );
а не
fragmentTransaction.commit( );
пока фрагментные операции.источник
ОСТОРОЖНО , использование
transaction.commitAllowingStateLoss()
может привести к неудаче для пользователя. Для получения дополнительной информации о том, почему это исключение выдается, смотрите этот пост .источник
Я нашел грязное решение для такой проблемы. Если вы все еще хотите сохранить вашу информацию
ActivityGroups
по какой-либо причине (у меня были причины ограничения времени), вы просто реализуетев вашем
Activity
и сделать некоторыйback
код там. даже если на старых устройствах такого метода нет, этот метод вызывается более новыми.источник
Не используйте commitAllowingStateLoss (), его следует использовать только в тех случаях, когда вполне допустимо неожиданно изменить состояние пользовательского интерфейса для пользователя.
https://developer.android.com/reference/android/app/FragmentTransaction.html#commitAllowingStateLoss ()
Если транзакция происходит в ChildFragmentManager of parentFragment, используйте для проверки parentFragment.isResume () снаружи.
источник
У меня была похожая проблема, сценарий был такой:
OnCreate метод деятельности было так:
Исключение было вызвано тем, что при изменении конфигурации (устройство поворачивается) создается действие, основной фрагмент извлекается из истории диспетчера фрагментов, и в то же время фрагмент уже имеет ссылку OLD на уничтоженное действие.
Изменение реализации для этого решило проблему:
вам нужно устанавливать своих слушателей каждый раз при создании действия, чтобы избежать ситуации, когда фрагменты имеют ссылки на старые уничтоженные экземпляры действия.
источник
Если вы наследуете от
FragmentActivity
, вы должны вызвать суперкласс вonActivityResult()
:Если вы не сделаете этого и попытаетесь показать диалоговое окно фрагмента в этом методе, вы можете получить OP
IllegalStateException
. (Честно говоря, я не совсем понимаю, почему супер-вызов решает проблему.onActivityResult()
Вызывается раньшеonResume()
, поэтому по-прежнему нельзя показывать диалоговое окно фрагмента.)источник
Я получал это исключение, когда нажимал кнопку «Назад», чтобы отменить выбор намерения на фрагменте карты. Я решил это, заменив код onResume (где я инициализировал фрагмент) на onstart (), и приложение работает нормально. Надеюсь, это поможет.
источник
Я думаю, что использование
transaction.commitAllowingStateLoss();
не лучшее решение. Это исключение будет сгенерировано, когда конфигурация действия изменена, и фрагментonSavedInstanceState()
вызывается, и после этого Ваш метод асинхронного обратного вызова пытается зафиксировать фрагмент.Простым решением может быть проверка, меняет ли активность конфигурацию или нет
например проверить
isChangingConfigurations()
т.е.
if(!isChangingConfigurations()) { //commit transaction. }
Проверьте эту ссылку, а также
источник
Возможно, самое гладкое и простое решение, которое я нашел в моем случае, состояло в том, чтобы избежать выталкивания оскорбительного фрагмента из стека в ответ на результат активности. Так что меняю этот звонок по моему
onActivityResult()
:к этому:
помогло в моем случае.
источник
Если вы выполняете некоторую FragmentTransaction в onActivityResult, вы можете установить некоторое логическое значение внутри onActivityResult, тогда в onResume вы можете выполнить FragmentTransaction на основе логического значения. Пожалуйста, ознакомьтесь с кодом ниже.
источник
Вежливость: решение для IllegalStateException
Эта проблема раздражала меня много времени, но, к счастью, я нашел для нее конкретное решение. Подробное объяснение этого здесь .
Использование commitAllowStateloss () может предотвратить это исключение, но приведет к нарушениям пользовательского интерфейса. До сих пор мы понимали, что IllegalStateException встречается, когда мы пытаемся зафиксировать фрагмент после потери состояния Activity, поэтому мы должны просто отложить транзакцию до восстановления состояния . Это можно сделать просто так
Объявите две частные логические переменные
Теперь в onPostResume () и onPause мы устанавливаем и удаляем нашу логическую переменную isTransactionSafe. Идея состоит в том, чтобы помечать транзакции как безопасные только тогда, когда активность находится на переднем плане, поэтому нет шансов потерять состояние.
-То, что мы сделали до сих пор, спасет от IllegalStateException, но наши транзакции будут потеряны, если они будут выполнены после того, как действие переместится в фоновый режим, что-то вроде commitAllowStateloss (). Чтобы помочь с этим, у нас есть логическая переменная isTransactionPending
источник
Фрагмент транзакции не должен выполняться после
Activity.onStop()
! Убедитесь, что у вас нет обратных вызовов, которые могли бы выполнить транзакцию послеonStop()
. Лучше исправить причину, чем пытаться обойти проблему с помощью таких подходов, как.commitAllowingStateLoss()
источник
Начиная с версии 24.0.0 библиотеки поддержки, вы можете вызывать
FragmentTransaction.commitNow()
метод, который синхронно фиксирует эту транзакцию вместо вызова сcommit()
последующимexecutePendingTransactions()
. Как сказано в документации, этот подход еще лучше:источник
Всякий раз, когда вы пытаетесь загрузить фрагмент в вашей активности, убедитесь, что активность возобновлена и не собирается приостанавливать состояние. В состоянии паузы вы можете в конечном итоге потерять выполненную операцию фиксации.
Вы можете использовать транзакцииmit.comlAllowingStateLoss () вместоaction.commit () для загрузки фрагмента.
или
Создайте логическое значение и проверьте, не прекращается ли активность
тогда при загрузке фрагмента проверяю
источник
Чтобы обойти эту проблему, мы можем использовать Компонент архитектуры навигации , который был представлен в Google I / O 2018. Компонент архитектуры навигации упрощает реализацию навигации в приложении Android.
источник
Что касается @Anthonyeef отличный ответ, вот пример кода на Java:
источник
Если у вас произошел сбой с помощью метода popBackStack () или popBackStackImmediate (), попробуйте исправить с помощью:
Это сработало и для меня.
источник
В моем случае я получил эту ошибку в методе переопределения onActivityResult. После копания я просто думаю, что мне нужно было позвонить " супер " раньше.
Я добавил это, и это просто сработало
Может быть, вам просто нужно добавить super в любое переопределение, которое вы делаете перед вашим кодом.
источник
Удлинение Котлина
Применение:
источник
fragment: Fragment
? Да, я попробовал этот вариант, но в этом случае фрагмент будет создан во всех случаях (даже когда фрагментManager == ноль, но я не сталкивался с этой ситуацией). Я обновил ответ и изменил значение null на тегaddToBackStack()
.Этот сбой происходит из-за того, что FragmentTransaction совершается после того, как жизненный цикл его собственной активности уже запущен наSaveInstanceState. Это часто вызывается фиксацией FragmentTransactions из асинхронного обратного вызова. Проверьте связанный ресурс для более подробной информации.
Фрагмент транзакций и активность State Loss
http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
источник
Добавьте это в свою деятельность
источник
Я также сталкивался с этой проблемой, и проблема возникает каждый раз, когда
FragmentActivity
меняется ваш контекст (например, изменяется ориентация экрана и т. Д.). Так что лучшее решение для этого - обновить контекст с вашегоFragmentActivity
.источник
Я закончил с созданием базового фрагмента и сделать все фрагменты в моем приложении расширить его
Затем, когда я пытаюсь показать фрагмент, я использую
showAllowingStateLoss
вместоshow
нравится:
Я пришел к этому решению из этого PR: https://github.com/googlesamples/easypermissions/pull/170/files
источник
Другой возможный обходной путь, который я не уверен, помогает ли во всех случаях (происхождение здесь ):
источник
Я знаю, что @Ovidiu Latcu принял приемлемый ответ, но через некоторое время ошибка все еще сохраняется.
Crashlytics все еще посылает мне это странное сообщение об ошибке.
Однако теперь ошибка возникает только в версии 7+ (Nougat). Мое исправление состояло в том, чтобы использовать commitAllowingStateLoss () вместо commit () для фрагмента транзакции .
Этот пост полезен для commitAllowingStateLoss () и никогда больше не сталкивался с проблемой фрагментов.
Подводя итог, можно сказать, что принятый ответ может работать на версиях для Android до Nougat.
Это может сэкономить кому-то несколько часов поиска. счастливых кодировок. <3 ура
источник