Encontrei muitos casos de uma pergunta semelhante no SO, mas infelizmente nenhuma resposta atende aos meus requisitos.
Tenho layouts diferentes para retrato e paisagem e estou usando a pilha traseira, o que me impede de usar setRetainState()
e truques usando rotinas de alteração de configuração.
Eu mostro certas informações para o usuário no TextViews, que não são salvas no manipulador padrão. Ao escrever meu aplicativo apenas usando o Activities, o seguinte funcionou bem:
TextView vstup;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.whatever);
vstup = (TextView)findViewById(R.id.whatever);
/* (...) */
}
@Override
public void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
state.putCharSequence(App.VSTUP, vstup.getText());
}
@Override
public void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
vstup.setText(state.getCharSequence(App.VSTUP));
}
Com Fragment
s, isso funciona apenas em situações muito específicas. Especificamente, o que quebra horrivelmente é substituir um fragmento, colocá-lo na pilha de trás e girar a tela enquanto o novo fragmento é mostrado. Pelo que entendi, o fragmento antigo não recebe uma chamada ao onSaveInstanceState()
ser substituído, mas permanece ligado de alguma forma ao Activity
e esse método é chamado posteriormente quando View
não existe mais, portanto, procurando por qualquer um dos meus TextView
resultados em a NullPointerException
.
Além disso, descobri que manter a referência à minha TextViews
não é uma boa ideia com Fragment
s, mesmo que esteja OK com Activity
's. Nesse caso, onSaveInstanceState()
na verdade salva o estado, mas o problema reaparece se eu girar a tela duas vezes quando o fragmento estiver oculto, pois onCreateView()
ele não é chamado na nova instância.
Pensei em salvar o estado em onDestroyView()
algum Bundle
elemento membro da classe (na verdade são mais dados, não apenas um TextView
) e salvá- lo , onSaveInstanceState()
mas existem outras desvantagens. Principalmente, se o fragmento é atualmente mostrado, a ordem de chamar as duas funções é invertida, então eu precisaria considerar duas situações diferentes. Deve haver uma solução mais limpa e correta!
fonte
Respostas:
Para salvar corretamente o estado da instância
Fragment
, faça o seguinte:1. No fragmento, salve o estado da instância substituindo
onSaveInstanceState()
e restaurando emonActivityCreated()
:2. E um ponto importante , na atividade, você deve salvar a instância do fragmento
onSaveInstanceState()
e restaurá-laonCreate()
.Espero que isto ajude.
fonte
É assim que estou usando neste momento ... é muito complicado, mas pelo menos lida com todas as situações possíveis. Caso alguém esteja interessado.
Como alternativa , é sempre possível manter os dados exibidos em
View
s passivos nas variáveis e usar osView
s apenas para exibi-los, mantendo as duas coisas sincronizadas. Mas não considero a última parte muito limpa.fonte
A
eB
, ondeA
está atualmente no backstack eB
é visível, perde o estado deA
(o invisível um) se você girar a tela duas vezes . O problema é queonCreateView()
não é chamado apenas nesse cenárioonCreate()
. Então, mais tarde,onSaveInstanceState()
não há visualizações para salvar o estado. Seria necessário armazenar e salvar o estado passadoonCreate()
.App.VSTUP
eApp.STAV
são duas tags de seqüência de caracteres que representam os objetos que estão tentando obter. Exemplo:savedState = savedInstanceState.getBundle(savedGamePlayString);
ousavedState.getDouble("averageTime")
Na biblioteca de suporte mais recente, nenhuma das soluções discutidas aqui é mais necessária. Você pode brincar com seus
Activity
fragmentos conforme desejarFragmentTransaction
. Apenas verifique se seus fragmentos podem ser identificados com um ID ou tag.Os fragmentos serão restaurados automaticamente, desde que você não tente recriá-los a cada chamada para
onCreate()
. Em vez disso, você deve verificar sesavedInstanceState
não é nulo e, nesse caso, encontrar as referências antigas aos fragmentos criados.Aqui está um exemplo:
Observe, no entanto, que existe atualmente um erro ao restaurar o estado oculto de um fragmento. Se você estiver ocultando fragmentos em sua atividade, será necessário restaurar esse estado manualmente neste caso.
fonte
FragmentPagerAdapter
ouFragmentStatePagerAdapter
. Se você olhar o código deFragmentStatePagerAdapter
, por exemplo, verá que orestoreState()
método restaura os fragmentos doFragmentManager
parâmetro que você passou como ao criar o adaptador.Eu só quero dar a solução que eu criei que lida com todos os casos apresentados neste post que eu derivei do Vasek e do devconsole. Essa solução também lida com o caso especial quando o telefone é girado mais de uma vez enquanto os fragmentos não são visíveis.
Aqui é onde eu armazeno o pacote para uso posterior, pois onCreate e onSaveInstanceState são as únicas chamadas feitas quando o fragmento não está visível
Como destroyView não é chamado na situação de rotação especial, podemos ter certeza de que, se ele criar o estado, devemos usá-lo.
Esta parte seria a mesma.
Agora, aqui está a parte complicada. No meu método onActivityCreated, instanciamos a variável "myObject", mas a rotação ocorre onActivity e onCreateView não são chamados. Portanto, myObject será nulo nessa situação quando a orientação girar mais de uma vez. Eu resolvo isso reutilizando o mesmo pacote que foi salvo no onCreate como o pacote que está saindo.
Agora, onde você quiser restaurar o estado, basta usar o pacote salvoState
fonte
Graças ao DroidT , fiz isso:
Sei que se o fragmento não executar onCreateView (), sua exibição não será instanciada. Portanto, se o fragmento na pilha traseira não criar suas visualizações, eu salvo o último estado armazenado, caso contrário, construo meu próprio pacote com os dados que desejo salvar / restaurar.
1) Estenda esta classe:
2) No seu fragmento, você deve ter o seguinte:
3) Por exemplo, você pode chamar hasSavedState em onActivityCreated:
fonte
fonte