View Model¶
Usar esta docuentación:
* Guía inicial
* Codelab para viewmodel: scrambleum
En Compose tenemos State
para mantener y pasar datos entre componentes.
Con ViewModel
iremos un paso más alla liberando a Activity y Fragment del mantenimiento del estado de la app.
Forma parte de Jetpack y se corresponde con la arquitectura MVVM (Nodel-View-View-Model).
Primer vistazo a ViewModel¶
El objetivo es desacoplar la lógica de presentación de los componentes.
ViewModel se situa entre el modelo (capa de datos ) y el UI
La idea principal es que los estados van hacia abajo, del viewModel al UI y los eventos(pulsaciones usuario) haciea arriba del UI al ViewModel.
--REVISAR--
ViewModel:
* La vista recibe actualizaciones del estado IU desde el ViewModel
* Viewmodel recibe actualizaciones mediante suscripción a otro componente: LiveData
LiveData:
- Es un componente observable
- Contiene un estado y cuando hay cambio avisa a los subscriptores.
Las Activities y Fragment se subscriben a LiveData a través del ViewModel.
LiveData está pendiente del ciclo de vida de Activity y Fragment (onDestroy, etc).
Partimos de un ejemplo con una pantalla principal con el estado y un componente que lee un nombre y actualiza el estado y un Text de salida
@Composable
fun MainScreen(){
val nameState = remember {mutableStateOf("")}
Surface(
color =
modifier=
){
MainLayout(nameState.value
){
newName -> nameState.value = newName
}
}
}
En MainLayout añadimos dos parámetros: name y una lambda *cammbioTexto"
@Composable
fun MainLayout(
name: String,
cambiaTexto: (String)-> Unit
){
Column {
Text()
TextField(
value=name,
onValueChanged=cambioTexto
)
Text(
text= name
)
}
}
Transformamos este código para incluir ViewModel. En un nuevo fichero creamos una clase derivada con un atributo LiveData para el estado y una función para recibir los eventos.
class MainViewModel: ViewModel() {
val nameState: MutableLiveData("")
fun onTextFieldChange(nuevoTexto: String){
}
}
Hemos creado el estado nameState
Ahora cambiamos MainScreen para admitir el ViewModel, que damos valor por defecto para no cambiar en otras parte del código.
Cambiamos la asignación de nameState
También cambiamos la lambda por una notificación del viewmovel con el métodos público
@Composable
fun MainScreen(viewModel: MainViewModel = MainViewModel())){
val nameState = viewModel.nameState.observeAsState("")
Surface(
color =
modifier=
){
MainLayout(nameState.value
){
newName -> viewModel.onTextFieldChange(newName)
}
}
}
Textfield ligado con state¶
Parámetros de Textfield * value: String texto a mostrar * onValueChange: (String)->Unit lambda de evento por cada cambio en la entrada.
Usaremos los estados para comparar las nuevas entradas.
Por ejemplo: Para el nombre del estudiante. En el componente padre añadimos el estado newStudenteState
@Composable
fun MainScreen() {
val studentsState = remember { mutableStateListOf("Esther", "Jaime") }
val newStudentState = remember { mutableStateOf("") }
Surface(
color = Color.LightGray,
modifier = Modifier.fillMaxSize()
) {
StudentList(
studentsState,
{ studentsState.add(newStudentState.value) },
newStudentState.value,
{ newStudent -> newStudentState.value = newStudent }
)
}
}
@Composable
fun StudentList(
students: List<String>,
onButtonClick: () -> Unit,
studentName: String,
onStudentNameChange: (String) -> Unit
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
for (student in students) {
StudentText(name = student)
}
TextField(
value = studentName,
onValueChange = onStudentNameChange
)
Button(
onClick = onButtonClick
) {
Text(text = "Add new student")
}
}
}