Descripción general de ViewModel (vistas)
Conceptos y la implementación de Jetpack Compose
La clase ViewModel es un contenedor de lógica empresarial o estado a nivel de pantalla. Expone el estado a la IU y encapsula la lógica empresarial relacionada.
Su principal ventaja es que almacena en caché el estado y lo conserva durante los cambios de configuración. Esto significa que la IU no tiene que recuperar datos cuando navegas entre actividades o si sigues cambios de configuración, como cuando rotas la pantalla.
Beneficios de ViewModel
La alternativa a un ViewModel es una clase simple que contiene los datos que muestras en tu IU. Esto puede convertirse en un problema cuando navegas entre actividades o destinos de Navigation. Si lo haces, esos datos se destruirán si no los almacenas con el mecanismo de guardado de estado de instancias. ViewModel proporciona una API conveniente para la persistencia de datos que resuelve este problema.
Los beneficios clave de la clase ViewModel son básicamente dos:
- Te permite conservar el estado de la IU.
- Proporciona acceso a la lógica empresarial.
Alcance
Cuando creas una instancia de ViewModel, le pasas un objeto que implementa la interfaz ViewModelStoreOwner. Puede ser un destino de Navigation, un gráfico de navegación, una actividad, un fragmento o cualquier otro tipo que implemente la interfaz. El alcance de tu ViewModel se define en el Lifecycle del
ViewModelStoreOwner. Continúa en la memoria hasta que su ViewModelStoreOwner desaparece de forma permanente.
Un rango de clases son subclases directas o indirectas de la interfaz ViewModelStoreOwner. Las subclases directas son ComponentActivity, Fragment y NavBackStackEntry.
Para obtener una lista completa de las subclases indirectas, consulta la
ViewModelStoreOwner referencia.
Cómo implementar un ViewModel
El siguiente es un ejemplo de implementación de un ViewModel para una pantalla que le permite al usuario lanzar un dado.
Kotlin
data class DiceUiState(
val firstDieValue: Int? = null,
val secondDieValue: Int? = null,
val numberOfRolls: Int = 0,
)
class DiceRollViewModel : ViewModel() {
// Expose screen UI state
private val _uiState = MutableStateFlow(DiceUiState())
val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()
// Handle business logic
fun rollDice() {
_uiState.update { currentState ->
currentState.copy(
firstDieValue = Random.nextInt(from = 1, until = 7),
secondDieValue = Random.nextInt(from = 1, until = 7),
numberOfRolls = currentState.numberOfRolls + 1,
)
}
}
}
Java
public class DiceUiState {
private final Integer firstDieValue;
private final Integer secondDieValue;
private final int numberOfRolls;
// ...
}
public class DiceRollViewModel extends ViewModel {
private final MutableLiveData<DiceUiState> uiState =
new MutableLiveData(new DiceUiState(null, null, 0));
public LiveData<DiceUiState> getUiState() {
return uiState;
}
public void rollDice() {
Random random = new Random();
uiState.setValue(
new DiceUiState(
random.nextInt(7) + 1,
random.nextInt(7) + 1,
uiState.getValue().getNumberOfRolls() + 1
)
);
}
}
Luego, puedes acceder a ViewModel desde una actividad de la siguiente manera:
Kotlin
import androidx.activity.viewModels
class DiceRollActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same DiceRollViewModel instance created by the first activity.
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
val viewModel: DiceRollViewModel by viewModels()
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
// Update UI elements
}
}
}
}
}
Java
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
DiceRollViewModel model = new ViewModelProvider(this).get(DiceRollViewModel.class);
model.getUiState().observe(this, uiState -> {
// update UI
});
}
}
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Cómo usar las corrutinas de Kotlin con componentes optimizados para ciclos de vida
- Cómo guardar estados de la IU
- Cómo cargar y mostrar datos paginados