Cómo crear una máquina de estado en Jetpack Compose | por Marco Cattaneo

Contenidos

Veremos cómo crear una máquina de estados e implementarla en Jetpack Compose

https://dribbble.com/shots/16692100-

¿Por qué necesitamos una máquina de estado en Jetpack Compose? ¡Empecemos con lo básico!

Componer jet pack

Jetpack Compose es el nuevo marco lanzado por Google que reemplazará el sistema de visualización XML introducido actualmente. hace diez años. Es muy diferente del método heredado a medida que pasamos del enfoque de programación imperativa a la programación declarativa donde los componentes de la interfaz de usuario son funciones y cada argumento representa una propiedad o incluso un Condición nuestro componente. El Estado: Esta es la parte más importante de este artículo porque básicamente Compose fue desarrollado responder a un cambio de estadoesto significa que nuestro objetivo principal es encontrar la mejor manera de manipular este estado. Cuando digo mejor, quiero decir:

  • Mantener este estado consistentemente durante la ejecución
  • Haga que el código sea legible/mantenible sin código de espagueti 🍝
  • hazlo comprobable (por favor, no te saltes este punto 😈)

caso de estudio

El propósito de este artículo es explicar cómo implementar una máquina de estado utilizando esta biblioteca https://github.com/freeletics/FlowRedux, cómo integrarla en Jetpack Compose y, por último, pero no menos importante, cómo escribir pruebas en ella. Nuestro caso de estudio será una pequeña aplicación que le permite al usuario escribir un nombre de usuario de Github y obtener su lista de repositorios asociados, por lo que nuestra capa de dominio expone esta interfaz: de lo contrario, desde la perspectiva de la interfaz de usuario, nuestra aplicación consta de una caja de textouna confirmacion botón y un Columna perezosacomo este fragmento: Ahora necesitamos encontrar un mejor pegamento para esos interfaz de usuario y el capa de dominio: una máquina de escenario. Mi sugerencia es pensar en las condiciones. ¿Qué conjunto de estados representará mi interfaz de usuario? Pensé en tres de ellos:

  • estado del contenido: donde básicamente el caja de texto se actualiza con el nombre de usuario y el Columna perezosa con la lista de repositorios (LazyColumn funciona como un RecyclerView)
  • Estado de carga: Se usa cuando la aplicación envía la solicitud HTTP
  • Estado de error: es el caso de que algo sale mal

Ahora eventos/acciones que pueden manipular nuestro estado:

  • El usuario ingresa el nombre de usuario: En Compose, existe el concepto de flujo de datos unidireccional (lea más aquí), por lo que debemos mantenerlo caja de texto‘s valor en nuestro estado.
  • Toca el botón «Confirmar»: El evento se activa cuando un usuario toca el botón de búsqueda.
  • El usuario solicita un reintento: activado por el botón de reintento en estado de error.

Si dibujamos la máquina de estado, debería verse así:Máquina de estado de la aplicación Desde la perspectiva del código, estos podrían ser nuestros estados y acciones:Estados y acciones

La máquina de estado

Ahora, para la parte divertida, vamos a implementar la máquina de estado y debemos definir las acciones admitidas para cada uno de estos estados. Flujo Redux nos ayudará en esta iteración.Flujo Redux es una biblioteca que le permite crear una máquina de estado donde podemos especificar para cada estado (al estilo de DSL) qué acciones se admiten. Cada acción puede ejecutar la lógica y manipular el estado de diferentes maneras:

  • Sobrescribir el estado con uno nuevo
  • mudar las propiedades de estado sin cambiar el tipo
  • mantener el mismo estado sin cambios

Mira el ejemplo a continuación. Básicamente creamos un Máquina de estado de FlowRedux con un estado basado en GithubState y una serie de acciones en base a eso GithubAcción, entonces necesitamos definir el estado inicial, Este será el estado inicial, en nuestro caso este es el ContentState (donde la entrada y los repositorios están vacíos).Ahora tenemos que describir el comportamiento de la máquina de estado dentro del especificación {}, Flujo Redux le permite definir diferentes comportamientos para cualquier acción en función del estado actual Estado del contenido:En este estado, decimos que cada vez que se imprime la interfaz de usuario:

  • GithubAction.TypeOwner los mutamos ContentState para persistir la entrada del usuario.
  • GithubAction.Confirmar lo sobrescribimos con el Estado de carga que contiene el nombre de usuario ingresado por el usuario (si no está vacío, de lo contrario no hacemos nada).

Las acciones de ContentStateAnd the carga estado? Es un poco diferente porque usamos el en Entrar {} función, esta función se llama cada vez que el estado cambia a cargay eso es perfecto, porque podemos llamar a eso Repositorio Github y obtener la lista de repositorios.Acciones de estado de carga y error En caso de éxito, sobrescribimos el estado con el ContentState de lo contrario cambiamos a encendido error Estado donde básicamente podemos repetir la llamada:

Cómo integrar StateMachine en Jetpack Compose

La máquina de estado está lista, ahora debemos adjuntarla a nuestra interfaz de usuario componible. Hay muchas maneras, he decidido encapsular la máquina de estado en un modelo de vista y pasarlo a la interfaz de usuario. Básicamente tengo un resumen AbsStateViewModel que expone el estado y permite que las acciones sean despachadas usando viewModelScope (porque el exportar método de Máquina de estado de FlowRedux es una función de suspensión). Así que creé uno GithubViewModel lo que expande esta clase: Y por fin puedo pasarla Ver modelo Dentro de la función componible, este es el resultado:

Pruebas

¡Oye! ¿A dónde vas? Ahora su máquina de estado está lista, ¡pero también necesita escribir pruebas! Es bastante fácil ya que las actualizaciones de estado viajan en un flujo de kotlin Necesita una biblioteca para ayudarlo a probar la emisión. Sugiero https://github.com/cashapp/turbine, que se adapta a nuestras áreas.

También usé https://github.com/mockk/mockk para burlarme y, si está interesado, también escribí un artículo al respecto.

Por ejemplo, en esta prueba probamos la entrada del nombre de usuario: pruebo la entrada en este otro, probamos el comportamiento en caso de que falle la llamada a la API: pruebo la búsqueda en caso de error

Conclusiones

Flujo Redux es una biblioteca genial, ¿es la mejor solución? Tal vez sí o tal vez no, nos encanta la frase «depende», con la que también he trabajado un poco en el pasado. IMV patrón y siento que funciona más o menos de la misma manera, pero tenemos más control porque podemos definir fácilmente qué acciones están disponibles para un estado determinado y tenemos una mejor jerarquía. Otro beneficio está relacionado con la declaración, la sintaxis DSL simplifica el código, haciéndolo más legible y mantenible. ¡Espero que hayas disfrutado leyendo este artículo! Deje 1/2/toneladas de 👏 si le gustó, ¡los comentarios también son bienvenidos!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.