Niektórzy użytkownicy zgłaszają, że jeśli używają szybkiej akcji na pasku powiadomień, zbliżają się do siły.
W powiadomieniu pokazuję szybką akcję, która wywołuje klasę „TestDialog” . W klasie TestDialog po naciśnięciu przycisku „drzemka” pokażę SnoozeDialog.
private View.OnClickListener btnSnoozeOnClick() {
return new View.OnClickListener() {
public void onClick(View v) {
showSnoozeDialog();
}
};
}
private void showSnoozeDialog() {
FragmentManager fm = getSupportFragmentManager();
SnoozeDialog snoozeDialog = new SnoozeDialog();
snoozeDialog.show(fm, "snooze_dialog");
}
Błąd jest *IllegalStateException: Can not perform this action after onSaveInstanceState*.
Wiersz kodu, w którym jest uruchamiany wyjątek IllegarStateException, to:
snoozeDialog.show(fm, "snooze_dialog");
Klasa rozszerza „FragmentActivity”, a klasa „SnoozeDialog” rozszerza „DialogFragment”.
Oto pełny ślad stosu błędu:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1327)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1338)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
at com.test.testing.TestDialog.f(TestDialog.java:538)
at com.test.testing.TestDialog.e(TestDialog.java:524)
at com.test.testing.TestDialog.d(TestDialog.java:519)
at com.test.testing.g.onClick(TestDialog.java:648)
at android.view.View.performClick(View.java:3620)
at android.view.View$PerformClick.run(View.java:14292)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4507)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
Nie mogę odtworzyć tego błędu, ale otrzymuję wiele raportów o błędach.
Czy ktoś może pomóc, jak mogę naprawić ten błąd?
Odpowiedzi:
To częsty problem . Rozwiązaliśmy ten problem, zastępując metodę show () i obsługując wyjątek w rozszerzonej klasie DialogFragment
Należy pamiętać, że zastosowanie tej metody nie zmieni wewnętrznych pól pliku DialogFragment.class:
W niektórych przypadkach może to prowadzić do nieoczekiwanych wyników. Lepiej użyj commitAllowingStateLoss () zamiast commit ()
źródło
To znaczy, że
commit()
(show()
w przypadku DialogFragment) fragment poonSaveInstanceState()
.Android zapisze stan fragmentu pod adresem
onSaveInstanceState()
. Tak więc, jeślicommit()
fragmentujesz poonSaveInstanceState()
fragmencie, stan fragmentu zostanie utracony.W rezultacie, jeśli aktywność zostanie zabita i odtworzona później, fragment nie zwiększy aktywności, co jest złym doświadczeniem użytkownika. Dlatego Android nie pozwala na utratę stanu za wszelką cenę.
Prostym rozwiązaniem jest sprawdzenie, czy stan został już zapisany.
Uwaga: onResumeFragments () będzie wywoływać po wznowieniu fragmentów.
źródło
ref: link
źródło
Po kilku dniach chcę podzielić się moją rozwiązanie jak Naprawiłem go, aby pokazać DialogFragment Państwo powinno przesłonić
show()
metodę to i zadzwonićcommitAllowingStateLoss()
naTransaction
obiekcie. Oto przykład w Kotlinie:źródło
DialogFragment
tobie, mogliby to zmienić na funkcję rozszerzenia Kotlin z następującą sygnaturą:fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String)
. Również try-catch nie jest konieczny, ponieważ wywołujeszcommitAllowingStateLoss()
metodę, a niecommit()
metodę.Jeśli okno dialogowe nie jest naprawdę ważne (można go nie pokazywać, gdy aplikacja jest zamknięta / nie jest już widoczna), użyj:
I otwórz swoje okno dialogowe (fragment) tylko wtedy, gdy uruchamiamy:
EDYTUJ, PRAWDOPODOBNIE LEPSZE ROZWIĄZANIE:
Tam, gdzie onSaveInstanceState jest wywoływana w cyklu życia jest nieprzewidywalna, myślę, że lepszym rozwiązaniem jest sprawdzenie isSavedInstanceStateDone () w następujący sposób:
źródło
Od lat spotykam się z tym problemem.
Internet jest zaśmiecony dziesiątkami (setkami? Tysiącami?) Dyskusji na ten temat, a zamieszania i dezinformacji w nich wydaje się mnóstwo.
Aby pogorszyć sytuację, w duchu komiksu xkcd „14 standardów”, wrzucam swoją odpowiedź na ring.
The
cancelPendingInputEvents()
,commitAllowingStateLoss()
,catch (IllegalStateException e)
, I podobne rozwiązania wszystkie wydają okropne.Mamy nadzieję, że poniższe informacje z łatwością pokazują, jak odtworzyć i rozwiązać problem:
źródło
spróbuj użyć FragmentTransaction zamiast FragmentManager. Myślę, że poniższy kod rozwiąże Twój problem. Jeśli nie, daj mi znać.
EDYTOWAĆ:
Transakcja fragmentaryczna
Proszę sprawdzić ten link. Myślę, że rozwiąże Twoje pytania.
źródło
Korzystanie z nowych zakresów cyklu życia Activity-KTX jest tak proste, jak poniższy przykład kodu:
Tę metodę można wywołać bezpośrednio po onStop () i pomyślnie pokaże okno dialogowe po wywołaniu metody onResume () po powrocie.
źródło
Wiele widoków publikuje zdarzenia wysokiego poziomu, takie jak programy obsługi kliknięć, w kolejce zdarzeń w celu wykonania odroczonego. Problem polega więc na tym, że „onSaveInstanceState” zostało już wywołane dla działania, ale kolejka zdarzeń zawiera odroczone „zdarzenie kliknięcia”. Stąd, kiedy to zdarzenie jest wysyłane do twojego programu obsługi
a Twój kod powoduje zgłoszenie
show
wyjątku IllegalStateException.Najprostszym rozwiązaniem jest wyczyszczenie kolejki zdarzeń w formacie
onSaveInstanceState
źródło
activity
ifragment
).Ustaw obiekt fragmentu okna dialogowego na globalny i wywołaj discissAllowingStateLoss () w metodzie onPause ()
Nie zapomnij przypisać wartości we fragmencie i wywołać funkcję show () po kliknięciu przycisku lub gdziekolwiek.
źródło
Chociaż nigdzie o tym oficjalnie nie wspomniano, kilka razy miałem do czynienia z tym problemem. Z mojego doświadczenia wynika, że coś jest nie tak w bibliotece kompatybilności obsługującej fragmenty na starszych platformach, co powoduje ten problem. Możesz to przetestować, używając normalnego interfejsu API menedżera fragmentów. Jeśli nic nie działa, możesz użyć normalnego okna dialogowego zamiast fragmentu okna dialogowego.
źródło
Użyj metody showAllowingStateLoss zamiast show
Cieszyć się ;)
źródło
StatelessDialogFragment
Otrzymałem błędy kompilacji podczas umieszczania w jednym z moich pakietów. Dzięki stary. Niedługo przetestuję to na produkcji.użyj tego kodu
zamiast
źródło
Znalazłem eleganckie rozwiązanie tego problemu za pomocą refleksji. Problem wszystkich powyższych rozwiązań polega na tym, że pola mDismissed i mShownByMe nie zmieniają swojego stanu.
Po prostu nadpisz metodę „show” we własnym niestandardowym fragmencie okna dialogowego dolnego arkusza, jak przykład poniżej (Kotlin)
źródło
Do rozwiązania problemu bezpiecznej zmiany stanu w trakcie
Activity
cyklu życia, w szczególności w przypadku wyświetlania okien dialogowych, można zastosować następującą implementację : jeśli stan instancji został już zapisany (np. W wyniku zmiany konfiguracji), to odkłada je do czasu przywrócenia stanu zostało wykonane.Następnie używając takiej klasy:
Możesz bezpiecznie wyświetlać okna dialogowe, nie martwiąc się o stan aplikacji:
a następnie zadzwoń
TestDialog.show(this)
ze swojegoXAppCompatActivity
.Jeśli chcesz utworzyć bardziej ogólną klasę okna dialogowego z parametrami, możesz zapisać je w a
Bundle
z argumentami wshow()
metodzie i pobrać je za pomocągetArguments()
inonCreateDialog()
.Całe podejście może wydawać się nieco skomplikowane, ale po utworzeniu dwóch klas podstawowych dla działań i dialogów jest dość łatwe w użyciu i doskonale działa. Może być używany do innych
Fragment
operacji bazowych, na które może mieć wpływ ten sam problem.źródło
Wydaje się, że ten błąd występuje, ponieważ zdarzenia wejściowe (takie jak naciśnięcie klawisza lub zdarzenia onclick) są dostarczane po
onSaveInstanceState
wywołaniu.Rozwiązaniem jest zastąpienie
onSaveInstanceState
aktywności i anulowanie wszelkich oczekujących wydarzeń.źródło