Conversor con binding feliz

@DEPRECATED
Este ejemplo se reemplazar con éste: Conversor con Data Binding

La aplicación

Repasemos una vez más de qué se trata
  • ingresamos un valor en kilómetros (o una unidad de origen)
  • pedimos "Convertir"
  • y la aplicación nos devuelve el valor convertido a millas (o una unidad de destino)

Conversor sin binding

En esta página vimos cómo desarrollar un conversor. Generamos un modelo pero no teníamos la posibilidad de tener binding
  • entre propiedades de nuestro modelo de dominio (un objeto conversor) y la propiedad de un elemento visual o widget, como el valor ingresado en el EditText con los kilómetros
  • entre acciones y los eventos de usuario, como el hecho de presionar el botón Convertir.
Las desventajas saltan a la vista:
  • tenemos que pedir las referencias a cada control (mediante el findViewById)
  • perdemos la posibilidad de definir controllers que resuelvan estas tareas repetitivas, esto incluye por ejemplo la adaptación de los valores entre el dominio y la vista
  • como la vista publica listeners, queda a criterio de quien desarrolla pensar un modelo y adaptarlo en ese listener
    • no se obliga desde la Activity a que exista un model, al contrario de lo que pasa en Arena, donde se fuerza ese mecanismo de binding desde la misma creación de la vista
  • todo resulta en el incremento de la cantidad de líneas de código y lo que es peor, en la repetición de ideas

Generando nuestro propio mecanismo de binding

El proyecto android-mvc que proveemos en los ejemplos nos permiten incorporar mecanismos sencillos de binding, reutilizando conceptos que nos son familiares y que ya hemos conocido en Arena:
  • los modelos de nuestra vista extienden de ObservableObject, que es quien registra los cambios en el modelo y los notifica a los observers (modelo -> vista)
  • a su vez nuestras activities deben disparar la actualización del modelo, esto se hace a partir de un objeto ModelBinder (vista -> modelo), que sirve tanto para editar propiedades como para disparar acciones
El lector puede investigar el desarrollo del proyecto android-mvc que queda como material BONUS de la materia.

Activity conversor

Cuál es nuestro model: un ConversorApplicationModel, al que le pasamos un conversor

Definiendo el binding

El activity define un modelBinder, que utilizamos en el onCreate:

override void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState)

    contentView = R.layout.activity_conversor

       

    this.binder = new ModelBinder(this, model)

        .property(R.id.conversor_millas, "millas") //

        .property(R.id.conversor_kilometros, "kilometros") //

        .action(R.id.conversor_convertir, "convertir") //

        .when(Events.CONVERTIR, "actualizarResultado") //

        .updateView()

}


  • nuestro application model debe exponer como properties millas y kilómetros, el modelBinder se encarga de relacionarlo con un EditText (conversor_millas) y un TextView (conversor_kilometros)
  • el action dispara el evento convertir hacia el application model
  • esto no resuelve enteramente nuestro problema, ya que necesitamos además forzar a que la vista se vuelva a bindear contra el modelo una vez hecha la conversión...

Interfaz Events para disparar notificaciones a la vista

Ok, cada vez que se dispare el evento Convertir tenemos que refrescar la vista. Definimos entonces un enum en nuestro proyecto:

public enum Events implements BusinessEvent {

    CONVERTIR

}


Esto debemos codificarlo en Java ya que por el momento no podemos decirle a un Enum de Xtend que implemente una interfaz.
Aquí anotamos todos los eventos de usuario que se pueden disparar y que tienen sentido para la vista.

Entonces en el onCreate podemos escribir esta línea:
.when(Events.CONVERTIR, "actualizarResultado") //
(mapeamos un BusinessEvent que debe disparar el applicationModel contra un método de nuestra vista)

El actualizarResultado simplemente va a refrescar la vista al igual que la última línea del onCreate de nuestra activity:

def void actualizarResultado() {

    binder.updateView()

}


El application model

Nuestro application model delega la responsabilidad de convertir al modelo, no obstante, tiene la misión de disparar el evento CONVERTIR que definimos antes:

def void convertir(){

    this.model.convertir

    fireEvent(Events.CONVERTIR)

}


Esto le llega a la vista quien disparará el actualizarResultado.
En cierta medida podemos decir que hay signos de sobrediseño mantener dominio + application model tan parecidos (como podrá notar el lector viendo la definición de las properties millas y kilómetros), de todas maneras sirve como ejemplo didáctico que el lector puede utilizar cuando la aplicación crezca en complejidad.

El resultado

Es básicamente similar a la aplicación que no tiene binding, la diferencia no pasa por la experiencia de usuario, sino por la experiencia del desarrollador...

TODO: El application model también convierte de Double a String!!
TODO 2: Millas a kilómetros y no al revés. Cambiar.
Comments