Mam aplikację na Androida na żywo, a z rynku otrzymałem śledzenie stosu i nie mam pojęcia, dlaczego dzieje się tak, ponieważ nie dzieje się w kodzie aplikacji, ale jest spowodowane przez jakieś lub inne zdarzenie z aplikacji (założenie)
Nie używam Fragments, wciąż istnieje odwołanie do FragmentManager. Jeśli jakikolwiek organ może rzucić nieco światła na niektóre ukryte fakty, aby uniknąć tego rodzaju problemów:
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)
android
illegalstateexception
chłodzenie
źródło
źródło
Odpowiedzi:
To najgłupszy błąd, jaki do tej pory napotkałem. Miałem
Fragment
aplikacji doskonale pracuje dla API <11 , aForce Closing
na API> 11 .Naprawdę nie mogłem dowiedzieć się, co zmienili w
Activity
cyklu życia w wezwaniu dosaveInstance
, ale oto jak to rozwiązałem:Po prostu nie dzwonię
.super()
i wszystko działa świetnie. Mam nadzieję, że pozwoli ci to zaoszczędzić trochę czasu.EDYCJA: po kilku dalszych badaniach jest to znany błąd w pakiecie wsparcia.
Jeśli chcesz zapisać instancję i dodać coś do swojego
outState
Bundle
, możesz użyć następujących opcji:EDYCJA 2: może się to również zdarzyć, jeśli próbujesz wykonać transakcję po tym, jak nie
Activity
ma Cię w tle. Aby tego uniknąć, powinieneś użyćcommitAllowingStateLoss()
EDYCJA 3: Powyższe rozwiązania naprawiały problemy we wczesnych bibliotekach support.v4 z tego, co pamiętam. Ale jeśli nadal masz z tym problemy, MUSISZ także przeczytać blog @AlexLockwood : Fragment Transactions & Activity State Loss
Podsumowanie z postu na blogu (ale zdecydowanie polecam go przeczytać):
commit()
przeprowadzaj transakcji poonPause()
Honeycomb ionStop()
po HoneycombActivity
metod cyklu życia. ZastosowanieonCreate()
,onResumeFragments()
aonPostResume()
commitAllowingStateLoss()
tylko w ostatecznościźródło
commitAllowingStateLoss()
unika tylko wyjątku. Nie chroni aplikacji przed przypadkową utratą stanu. Zobacz ten post na blogu .Po zapoznaniu się z kodem źródłowym Androida, co powoduje ten problem, flaga mStateSaved w
FragmentManagerImpl
klasie (instancja dostępna w działaniu) ma wartość true. Jest ustawiony na true, gdy tylny stos jest zapisywany (saveAllState) podczas połączenia zActivity#onSaveInstanceState
. Następnie połączenia z ActivityThread nie resetują tej flagi przy użyciu dostępnych metod resetowania zFragmentManagerImpl#noteStateNotSaved()
idispatch()
.Widzę, że jest kilka dostępnych poprawek, w zależności od tego, co robi Twoja aplikacja i używa:
Dobre sposoby
Przede wszystkim: reklamowałbym artykuł Alexa Lockwooda . Następnie z tego, co zrobiłem do tej pory:
W przypadku fragmentów i działań, które nie muszą przechowywać żadnych informacji o stanie, wywołaj commitAllowStateLoss . Zaczerpnięte z dokumentacji:
Zaraz po zatwierdzeniu transakcji (właśnie dzwoniłeś
commit()
), zadzwoń doFragmentManager.executePendingTransactions()
.Niezalecane sposoby:
Jak wspomniano powyżej Ovidiu Latcu, nie dzwoń
super.onSaveInstanceState()
. Ale to oznacza, że stracisz cały stan swojej aktywności wraz ze stanem fragmentów.Zastąp,
onBackPressed
a tam tylko połączeniefinish()
. To powinno być OK, jeśli twoja aplikacja nie używa Fragments API; jaksuper.onBackPressed
tam jest wezwanie doFragmentManager#popBackStackImmediate()
.Jeśli używasz interfejsu API Fragments, a stan Twojej aktywności jest ważny / ważny, możesz spróbować zadzwonić za pomocą interfejsu API refleksji
FragmentManagerImpl#noteStateNotSaved()
. Ale to jest włamanie, albo można powiedzieć, że to obejście. Nie podoba mi się to, ale w moim przypadku jest to całkiem do przyjęcia, ponieważ mam kod ze starej aplikacji, która używa przestarzałego kodu (TabActivity
i niejawnieLocalActivityManager
).Poniżej znajduje się kod wykorzystujący odbicie:
Twoje zdrowie!
źródło
Taki wyjątek wystąpi, jeśli spróbujesz wykonać przejście fragmentu po
onSaveInstanceState()
wywołaniu aktywności fragmentu .Jednym z powodów takiego stanu rzeczy może być pozostawienie uruchomionego
AsyncTask
(lubThread
) działania, gdy działanie zostanie zatrzymane.Wywołane później przejścia
onSaveInstanceState()
mogą potencjalnie zostać utracone, jeśli system odzyska aktywność dla zasobów i odtworzy ją później.źródło
super.onSaveInstanceState()
.Wystarczy wywołać super.onPostResume () przed pokazaniem fragmentu lub przenieść kod w metodzie onPostResume () po wywołaniu super.onPostResume (). To rozwiązuje problem!
źródło
Może się to również zdarzyć podczas wywoływania
dismiss()
fragmentu okna dialogowego po zablokowaniu ekranu \ wygaszeniu i zapisaniu stanu instancji Aktywność + okno dialogowe. Aby obejść to połączenie:Dosłownie za każdym razem, gdy zamykam okno dialogowe, nie dbam już o jego stan, więc możesz to zrobić - właściwie nie tracisz żadnego stanu.
źródło
Krótkie i działające rozwiązanie:
Wykonaj proste kroki:
Krok 1 : Zastąp stan onSaveInstanceState w odpowiednim fragmencie. I usuń z niego super metodę.
Krok 2 : Użyj CommitAllowingStateLoss (); zamiast commit (); podczas operacji fragmentacji.
źródło
Myślę, że Lifecycle stan może pomóc w zapobieganiu takiej awarii, zaczynając od wsparcia dla Androida lib v26.1.0, możesz mieć następujące sprawdzenie:
lub możesz spróbować:
więcej informacji tutaj https://developer.android.com/reference/android/support/v4/app/Fragment.html#isStateSaved ()
źródło
to zadziałało dla mnie ... odkryłem to na własną rękę ... mam nadzieję, że ci to pomoże!
1) NIE mają globalnego „statycznego” FragmentManager / FragmentTransaction.
2) onCreate, ZAWSZE inicjuj FragmentManager ponownie!
próbka poniżej: -
źródło
Zawsze otrzymywałem to, gdy próbowałem pokazać fragment w metodzie onActivityForResult (), więc problem był następny:
To, co zrobiłem, jest następne:
źródło
Rozwiązałem problem ze zmianą konfiguracji. Sztuczka polega na tym, że zgodnie z cyklem życia aktywności Androida, gdy wyraźnie nazwałeś zamiar (zamiar kamery lub jakikolwiek inny); działanie zostaje wstrzymane i zostaje zapisane. W takim przypadku wywoływana jest instancja. Podczas obracania urządzenia w inne miejsce niż to, w którym aktywność była aktywna; wykonywanie operacji fragmentów, takich jak zatwierdzanie fragmentów, powoduje wyjątek dotyczący stanu niezgodnego z prawem. Jest na to wiele skarg. Chodzi o zarządzanie cyklem życia aktywności Androida i odpowiednie wywołania metod. Aby to rozwiązać, zrobiłem to: 1-Zastąp metodę onsavedInstance Twojej aktywności i określ bieżącą orientację ekranu (pionową lub poziomą), a następnie ustaw na nią orientację ekranu przed wstrzymaniem aktywności. w ten sposób działanie blokuje obrót ekranu dla działania w przypadku, gdy zostało ono obrócone przez inne. 2, następnie zastąp metodę wznawiania działania i ustaw teraz tryb orientacji na czujnik, aby po wywołaniu metody zachowanej wywoła jeszcze raz konfigurację, aby poprawnie poradzić sobie z obrotem.
Możesz skopiować / wkleić ten kod do swojej aktywności, aby sobie z tym poradzić:
źródło
Miałem ten sam problem, otrzymywanie IllegalStateException, ale zastąpienie wszystkich moich wywołań funkcji commit () funkcją commitAllowingStateLoss () nie pomogło.
Sprawcą było wywołanie DialogFragment.show ().
Otaczam to
i to zrobiło. OK, nie mogę wyświetlić okna dialogowego, ale w tym przypadku było dobrze.
Było to jedyne miejsce w mojej aplikacji, w którym po raz pierwszy wywołałem FragmentManager.beginTransaction (), ale nigdy nie wywołałem commit (), więc nie znalazłem go, gdy szukałem „commit ()”.
Zabawne jest to, że użytkownik nigdy nie opuszcza aplikacji. Zamiast tego zabójcą była reklama pełnoekranowa AdMob.
źródło
Moje rozwiązanie tego problemu było
W fragmentach dodaj metody:
Może być źle, ale nie mogłem znaleźć nic lepszego.
źródło
Mam ten problem, ale myślę, że ten problem nie jest związany z zatwierdzaniem i zatwierdzaniemAllowStateLoss.
Poniższy komunikat śledzenia stosu i wyjątku dotyczy commit ().
Ale ten wyjątek został spowodowany przez onBackPressed ()
Wszystkie zostały spowodowane przez checkStateLoss ()
mStateSaved będzie prawdziwe po onSaveInstanceState.
Ten problem rzadko się zdarza. Nigdy nie napotkałem tego problemu. Nie mogę powtórzyć problemu.
znalazłem problem 25517
Mogło to nastąpić w następujących okolicznościach
Klawisz Wstecz jest wywoływany po onSaveInstanceState, ale przed rozpoczęciem nowej aktywności.
użyj onStop () w kodzie
Nie jestem pewien, na czym polega problem. Więc użyłem brzydkiego sposobu.
źródło
Mam ten sam problem w mojej aplikacji. Ten problem został rozwiązany przez wywołanie
super.onBackPressed();
poprzedniej klasy i wywołaniecommitAllowingStateLoss()
bieżącej klasy za pomocą tego fragmentu.źródło
commitAllowingStateLoss()
zamiastcommit()
onSaveInstance zostanie wywołany, jeśli użytkownik obróci ekran, aby mógł załadować zasoby związane z nową orientacją.
Możliwe, że ten użytkownik obrócił ekran, a następnie naciśnie przycisk Wstecz (ponieważ możliwe jest również, że ten użytkownik sfałszował swój telefon podczas korzystania z aplikacji)
źródło
Przeczytaj http://chris-alexander.co.uk/on-engineering/dev/android-fragments-within-fragments/
artykuł. Sprawdzanie fragment.isResumed () pomaga mi w onDestroyView bez użycia metody onSaveInstanceState.
źródło
Ten sam problem ode mnie i po całodniowej analizie wszystkich artykułów, blogu i stackoverflow znalazłem proste rozwiązanie. W ogóle nie używaj saveInstanceState, jest to warunek z jednym wierszem kodu. Na kodzie fragmentu:
źródło
Dzieje się tak za każdym razem, gdy próbujesz załadować fragment, ale działanie zmieniło swój stan na onPause (). Dzieje się tak na przykład, gdy próbujesz pobrać dane i załadować je do działania, ale do czasu kliknięcia przycisku przez użytkownika przeniesiony do następnej aktywności.
Możesz to rozwiązać na dwa sposoby
Można użyć transakcji.commitAllowingStateLoss () zamiast transakcji.commit (), aby załadować fragment, ale może to spowodować utratę wykonanej operacji zatwierdzania.
lub
Upewnij się, że aktywność jest wznawiana i nie będzie wstrzymywać stanu podczas ładowania fragmentu. Utwórz wartość logiczną i sprawdź, czy aktywność nie przejdzie w stan onPause ().
następnie podczas ładowania fragmentu sprawdź, czy aktywność jest obecna i ładuj tylko, gdy aktywność jest na pierwszym planie.
źródło
Dzięki @gunar, ale myślę, że jest lepszy sposób.
Według dokumentu:
Więc użyj,
commitNow
aby zastąpić:źródło
Cóż, po wypróbowaniu wszystkich powyższych rozwiązań bez powodzenia (ponieważ w zasadzie nie mam transakcji).
W moim przypadku użyłem AlertDialogs i ProgressDialog jako fragmentów, które czasami przy rotacji, gdy pytamy o FragmentManager, błąd rośnie.
Znalazłem obejście mieszające kilka podobnych postów:
Jest to 3-etapowe rozwiązanie, wszystkie wykonane na FragmentActivity (w tym przypadku nazywa się GenericActivity):
źródło
Kiedy użyję startactivity w jednym fragmencie, otrzymam ten wyjątek;
Kiedy zmieniam się na startactivityforresult, wyjątek zniknął :)
Tak więc najłatwiejszym sposobem, aby to naprawić, jest użycie interfejsu startActivityForResult :)
źródło
Otrzymywałem ten wyjątek, kiedy naciskałem przycisk Wstecz, aby anulować zamiar wyboru aktywności mojej fragmentu mapy. Rozwiązałem ten problem, zastępując kod onResume () (gdzie inicjowałem fragment i zatwierdzałem transakcję) na onStart (), a aplikacja działa teraz poprawnie. Mam nadzieję, że to pomoże.
źródło
Zostało to naprawione w Androidzie 4.2, a także w źródle biblioteki wsparcia. [*]
Szczegółowe informacje na temat przyczyny (i obejścia) można znaleźć w raporcie o błędach Google: http://code.google.com/p/android/issues/detail?id=19917
Jeśli korzystasz z biblioteki wsparcia, nie powinieneś martwić się tym błędem (na długo) [*]. Jeśli jednak używasz interfejsu API bezpośrednio (tj. Nie używasz FragmentManager biblioteki obsługi) i celujesz w interfejs API poniżej Androida 4.2, musisz wypróbować jedno z obejść tego problemu.
[*] W chwili pisania tego tekstu Menedżer pakietu SDK systemu Android nadal rozpowszechnia starą wersję, w której występuje ten błąd.
Edytuj Zamierzam tu dodać wyjaśnienie, ponieważ najwyraźniej w jakiś sposób zdezorientowałem tego, kto obniżył tę odpowiedź.
Istnieje kilka różnych (ale powiązanych) okoliczności, które mogą spowodować zgłoszenie tego wyjątku . Moja odpowiedź powyżej odnosi się do konkretnego wystąpienia omówionego w pytaniu, tj. Błędu w Androidzie, który został następnie naprawiony. Jeśli otrzymujesz ten wyjątek z innego powodu, to dlatego, że dodajesz / usuwasz fragmenty, kiedy nie powinieneś (po zapisaniu stanów fragmentów). Jeśli znajdujesz się w takiej sytuacji, być może przydadzą Ci się „ Zagnieżdżone fragmenty - IllegalStateException„ Nie można wykonać tej akcji po onSaveInstanceState ” ”.
źródło
Po dokładnym zbadaniu rozwiązania tego problemu jest wykonanie fragmentów zatwierdzeń w jednym miejscu.
Źródło: https://wenchaojames.wordpress.com/2013/01/12/illegalstateexception-from-onactivityresult/
źródło
Mój przypadek użycia: Użyłem detektora we fragmentach, aby powiadomić aktywność, że coś się wydarzyło. Zrobiłem nowy fragment zatwierdzenia metodą wywołania zwrotnego. Działa to doskonale za pierwszym razem. Ale po zmianie orientacji aktywność jest odtwarzana z zachowanym stanem instancji. W takim przypadku fragment nie jest ponownie tworzony, co oznacza, że fragment ma detektora, który jest starą, zniszczoną działalnością. W dowolny sposób zostanie wywołana metoda wywołania zwrotnego po akcji. Chodzi o zniszczone działania, które powodują problem. Rozwiązaniem jest zresetowanie detektora we fragmentach z bieżącą aktywnością na żywo. To rozwiązuje problem.
źródło
Odkryłem, że jeśli inna aplikacja ma typ okna dialogowego i zezwala na wysyłanie poprawek do aplikacji w tle, prawie każda aplikacja w tle ulegnie awarii z powodu tego błędu. Myślę, że musimy za każdym razem sprawdzać, czy instancja została zapisana lub przywrócona.
źródło
W moim przypadku, z tym samym wyjątkiem błędu, umieszczam „onBackPressed ()” w uruchamialnym (możesz użyć dowolnego widoku):
Nie rozumiem dlaczego, ale działa!
źródło
Możesz wywoływać fragmentManager.popBackStackImmediate (); kiedy aktywność jest wstrzymana. Działanie nie zostało zakończone, ale zostało wstrzymane i nie jest na pierwszym planie. Musisz sprawdzić, czy aktywność jest wstrzymana przed popBackStackImmediate ().
źródło
Zauważyłem coś bardzo interesującego. Mam w swojej aplikacji opcję otwarcia galerii telefonu, a urządzenie pyta, jakiej aplikacji użyć, tam klikam szary obszar poza oknem dialogowym i zobaczyłem ten problem. Zauważyłem, jak moja aktywność przechodzi z onPause, onSaveInstanceState z powrotem do onResume, nie zdarza się odwiedzać onCreateView. Robię transakcje w onResume. Skończyło się na ustawieniu flagi, która jest negowana naPause, ale jest prawdziwa naCreateView. jeśli flaga ma wartość true onResume, wykonaj onCommit, w przeciwnym razie commitAllowingStateLoss. Mogłem marnować tyle czasu, ale chciałem sprawdzić cykl życia. Mam urządzenie, które jest sdkversion 23, i nie dostaję tego problemu, ale mam inne, które ma 21, i tam widzę.
źródło
możesz użyć FragmentActivity.onStart przed popBackStackImmediate
lubię to:
http://jorryliu.blogspot.com/2014/09/illegalstateexception-can-not-perform.html
źródło