Você faz isso através da implementação View#onSaveInstanceState
e View#onRestoreInstanceState
e estender a View.BaseSavedState
classe.
public class CustomView extends View {
private int stateToSave;
...
@Override
public Parcelable onSaveInstanceState() {
//begin boilerplate code that allows parent classes to save state
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
//end
ss.stateToSave = this.stateToSave;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
//begin boilerplate code so parent classes can restore state
if(!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
//end
this.stateToSave = ss.stateToSave;
}
static class SavedState extends BaseSavedState {
int stateToSave;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
this.stateToSave = in.readInt();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(this.stateToSave);
}
//required field that makes Parcelables from a Parcel
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
O trabalho é dividido entre as classes View e SavedState da View. Você deve fazer todo o trabalho de ler e escrever de e para Parcel
a SavedState
turma. Em seguida, sua classe View poderá extrair os membros do estado e fazer o trabalho necessário para retornar a classe a um estado válido.
Notas: View#onSavedInstanceState
e View#onRestoreInstanceState
são chamadas automaticamente para você se View#getId
retornar um valor> = 0. Isso acontece quando você fornece um ID em xml ou chama setId
manualmente. Caso contrário, você tem que chamar View#onSaveInstanceState
e escrever o Parcelable voltou para o pacote que você entrar em Activity#onSaveInstanceState
para salvar o estado e, posteriormente, lê-lo e passá-lo para View#onRestoreInstanceState
partir Activity#onRestoreInstanceState
.
Outro exemplo simples disso é o CompoundButton
onSaveInstanceState()
eonRestoreInstanceState()
deveria serprotected
(como a superclasse), nãopublic
. Não há razão para expô-los ...BaseSaveState
para uma classe que estende o RecyclerView,Parcel﹕ Class not found when unmarshalling: android.support.v7.widget.RecyclerView$SavedState java.lang.ClassNotFoundException: android.support.v7.widget.RecyclerView$SavedState
você precisa executar a correção de bug descrita aqui: github.com/ksoichiro/Android-ObservableScrollView/commit/… (usando o ClassLoader de RecyclerView.class para carregar o estado super)Eu acho que esta é uma versão muito mais simples.
Bundle
é um tipo embutido que implementaParcelable
fonte
onRestoreInstanceState
seria chamado com um pacote seonSaveInstanceState
retornasse um pacote?OnRestoreInstance
é herdado. Não podemos mudar o cabeçalho.Parcelable
é apenas uma interface,Bundle
é uma implementação para isso.View
estado base não é umBundle
. Obviamente, isso é verdade no momento, mas você está contando com esse fato de implementação atual que não é garantido.Aqui está outra variante que usa uma mistura dos dois métodos acima. Combinando a velocidade e a correção
Parcelable
com a simplicidade de umBundle
:fonte
State
pacote. Por favor, dê uma olhada em: charlesharley.com/2012/programming/…As respostas aqui já são ótimas, mas não necessariamente funcionam para grupos de vistas personalizados. Para que todas as Views personalizadas mantenham seu estado, você deve substituir
onSaveInstanceState()
eonRestoreInstanceState(Parcelable state)
em cada classe. Você também precisa garantir que todos tenham IDs exclusivos, sejam inflados a partir do xml ou adicionados programaticamente.O que eu criei foi notavelmente como a resposta do Kobor42, mas o erro permaneceu porque eu estava adicionando as Views a um ViewGroup personalizado programaticamente e não atribuindo IDs exclusivos.
O link compartilhado por mato funcionará, mas significa que nenhuma das Visualizações individuais gerencia seu próprio estado - todo o estado é salvo nos métodos do ViewGroup.
O problema é que, quando vários desses grupos de vistas são adicionados a um layout, os IDs de seus elementos do xml não são mais exclusivos (se definidos em xml). No tempo de execução, você pode chamar o método estático
View.generateViewId()
para obter um ID exclusivo para uma Visualização. Isso está disponível apenas na API 17.Aqui está o meu código do ViewGroup (é abstrato e mOriginalValue é uma variável de tipo):
fonte
Eu tive o problema de que onRestoreInstanceState restaurou todas as minhas visualizações personalizadas com o estado da última visualização. Eu o resolvi adicionando esses dois métodos à minha exibição personalizada:
fonte
Em vez de usar
onSaveInstanceState
eonRestoreInstanceState
, você também pode usar aViewModel
. Amplie seu modelo de dadosViewModel
e, em seguida, você pode usarViewModelProviders
para obter a mesma instância do seu modelo toda vez que a Atividade for recriada:Para usar
ViewModelProviders
, adicione o seguintedependencies
emapp/build.gradle
:Observe que você
MyActivity
estende emFragmentActivity
vez de apenas estenderActivity
.Você pode ler mais sobre o ViewModels aqui:
fonte
ViewModel
é especialmente útil se você tiver grandes conjuntos de dados para reter durante uma alteração de estado, como uma rotação de tela. Eu prefiro usá-ViewModel
lo em vez de escrevê-loApplication
porque ele tem um escopo claro e posso ter várias atividades do mesmo aplicativo se comportando corretamente.Descobri que essa resposta estava causando algumas falhas nas versões 9 e 10. do Android. Acho que é uma boa abordagem, mas quando eu estava olhando para algum código do Android , descobri que estava faltando um construtor. A resposta é bastante antiga, portanto, na época, provavelmente não havia necessidade. Quando adicionei o construtor ausente e o chamei do criador, a falha foi corrigida.
Então, aqui está o código editado:
fonte
Para aumentar outras respostas - se você tiver várias visualizações compostas personalizadas com o mesmo ID e todas elas estiverem sendo restauradas com o estado da última visualização em uma alteração na configuração, tudo que você precisa fazer é dizer à visualização para enviar apenas os eventos de salvar / restaurar substituindo alguns métodos.
Para uma explicação do que está acontecendo e por que isso funciona, consulte esta postagem no blog . Basicamente, os IDs de exibição dos filhos da visualização composta são compartilhados por cada visualização composta e a restauração do estado fica confusa. Ao despachar apenas o estado da própria exibição composta, impedimos que seus filhos recebam mensagens misturadas de outras visualizações compostas.
fonte