Patrón Provider en flutter

Noé Montes AlvarezFlutter

¡Hola! Esta es mi primera entrada en el blog. La idea del blog es básicamente publicar cosas que voy probando, no solo de flutter, sino de cualquier lenguaje o tecnología. Espero no aburriros demasiado y que os sea util en la medida de lo posible.

Mi intención no es crear tutoriales completos sobre distintos lenguajes, por eso en esta entrada no empiezo hablando de que es flutter, que es dart o que es un widget. Publicaré ejemplos sobre funcionalidades concretas. Bueno, vamos al lío que me enrollo más que las persianas.

¿Qué es provider?

Provider es un manejador de estado. Nos permite la comunicación entre widgets centralizando la información en una clase la cual notifica el cambio de estado para que se redibujen los widget (que están escuchando este provider) mostrando los últimos cambios en la información. No es el único manejado de estado que existe en flutter (cubit, bloc …), pero sí es muy utilizado por su fácil implementación.

Aplicación de prueba

Para ver cómo funciona provider vamos a hacer una aplicación de ejemplo. Va a ser una aplicación muy sencilla. Se trata del clásico contador que se crea como código base cada vez que arrancamos un proyecto en flutter, pero modificado para comunicar los componentes usando el patrón Provider. Puedes descargarte el código completo en:

https://github.com/dark-wave/flutter-provider-demo

Instalación

Instalar provider es muy sencillo. Para ello podemos acceder a la página de https://pub.dev Esta página es un repositorio de paquetes, donde puedes encontrar librerías tanto de los propios desarrolladores de Flutter como de terceros. Una vez dentro buscamos el paquete provider (cuando escribí este articulo la última versión era la 4.3.2+4) y lo incluimos en el fichero pubspec.yaml.

provider: ^4.3.2+4

Guardamos los cambios, esto ejecuta el comando flutter packages get que realiza la instalación del paquete. Ya podemos utilizarlo

Clase provider o service

Como habíamos visto en la definición de provider, necesitamos una clase (o varias ya que se pueden implementar varios provider en la aplicación) que se encarga de centralizar la información que vamos a compartir entre los distintos componentes (widgets) de la aplicación. Esta clase es conocida como provider (o service) y tiene que extender de ChangeNotifier, clase encargada de exponer los eventos de notificación.

import 'package:flutter/material.dart';

class CounterService extends ChangeNotifier{
  int _counter = 0;

  int get counter => this._counter;

Como podemos ver en esta clase tenemos una variable privada _counter que almacena un entero. Podemos crear un método para incrementar su valor.

void increase(){
   this._counter++;
   notifyListeners();
}

Una vez incrementado el valor podemos notificar a todos los widget que escuchen ese _counter el cambio para que actualicen su estado.

Multiprovider

Ahora que tenemos la información necesitamos «encapsular» aquellos widget que van a escuchar estos cambios. Normalmente este multiprovider se incluye en el primer nivel de la aplicación (aunque no es necesario) de esta manera todos los elementos que se encuentren por debajo de el, van a escuchar los cambios en el estado.

MultiProvider(
  providers: [
    ChangeNotifierProvider(create: (_) => CounterService())
  ],

En este ejemplo tenemos un único provider aunque podríamos tener mas clases. Desde este momento cualquier elemento que se encuentre por debajo de este MultiProvider será candidato de escuchar los cambios en la clase CounterService

Modificación y escucha del provider

En este punto ya tenemos todos los ingredientes para poder comunicar los distintos widgets de la aplicación usando como intermediario provider mediante nuestra clase CounterService. Por ejemplo podemos crear un botón que incremente el valor de nuestro contador

FloatingActionButton(
  onPressed: (){
    final counterService = Provider.of<CounterService>(context, listen: false);
    counterService.increase();
  },
  tooltip: 'Increment',
  child: Icon(Icons.add),
)

Vamos a centrarnos en el evento onPressed, que como su nombre indica se lanza cuando pulsamos el botón. Tiene dos lineas de código (nada complicado) la primera crea una instancia de nuestro provider. Como podemos tener varias clases dentro de nuestro MultiProvider tenemos que especificar que clase de todas las que puede tener nuestro provider queremos instancias. Esto lo hacemos mediante .of<CounterService>. Como punto importante tenemos en la sentencia un listen: false. Esto indica que este botón no se tiene q redibujar cuando cambie el estado.

Ahora que hemos cambiado el estado del provider vamos a crear un widget Text que va a escuchar el provider para pintar por pantalla el valor de _counter.

final counterService = Provider.of<CounterService>(context);
Text('${counterService.counter}'),

Al igual que en el botón volvemos a llamar a la instancia de provider, pero en este caso no pasamos el parámetro listen: false. No pasarle el parámetro es lo mismo que enviar un listen: true. En este caso si nos interesa que cada vez que el estado cambie se redibuje el widget (en este ejemplo el Text).

Bueno pues hasta aquí este ejemplo del patrón provider. Espero haberme explicado bien. Las ideas en la cabeza están claras, pero expresarlas por escrito no es tan fácil jeje. Nos vemos en la siguiente entrada!!!

Bye!!