Varias operaciones del sistema Android pueden afectar el estado de tu fragmento. Para garantizar que se guarde el estado del usuario, el framework de Android guarda y restablece automáticamente los fragmentos y la pila de actividades. Por lo tanto, debes asegurarte de guardar y restablecer también todos los datos de tu fragmento.
En la siguiente tabla, se describen las operaciones que hacen que el fragmento pierda su estado, junto con la posibilidad de que los diferentes tipos de estado se conserven a través de esos cambios. Los tipos de estado que se mencionan en la tabla son los siguientes:
- Variables: Variables locales en el fragmento
- View State: Cualquier dato que pertenezca a una o más vistas del fragmento
- SavedState: Datos inherentes a esta instancia del fragmento que se deben guardar en
onSaveInstanceState()
- NonConfig: Datos extraídos de una fuente externa, como un servidor o repositorio local, o datos creados por el usuario que se envían al servidor una vez confirmados
A menudo, las Variables se tratan de la misma manera que el SavedState, pero la tabla siguiente distingue entre los dos para mostrar el efecto de las distintas operaciones en cada uno.
Operación | Variables | View State | SavedState | NonConfig |
---|---|---|---|---|
Agregado a la pila de actividades | ✓ | ✓ | x | ✓ |
Cambio de configuración | x | ✓ | ✓ | ✓ |
Cierre o recreación del proceso | x | ✓ | ✓ | ✓* |
Quitado, no agregado a la pila de actividades | x | x | x | x |
Host terminado | x | x | x | x |
* Se puede retener el estado NonConfig luego del cierre del proceso mediante el módulo de estado guardado para ViewModel.
Tabla 1: Varias operaciones destructivas de fragmentos y los efectos que tienen en diferentes tipos de estados
Veamos un ejemplo específico. Considera una pantalla que genera una string aleatoria, la muestra en una TextView
y proporciona la opción de editar la string antes de enviarla a un amigo:
Para este ejemplo, supongamos que una vez que el usuario presiona el botón de edición, la app muestra una vista de EditText
en la que el usuario puede editar el mensaje. Si este hace clic en CANCELAR, la vista de EditText
se debe borrar y su visibilidad se debe establecer en View.GONE
. Tal pantalla podría requerir la administración de cuatro datos para garantizar una experiencia sin interrupciones:
Datos | Tipo | Tipo de estado | Descripción |
---|---|---|---|
seed |
Long |
NonConfig | Seed utilizada para generar un nuevo random good deed. Generada cuando se crea el ViewModel . |
randomGoodDeed |
String |
SavedState + Variable | Generado cuando se crea el fragmento por primera vez.
randomGoodDeed se guarda para garantizar que los usuarios vean el mismo random good deed, incluso después del cierre del proceso y de su recreación. |
isEditing |
Boolean |
SavedState + Variable | Marca booleana establecida en true cuando el usuario comienza a editar.
Se guarda isEditing para garantizar que la parte de edición de la pantalla permanezca visible cuando se vuelva a crear el fragmento. |
Texto editado | Editable |
View State (propiedad de EditText ) |
El texto editado en la vista de EditText .
La vista EditText guarda este texto para garantizar que no se pierdan los cambios en curso del usuario. |
Tabla 2: Estados que debe administrar la app de generación de textos aleatorios
En las siguientes secciones, se describe cómo administrar adecuadamente el estado de tus datos mediante operaciones destructivas.
Estado de vistas
Las vistas se encargan de administrar su propio estado. Por ejemplo, cuando una vista acepta la entrada del usuario, es su responsabilidad guardar y restablecer esa entrada para controlar los cambios de configuración. Todas las vistas proporcionadas por el framework de Android tienen su propia implementación de onSaveInstanceState()
y onRestoreInstanceState()
, por lo que no necesitas administrar el estado de la vista en tu fragmento.
Por ejemplo, en la situación anterior, la string editada se conserva en un EditText
. Un EditText
reconoce el valor del texto que muestra, así como otros detalles, como el principio y el final del texto seleccionado.
Una vista necesita un ID para retener su estado. Ese ID debe ser único dentro del fragmento y de su jerarquía de vistas. Las vistas que no tienen un ID no pueden retener su estado.
<EditText android:id="@+id/good_deed_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" />
Como se mencionó en la Tabla 1, las vistas guardan y restablecen su ViewState
a través de todas las operaciones que no quitan el fragmento ni destruyen el host.
SavedState
Tu fragmento se encarga de administrar pequeñas cantidades de estado dinámico que son fundamentales para su funcionamiento. Puedes retener datos serializados con facilidad mediante Fragment.onSaveInstanceState(Bundle)
.
Similar a Activity.onSaveInstanceState(Bundle)
, los datos que colocas en el paquete se retienen a través de cambios de configuración y del cierre y la recreación de los procesos, y están disponibles en los métodos onCreate(Bundle)
, onCreateView(LayoutInflater, ViewGroup, Bundle)
y onViewCreated(View, Bundle)
de tu fragmento.
Siguiendo con el ejemplo anterior, randomGoodDeed
es la acción que se muestra al usuario y isEditing
es una marca para determinar si el fragmento muestra u oculta el EditText
. Este estado guardado debe conservarse por medio de onSaveInstanceState(Bundle)
, como se muestra en el siguiente ejemplo:
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 restablecer el estado de onCreate(Bundle)
, recupera el valor almacenado del paquete:
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 se mencionó en la Tabla 1, ten en cuenta que las variables se retienen cuando el fragmento se coloca en la pila de actividades. Tratarlas como estados guardados garantiza que se conserven a lo largo de todas las operaciones destructivas.
NonConfig
Los datos de NonConfig deben colocarse fuera de tu fragmento, como en un ViewModel
. En el ejemplo anterior, seed
(nuestro estado de NonConfig) se genera en el ViewModel
.
La lógica para mantener su estado pertenece al 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; } }
La clase ViewModel
permite de forma inherente que los datos sobrevivan a los cambios de configuración, como las rotaciones de pantalla, y que permanezcan en la memoria cuando el fragmento se coloca en la pila de actividades. Después del cierre y de la recreación del proceso, se recrea el ViewModel
y se genera una nueva seed
. Agregar un módulo de SavedState
a tu ViewModel
permite que el ViewModel
retenga un estado simple a través del cierre y la recreación del proceso.
Recursos adicionales
Si deseas obtener más información para administrar el estado de los fragmentos, consulta los siguientes recursos adicionales:
Codelabs
- Codelab de componentes optimizados para ciclos de vida