Eu tenho um aplicativo Live Android e, do mercado, recebi o rastreamento de pilha a seguir e não tenho idéia do por que isso está acontecendo porque não está acontecendo no código do aplicativo, mas está sendo causado por algum ou outro evento do aplicativo (suposição)
Não estou usando fragmentos, ainda há uma referência do FragmentManager. Se alguém puder esclarecer alguns fatos ocultos para evitar esse tipo de problema:
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)
Respostas:
Este é o bug mais estúpido que encontrei até agora. Eu tinha um
Fragment
aplicativo funcionando perfeitamente para a API <11 eForce Closing
na API> 11 .Eu realmente não conseguia descobrir o que eles mudaram dentro do
Activity
ciclo de vida na chamada parasaveInstance
, mas aqui está como resolvi isso:Eu simplesmente não faço a ligação
.super()
e tudo funciona muito bem. Espero que isso poupe algum tempo.EDIT: após mais algumas pesquisas, esse é um bug conhecido no pacote de suporte.
Se você precisar salvar a instância e adicionar algo ao seu,
outState
Bundle
poderá usar o seguinte:EDIT2: isso também pode ocorrer se você estiver tentando executar uma transação depois que a sua
Activity
for colocada em segundo plano. Para evitar isso, você deve usarcommitAllowingStateLoss()
EDIT3: As soluções acima estavam corrigindo problemas nas bibliotecas support.v4 anteriores, pelo que me lembro. Mas se você ainda tiver problemas com isso, DEVE também ler o blog de @AlexLockwood : Transações de fragmentos e perda de estado de atividade
Resumo da postagem do blog (mas eu recomendo fortemente que você a leia):
commit()
transações apósonPause()
pré-Honeycomb eonStop()
pós-HoneycombActivity
métodos do ciclo de vida. UseonCreate()
,onResumeFragments()
eonPostResume()
commitAllowingStateLoss()
apenas como último recursofonte
commitAllowingStateLoss()
evita apenas a exceção. Não protege seu aplicativo contra perda acidental de estado. Veja esta postagem do blog .A pesquisa no código-fonte do Android sobre o que causa esse problema indica que o sinalizador mStateSaved na
FragmentManagerImpl
classe (instância disponível em Activity) tem valor true. É definido como true quando a pilha de trás é salva (saveAllState) de plantãoActivity#onSaveInstanceState
. Posteriormente, as chamadas do ActivityThread não redefinem esse sinalizador usando os métodos de redefinição disponíveis deFragmentManagerImpl#noteStateNotSaved()
edispatch()
.A meu ver, existem algumas correções disponíveis, dependendo do que seu aplicativo está fazendo e usando:
Boas maneiras
Antes de mais nada: eu anunciaria o artigo de Alex Lockwood . Então, pelo que eu fiz até agora:
Para fragmentos e atividades que não precisam manter nenhuma informação de estado, chame commitAllowStateLoss . Retirado da documentação:
Logo após a transação ser confirmada (você acabou de
commit()
ligar), faça uma chamada paraFragmentManager.executePendingTransactions()
.Maneiras não recomendadas:
Como Ovidiu Latcu mencionou acima, não ligue
super.onSaveInstanceState()
. Mas isso significa que você perderá todo o estado de sua atividade junto com o estado de fragmentos.Substituir
onBackPressed
e apenas chamar láfinish()
. Isso deve ser bom se o aplicativo não usar a API de fragmentos; comosuper.onBackPressed
existe uma chamada paraFragmentManager#popBackStackImmediate()
.Se você estiver usando a API de fragmentos e o estado de sua atividade for importante / vital, tente chamar usando a API de reflexão
FragmentManagerImpl#noteStateNotSaved()
. Mas isso é um hack, ou pode-se dizer que é uma solução alternativa. Não gosto, mas no meu caso é bastante aceitável, pois tenho um código de um aplicativo herdado que usa código obsoleto (TabActivity
e implicitamenteLocalActivityManager
).Abaixo está o código que usa reflexão:
Felicidades!
fonte
Essa exceção ocorrerá se você tentar executar uma transição de fragmento após a
onSaveInstanceState()
chamada de sua atividade de fragmento .Uma razão pela qual isso pode acontecer é se você deixar um
AsyncTask
(ouThread
) em execução quando uma atividade for interrompida.Qualquer transição após a
onSaveInstanceState()
chamada pode se perder se o sistema recuperar a atividade por recursos e recriá-la mais tarde.fonte
super.onSaveInstanceState()
.Simplesmente chame super.onPostResume () antes de mostrar seu fragmento ou mova seu código no método onPostResume () depois de chamar super.onPostResume (). Isso resolve o problema!
fonte
Isso também pode acontecer ao chamar
dismiss()
um fragmento de caixa de diálogo após a tela ser bloqueada \ em branco e o estado da instância da caixa de diálogo Atividade + ter sido salvo. Para contornar esta chamada:Literalmente, toda vez que estou descartando uma caixa de diálogo, não me importo mais com o seu estado, de modo que está tudo bem, pois você não está perdendo nenhum estado.
fonte
Solução curta e funcional:
Siga etapas simples:
Etapa 1 : Substitua o estado onSaveInstanceState no respectivo fragmento. E remova super método dele.
Etapa 2 : Use CommitAllowingStateLoss (); em vez de commit (); enquanto operações de fragmento.
fonte
Penso que o estado do ciclo de vida pode ajudar a impedir essa falha a partir do suporte Android lib v26.1.0, você pode ter a seguinte verificação:
ou você pode tentar:
mais informações aqui https://developer.android.com/reference/android/support/v4/app/Fragment.html#isStateSaved ()
fonte
isso funcionou para mim ... descobri isso sozinho ... espero que ajude!
1) NÃO possui um FragmentManager / FragmentTransaction global "estático".
2) onCreate, SEMPRE inicialize o FragmentManager novamente!
amostra abaixo: -
fonte
Eu estava sempre recebendo isso quando tentei mostrar fragmentos no método onActivityForResult (), então o problema era o seguinte:
O que eu fiz é o seguinte:
fonte
Resolvi o problema com onconfigurationchanged. O truque é que, de acordo com o ciclo de vida da atividade do Android, quando você chamava explicitamente uma intenção (intenção da câmera ou qualquer outra); a atividade é pausada e o onsavedInstance é chamado nesse caso. Ao girar o dispositivo para uma posição diferente daquela em que a atividade estava ativa; executar operações de fragmento, como confirmação de fragmento, causa exceção de estado ilegal. Há muitas reclamações sobre isso. É algo sobre gerenciamento do ciclo de vida da atividade do Android e chamadas de método adequadas. Para resolvê-lo, fiz o seguinte: 1-Substitua o método onsavedInstance da sua atividade e determine a orientação atual da tela (retrato ou paisagem) e defina a orientação da tela antes que sua atividade seja pausada. dessa forma, a atividade que você bloqueia a rotação da tela para a sua atividade, caso tenha sido girada por outra. 2 - substitua um método de atividade de retomada e defina seu modo de orientação agora para sensor, para que, depois que o método salvo seja chamado, ele chame mais uma vez na configuração para lidar com a rotação corretamente.
Você pode copiar / colar este código em sua atividade para lidar com ele:
fonte
Eu tive o mesmo problema, obtendo IllegalStateException, mas substituir todas as minhas chamadas para commit () por commitAllowingStateLoss () não ajudou.
O culpado foi uma ligação para DialogFragment.show ().
Eu o envolvo
e fez isso. OK, não consigo mostrar a caixa de diálogo, mas neste caso estava tudo bem.
Era o único lugar no meu aplicativo em que chamei FragmentManager.beginTransaction (), mas nunca chamei commit (), então não o encontrei quando procurei "commit ()".
O engraçado é que o usuário nunca sai do aplicativo. Em vez disso, o assassino era um anúncio intersticial da AdMob sendo exibido.
fonte
Minha solução para esse problema foi
No fragmento, adicione métodos:
Pode ser ruim, mas não foi possível encontrar nada melhor.
fonte
Eu consegui esse problema, mas acho que esse problema não está relacionado a commit e commitAllowStateLoss.
O seguinte rastreamento de pilha e mensagem de exceção é sobre commit ().
Mas essa exceção foi causada por onBackPressed ()
Todos foram causados por checkStateLoss ()
mStateSaved será verdadeiro após onSaveInstanceState.
Esse problema raramente ocorre. Nunca encontrei esse problema. Não posso repetir o problema.
Encontrei o problema 25517
Pode ter ocorrido nas seguintes circunstâncias
A tecla Voltar é chamada após onSaveInstanceState, mas antes que a nova atividade seja iniciada.
use onStop () no código
Não sei ao certo qual é a raiz do problema. Então eu usei uma maneira feia.
fonte
Eu tenho o mesmo problema no meu aplicativo. Eu resolvi esse problema chamando a
super.onBackPressed();
classe anterior ecommitAllowingStateLoss()
a classe atual com esse fragmento.fonte
commitAllowingStateLoss()
em vez decommit()
onSaveInstance será chamado se um usuário girar a tela para carregar os recursos associados à nova orientação.
É possível que esse usuário tenha girado a tela e pressionado o botão Voltar (porque também é possível que esse usuário atrapalhe o telefone enquanto estiver usando o aplicativo)
fonte
Leia http://chris-alexander.co.uk/on-engineering/dev/android-fragments-within-fragments/
artigo. A verificação fragment.isResumed () me ajuda no onDestroyView sem usar o método onSaveInstanceState.
fonte
Mesmo problema para mim e após um dia de análise de todos os artigos, blog e stackoverflow, encontrei uma solução simples. Não use o método SavedInstanceState, esta é a condição com uma linha de código. No código do fragmento:
fonte
Isso acontece sempre que você está tentando carregar um fragmento, mas a atividade mudou de estado para onPause () .Por exemplo, quando você tenta buscar dados e carregá-los na atividade, mas quando o usuário clica em algum botão e pressiona mudou para a próxima atividade.
Você pode resolver isso de duas maneiras
Você pode usar transaction.commitAllowingStateLoss () em vez de transaction.commit () para carregar o fragmento, mas pode acabar perdendo a operação de confirmação concluída.
ou
Certifique-se de que a atividade esteja retomada e não entre no estado de pausa ao carregar um fragmento. Crie um booleano e verifique se a atividade não está no estado onPause ().
ao carregar o fragmento, verifique se há atividade presente e carregue apenas quando a atividade estiver em primeiro plano.
fonte
Obrigado @ gunar, mas acho que existe uma maneira melhor.
De acordo com o documento:
Então use
commitNow
para substituir:fonte
Bem, depois de tentar todas as soluções acima sem sucesso (porque basicamente eu não tenho transações).
No meu caso, eu estava usando AlertDialogs e ProgressDialog como fragmentos que, às vezes, na rotação, ao solicitar o FragmentManager, o erro aumenta.
Eu encontrei uma solução alternativa misturando alguns posts semelhantes:
É uma solução de 3 etapas, tudo feito em sua FragmentActivity (neste caso, é chamada GenericActivity):
fonte
Quando eu uso a atividade de inicialização em um fragmento, receberei essa exceção;
Quando mudo para usar startactivityforresult, a exceção desaparece :)
Portanto, a maneira mais fácil de corrigi-lo é usar a API startActivityForResult :)
fonte
Eu estava recebendo essa exceção ao pressionar o botão Voltar para cancelar o seletor de intenção na atividade de fragmentos do mapa. Resolvi isso substituindo o código de onResume () (onde estava inicializando o fragmento e confirmando a transação) por onStart () e o aplicativo está funcionando bem agora. Espero que ajude.
fonte
Isso foi corrigido no Android 4.2 e também na fonte da biblioteca de suporte. [*]
Para obter detalhes da causa (e soluções alternativas), consulte o relatório de erros do Google: http://code.google.com/p/android/issues/detail?id=19917
Se você estiver usando a biblioteca de suporte, não precisará se preocupar com esse bug (por muito tempo) [*]. No entanto, se você estiver usando a API diretamente (ou seja, não usando o FragmentManager da biblioteca de suporte) e segmentando uma API abaixo do Android 4.2, precisará tentar uma das soluções alternativas.
[*] No momento da redação, o Android SDK Manager ainda está distribuindo uma versão antiga que exibe esse bug.
Editar Vou acrescentar alguns esclarecimentos aqui, porque obviamente de alguma forma confundi quem recusou esta resposta.
Existem várias circunstâncias diferentes (mas relacionadas) que podem causar o lançamento dessa exceção . Minha resposta acima está se referindo à instância específica discutida na pergunta, ou seja, um bug no Android que foi corrigido posteriormente. Se você está recebendo essa exceção por outro motivo, é porque está adicionando / removendo fragmentos quando não deveria estar (depois que os estados dos fragmentos foram salvos). Se você estiver nessa situação, talvez " Fragmentos Aninhados - IllegalStateException" Não é possível executar esta ação após onSaveInstanceState " " possa ser útil para você.
fonte
Depois de pesquisar um pouco, a solução para esse problema é fazer o seu fragmento confirmado no currículo.
Fonte: https://wenchaojames.wordpress.com/2013/01/12/illegalstateexception-from-onactivityresult/
fonte
Meu caso de uso: usei o ouvinte no fragmento para notificar a atividade que algo aconteceu. Eu fiz o novo fragmento confirmar no método de retorno de chamada. Isso funciona perfeitamente bem na primeira vez. Mas, na mudança de orientação, a atividade é recriada com o estado da instância salva. Nesse caso, o fragmento não é criado novamente implica que o fragmento tem o ouvinte que é uma atividade destruída antiga. De qualquer maneira, o método de retorno de chamada será acionado na ação. Vai para a atividade destruída que causa o problema. A solução é redefinir o ouvinte no fragmento com a atividade ativa atual. Isso resolve o problema.
fonte
O que descobri é que, se outro aplicativo for do tipo caixa de diálogo e permitir que toques sejam enviados para o aplicativo em segundo plano, quase qualquer aplicativo em segundo plano falhará com esse erro. Acho que precisamos verificar sempre que uma transação for executada se a instância foi salva ou restaurada.
fonte
No meu caso, com a mesma exceção de erro, coloquei o "onBackPressed ()" em um executável (você pode usar qualquer uma das suas visualizações):
Eu não entendo o porquê, mas funciona!
fonte
Você pode estar chamando fragmentManager.popBackStackImmediate (); quando a atividade está em pausa. A atividade não está concluída, mas está em pausa e não está em primeiro plano. Você precisa verificar se a atividade está em pausa ou não antes de popBackStackImmediate ().
fonte
Eu notei algo muito interessante. Eu tenho no meu aplicativo a opção de abrir a galeria do telefone e o dispositivo pergunta qual aplicativo usar; clique na área cinza da caixa de diálogo e vi esse problema. Percebi como minha atividade passa de onPause, onSaveInstanceState de volta para onResume, e isso não acontece com onCreateView. Estou fazendo transações no onResume. Então, o que acabei fazendo é definir um sinalizador sendo negado em Pausa, mas sendo verdadeiro emCriarView. se o sinalizador for verdadeiro onResume, execute onCommit, caso contrário, commitAllowingStateLoss. Eu poderia continuar perdendo muito tempo, mas queria verificar o ciclo de vida. Eu tenho um dispositivo que é o sdkversion 23 e não entendi esse problema, mas eu tenho outro que tem 21 anos e lá estou.
fonte
você pode usar FragmentActivity.onStart antes de popBackStackImmediate
como isso:
http://jorryliu.blogspot.com/2014/09/illegalstateexception-can-not-perform.html
fonte