Alguns usuários estão relatando que, se eles usarem a ação rápida na barra de notificação, estão recebendo um fechamento de força.
Eu mostro uma ação rápida na notificação que chama a classe "TestDialog" . Na classe TestDialog depois de pressionar o botão "soneca", mostrarei o 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");
}
O erro é *IllegalStateException: Can not perform this action after onSaveInstanceState*.
A linha de código onde a IllegarStateException é acionada é:
snoozeDialog.show(fm, "snooze_dialog");
A classe está estendendo "FragmentActivity" e a classe "SnoozeDialog" está estendendo "DialogFragment".
Aqui está o rastreamento completo da pilha do erro:
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)
Não consigo reproduzir esse erro, mas estou recebendo muitos relatórios de erros.
Alguém pode ajudar? Como posso corrigir esse erro?
Respostas:
Este é um problema comum . Resolvemos esse problema substituindo show () e manipulando a exceção na classe estendida DialogFragment
Observe que a aplicação desse método não alterará os campos internos da classe DialogFragment.class:
Isso pode levar a resultados inesperados em alguns casos. Melhor usar commitAllowingStateLoss () em vez de commit ()
fonte
Isso significa que você
commit()
(show()
no caso de DialogFragment) fragmenta apósonSaveInstanceState()
.O Android salvará seu estado de fragmento em
onSaveInstanceState()
. Então, se vocêcommit()
fragmentar depoisonSaveInstanceState()
estado do fragmento, será perdido.Como resultado, se Activity for morto e recriado mais tarde, o fragmento não será adicionado à atividade, o que é uma experiência ruim do usuário. É por isso que o Android não permite a perda de estado a todo custo.
A solução fácil é verificar se o estado já foi salvo.
Nota: onResumeFragments () chamará quando os fragmentos forem reiniciados.
fonte
ref: link
fonte
Depois de alguns dias eu quero compartilhar minha solução como eu fixa-lo, para mostrar DialogFragment você deve substituir
show()
método dele e chamarcommitAllowingStateLoss()
noTransaction
objeto. Aqui está um exemplo no Kotlin:fonte
DialogFragment
você pudesse mudar isso para ser uma função de extensão Kotlin com a seguinte assinatura:fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String)
. Além disso, o try-catch não é necessário, pois você está chamando ocommitAllowingStateLoss()
método e não ocommit()
método.Se a caixa de diálogo não for realmente importante (não há problema em não mostrá-la quando o aplicativo foi fechado / não está mais sendo exibido), use:
E abra sua caixa de diálogo (fragmento) somente quando estivermos executando:
EDIÇÃO, SOLUÇÃO PROVAVELMENTE MELHOR:
Onde onSaveInstanceState é chamado no ciclo de vida é imprevisível, acho que uma solução melhor é verificar isSavedInstanceStateDone () assim:
fonte
tente usar FragmentTransaction em vez de FragmentManager. Acho que o código abaixo resolverá seu problema. Se não, por favor me avise.
EDITAR:
Transação de fragmento
Por favor, verifique este link. Eu acho que isso resolverá suas dúvidas.
fonte
Corri para esse problema há anos.
Os Internets estão repletos de dezenas (centenas? Milhares?) De discussões sobre isso, e confusão e desinformação nelas parecem abundantes.
Para piorar a situação, e no espírito dos quadrinhos "14 standards" do xkcd, estou jogando minha resposta no ringue.
A
cancelPendingInputEvents()
,commitAllowingStateLoss()
,catch (IllegalStateException e)
, e soluções semelhantes todos parecem atroz.Felizmente, o seguinte mostra facilmente como reproduzir e corrigir o problema:
fonte
O uso dos novos escopos de ciclo de vida do Activity-KTX é tão simples quanto o seguinte exemplo de código:
Este método pode ser chamado diretamente após onStop () e mostrará com êxito a caixa de diálogo assim que onResume () for chamado ao retornar.
fonte
Muitas visualizações postam eventos de alto nível, como manipuladores de cliques na fila de eventos para executar adiados. Portanto, o problema é que "onSaveInstanceState" já foi chamado para a Atividade, mas a fila de eventos contém "evento de clique" adiado. Portanto, quando este evento é despachado para seu manipulador
e seu código faz
show
o IllegalStateException é lançado.A solução mais simples é limpar a fila de eventos, em
onSaveInstanceState
fonte
activity
efragment
).Torne seu objeto de fragmento de diálogo global e chame o método allowAllowingStateLoss () no método onPause ()
Não se esqueça de atribuir valor no fragmento e chamar show () ao clicar no botão ou em qualquer lugar.
fonte
Embora não seja oficialmente mencionado em nenhum lugar, mas eu enfrentei esse problema algumas vezes. Na minha experiência, há algo errado na biblioteca de compatibilidade que suporta fragmentos em plataformas mais antigas, o que causa esse problema. Você pode testar isso usando a API normal do gerenciador de fragmentos. Se nada funcionar, você poderá usar a caixa de diálogo normal em vez do fragmento da caixa de diálogo.
fonte
Use o método showAllowingStateLoss em vez de show
Aproveitar ;)
fonte
StatelessDialogFragment
procurando por uma solução para o seu problema, entre em contato com a nossa equipe de suporte para obter mais informações sobre os nossos serviços.use este código
ao invés de
fonte
Encontrei uma solução elegante para esse problema usando a reflexão. O problema de todas as soluções acima é que os campos mDismissed e mShownByMe não alteram seu estado.
Basta substituir o método "show" em seu próprio fragmento de diálogo da folha de baixo personalizado, como a amostra abaixo (Kotlin)
fonte
A implementação a seguir pode ser usada para resolver o problema de realizar alterações de estado com segurança durante o
Activity
ciclo de vida, principalmente para mostrar diálogos: se o estado da instância já tiver sido salvo (por exemplo, devido a uma alteração na configuração), ele será adiado até que o estado retomado realizado.Então, usando uma classe como esta:
Você pode mostrar diálogos com segurança sem se preocupar com o estado do aplicativo:
e depois ligue
TestDialog.show(this)
de dentro do seuXAppCompatActivity
.Se você deseja criar uma classe de diálogo mais genérica com parâmetros, você pode salvá-los em um
Bundle
com os argumentos doshow()
método e recuperá-losgetArguments()
emonCreateDialog()
.Toda a abordagem pode parecer um pouco complexa, mas depois de criar as duas classes base para atividades e diálogos, é bastante fácil de usar e funciona perfeitamente. Pode ser usado para outras
Fragment
operações baseadas que podem ser afetadas pelo mesmo problema.fonte
Este erro parece estar ocorrendo porque os eventos de entrada (como eventos de pressionamento de tecla ou onclick) estão sendo entregues após a
onSaveInstanceState
chamada.A solução é substituir
onSaveInstanceState
sua Atividade e cancelar quaisquer eventos pendentes.fonte