Várias operações do sistema Android podem afetar o estado do fragmento. Para garantir que o estado do usuário seja salvo, o framework do Android salva e restaura automaticamente os fragmentos e a pilha de retorno. Portanto, você precisa garantir que todos os dados do seu fragmento também sejam salvos e restaurados.
A tabela a seguir descreve as operações que fazem com que o fragmento perca o estado e se os vários tipos de estado persistem com essas mudanças. Os tipos de estado mencionados na tabela são os seguintes:
- Variáveis: variáveis locais no fragmento.
- Estado da visualização: qualquer dado pertencente a uma ou mais visualizações no fragmento.
- SavedState: dados inerentes a essa instância de fragmento que precisam ser salvos
em
onSaveInstanceState(). - NonConfig: dados extraídos de uma fonte externa, como um servidor ou repositório local, ou dados criados pelo usuário que são enviados a um servidor após a confirmação.
Muitas vezes, as variáveis são tratadas da mesma forma que SavedState, mas a tabela a seguir distingue entre os dois para demonstrar o efeito das várias operações em cada um.
| Operação | Variáveis | Estado da visualização | SavedState | NonConfig |
|---|---|---|---|---|
| Adicionado à pilha de retorno | ✓ | ✓ | x | ✓ |
| Mudança de configuração | x | ✓ | ✓ | ✓ |
| Interrupção/recriação de processos | x | ✓ | ✓ | ✓* |
| Removido e não adicionado à backstack | x | x | x | x |
| Host concluído | x | x | x | x |
* O estado NonConfig pode ser retido durante o encerramento do processo usando o módulo Saved State para ViewModel.
Tabela 1: várias operações destrutivas de fragmentos e os efeitos que elas têm em diferentes tipos de estado.
Vejamos um exemplo específico. Imagine uma tela que gera uma
string aleatória, exibindo-a em uma TextView e oferecendo uma opção para editar
a string antes de enviá-la a um amigo:
Para esse exemplo, suponha que, quando o usuário pressionar o botão de edição, o
app exibirá uma visualização EditText, em que o usuário poderá editar a mensagem. Se o
usuário clicar em CANCELAR, a visualização EditText será removida, e a
visibilidade será definida como View.GONE. Essa
tela pode exigir o gerenciamento de quatro partes de dados para garantir uma experiência
perfeita:
| Dados | Tipo | Tipo de estado | Descrição |
|---|---|---|---|
seed |
Long |
NonConfig | Seed usada para gerar aleatoriamente uma nova boa ação. Gerada quando
o ViewModel é criado. |
randomGoodDeed |
String |
SavedState + variável | Gerado quando o fragmento é criado pela primeira vez.
A randomGoodDeed é salva para garantir que os usuários tenham acesso à
mesma boa ação aleatória até mesmo após o encerramento e
a recriação do processo. |
isEditing |
Boolean |
SavedState + variável | Sinalização booleana definida como true quando o usuário começa a editar.
isEditing é salvo para garantir que a parte de edição
da tela permaneça visível quando o fragmento é recriado. |
| Texto editado | Editable |
Estado da visualização (propriedade de EditText) |
O texto editado na visualização EditText.
A EditText salva esse texto para garantir que as mudanças
em andamento do usuário não sejam perdidas. |
Tabela 2: determina que o app gerador de texto aleatório precisa fazer o gerenciamento.
Nas seções a seguir, descrevemos como gerenciar corretamente o estado dos seus dados usando operações destrutivas.
Estado da visualização
As visualizações são responsáveis por gerenciar os próprios estados. Por exemplo, quando uma
visualização aceita entrada do usuário, é responsabilidade dela salvar e restaurar
essa entrada para processar as mudanças de configuração. Todas as visualizações fornecidas pelo framework do Android têm a própria implementação de onSaveInstanceState() e
onRestoreInstanceState(). Assim, você não precisa gerenciar o estado da visualização no
seu fragmento.
Por exemplo, no cenário anterior, a string editada é mantida em um
EditText. Um EditText sabe
o valor do texto que está sendo exibido, bem como outros detalhes, como
o início e o fim de qualquer texto selecionado.
Uma visualização precisa de um ID para reter o estado. Esse ID precisa ser exclusivo no fragmento e na hierarquia da visualização. Visualizações sem ID não podem reter o estado.
<EditText android:id="@+id/good_deed_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" />
Como mencionado na tabela 1, as visualizações salvam e restauram ViewState usando
todas as operações que não removem o fragmento nem destroem o host.
SavedState
Seu fragmento é responsável por gerenciar pequenas quantidades de estado dinâmico
que são essenciais para as funções do fragmento. É possível reter
dados facilmente serializados usando
Fragment.onSaveInstanceState(Bundle).
De modo semelhante a
Activity.onSaveInstanceState(Bundle),
os dados que você coloca no pacote são retidos por mudanças de configuração
e processam o encerramento e a recriação, estando disponíveis nos métodos
onCreate(Bundle),
onCreateView(LayoutInflater, ViewGroup, Bundle)
e
onViewCreated(View, Bundle)
do fragmento.
Continuando com o exemplo anterior, randomGoodDeed é a ação
exibida para o usuário, enquanto isEditing é uma sinalização para determinar se o
fragmento exibe ou oculta o EditText. Esse estado salvo precisa ser
mantido usando onSaveInstanceState(Bundle), conforme mostrado no exemplo
a seguir:
Kotlin
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putBoolean(IS_EDITING_KEY, isEditing) outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed) }
Java
@Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(IS_EDITING_KEY, isEditing); outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed); }
Para restaurar o estado em onCreate(Bundle), recupere o valor armazenado
do pacote:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) isEditing = savedInstanceState?.getBoolean(IS_EDITING_KEY, false) randomGoodDeed = savedInstanceState?.getString(RANDOM_GOOD_DEED_KEY) ?: viewModel.generateRandomGoodDeed() }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { isEditing = savedInstanceState.getBoolean(IS_EDITING_KEY, false); randomGoodDeed = savedInstanceState.getString(RANDOM_GOOD_DEED_KEY); } else { randomGoodDeed = viewModel.generateRandomGoodDeed(); } }
Como mencionado na tabela 1, as variáveis são retidas quando o fragmento é colocado na pilha de retorno. Tratá-las como estado salvo garante que elas persistam por todas as operações destrutivas.
NonConfig
Os dados de NonConfig precisam ser colocados fora do seu fragmento, como em
um ViewModel. No exemplo
anterior, seed (nosso estado NonConfig) é gerado no ViewModel.
A lógica para manter o estado pertence ao ViewModel.
Kotlin
public class RandomGoodDeedViewModel : ViewModel() { private val seed = ... // Generate the seed private fun generateRandomGoodDeed(): String { val goodDeed = ... // Generate a random good deed using the seed return goodDeed } }
Java
public class RandomGoodDeedViewModel extends ViewModel { private Long seed = ... // Generate the seed private String generateRandomGoodDeed() { String goodDeed = ... // Generate a random good deed using the seed return goodDeed; } }
A classe ViewModel permite inerentemente que os dados sobrevivam a mudanças de
configuração, como rotações de tela, e permaneçam na memória quando o
fragmento é colocado na pilha de retorno. Após o encerramento e a recriação do processo,
o ViewModel é recriado, e uma nova seed é gerada. A adição de um
módulo SavedState
ao ViewModel permite que o ViewModel retenha o estado simples após o
encerramento e a recriação do processo.
Outros recursos
Para ver mais informações sobre como gerenciar o estado de fragmentos, consulte os recursos a seguir.