Padrão de provedor no Flutter

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State {
  int _counter = 0;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Agora adicione a dependência para o padrão do provedor no diretório pubspec.yaml Arquivo. No momento da redação deste artigo, a versão mais recente é 4.1.2.

Aqui está como pubspec.yaml o arquivo ficará agora:

name: provider_pattern_explained
description: A new Flutter project.

publish_to: 'none' 

version: 1.0.0+1

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  provider: ^4.1.2

  cupertino_icons: ^0.1.3

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true

O aplicativo padrão é basicamente um widget com estado, que é reconstruído toda vez que você clica no botão FloatingActionButton (que chama setState() )

Mas agora vamos convertê-lo em um widget sem estado.

Vamos seguir em frente e criar nosso provedor. Esta será a única fonte de verdade para o nosso aplicativo. É aqui que armazenaremos nosso estado, que neste caso é a contagem atual.

Crie uma classe chamada Counter e adicione o count variável:

import 'package:flutter/material.dart';

class Counter {
  var _count = 0;
}

Para convertê-lo em uma classe de provedor, estenda ChangeNotifier de material.dart pacote. Isso nos fornece o notifyListeners() e notificará todos os ouvintes sempre que alterarmos um valor.

Agora adicione um método para incrementar o contador:

import 'package:flutter/material.dart';

class Counter extends ChangeNotifier {
  var _count = 0;
  void incrementCounter() {
    _count += 1;
  }
}

No final deste método, chamaremos notifyListeners(). Isso acionará uma alteração em todo o aplicativo para o widget que estiver ouvindo.

Essa é a beleza do padrão de provedor no Flutter - você não precisa se preocupar em enviar manualmente para fluxos.

Por fim, crie um getter para retornar o valor do contador. Usaremos isso para exibir o valor mais recente:

import 'package:flutter/material.dart';

class Counter extends ChangeNotifier {
  var _count = 0;
  int get getCounter {
    return _count;
  }

  void incrementCounter() {
    _count += 1;
    notifyListeners();
  }
}

Ouvindo cliques no botão

Agora que temos o provedor configurado, podemos prosseguir e usá-lo em nosso widget principal.

Primeiro, vamos converter MyHomePage para um widget sem estado em vez de com um estado. Teremos que remover o setState() ligar já que está disponível apenas em StatefulWidget:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  int _counter = 0;
  final String title;
  MyHomePage({this.title});
  void _incrementCounter() {}
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Com isso feito, agora podemos usar o padrão de provedor no Flutter para definir e obter o valor do contador. Em cada botão, precisamos aumentar o valor do contador em 1.

Então, no _incrementCounter método (que é chamado quando o botão é pressionado) adicione esta linha:

Provider.of(context, listen: false).incrementCounter();

O que está acontecendo aqui é que você pediu ao Flutter para subir no árvore de widgets e encontre o primeiro lugar onde Counter é fornecido. (Vou lhe dizer como fornecê-lo na próxima seção.) É isso que Provider.of() faz.

Os genéricos (valores dentro <> colchetes) informam ao Flutter que tipo de provedor procurar. Em seguida, o Flutter percorre a árvore do widget até encontrar o valor fornecido. Se o valor não for fornecido em nenhum lugar, uma exceção será lançada.

Por fim, depois de obter o provedor, você pode chamar qualquer método. Aqui chamamos nossa incrementCounter método.

Mas também precisamos de um contexto, por isso aceitamos o contexto como argumento e alteramos o onPressed método para passar o contexto também:

void _incrementCounter(BuildContext context) {
  Provider.of(context, listen: false).incrementCounter();
}

Observação: definimos listen para false porque não precisamos ouvir nenhum valor aqui. Estamos apenas enviando uma ação a ser executada.

O padrão do provedor no Flutter procurará o valor mais recente fornecido. O diagrama abaixo ajudará você a entender melhor.

Neste diagrama, o VERDE objeto UMA estará disponível para o restante dos elementos abaixo, ou seja, B, C, D, E, e F.

Agora, suponha que desejamos adicionar alguma funcionalidade ao aplicativo e criamos outro provedor, Z. Z é requerido por E e F.

Então, qual é o melhor lugar para adicionar isso?

Podemos adicioná-lo à raiz acima UMA. Isso funcionaria:

Mas esse método não é muito eficiente.

O Flutter percorre todos os widgets acima e, finalmente, vai para a raiz. Se você possui árvores de widgets muito longas - o que você definitivamente criará em um aplicativo de produção -, não é uma boa ideia colocar tudo na raiz.

Em vez disso, podemos olhar para o denominador comum de E e F. Isso é C. Então, se colocarmos Z logo acima de E e F, funcionaria.

Mas e se quisermos adicionar outro objeto X isso é exigido por E e F? Faremos a mesma coisa. Mas observe como a árvore continua crescendo.

Existe uma maneira melhor de gerenciar isso. E se fornecermos todos os objetos em um nível?

Isso é perfeito e é como implementaremos nosso padrão de provedor no Flutter. Vamos usar algo chamado MultiProvider o que nos permite declarar vários fornecedores em um nível.

Nós conseguiremos MultiProvider para embrulhar o MaterialApp ferramenta:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(
          value: Counter(),
        ),
      ],
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: MyHomePage(title: "AndroidVille Provider Pattern"),
      ),
    );
  }
}

Com isso, fornecemos o provedor à nossa árvore de widgets e podemos usá-lo em qualquer lugar abaixo deste nível na árvore.

Resta apenas mais uma coisa: precisamos atualizar o valor exibido.

Atualizando o texto

Para atualizar o texto, obtenha o provedor na função de construção do seu MyHomePage ferramenta. Usaremos o getter que criamos para obter o valor mais recente.

Em seguida, basta adicionar esse valor ao widget de texto abaixo.

E nós terminamos! É assim que o seu final main.dart O arquivo deve ter a seguinte aparência:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_pattern_explained/counter.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(
          value: Counter(),
        ),
      ],
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: MyHomePage(title: "AndroidVille Provider Pattern"),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;
  MyHomePage({this.title});
  void _incrementCounter(BuildContext context) {
    Provider.of(context, listen: false).incrementCounter();
  }

  @override
  Widget build(BuildContext context) {
    var counter = Provider.of(context).getCounter;
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => _incrementCounter(context),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Nota: ainda não definimos listen:false neste caso, porque queremos ouvir as atualizações no valor da contagem.

Aqui está o código fonte no GitHub, se você quiser dar uma olhada: https://github.com/Ayusch/Flutter-Provider-Pattern.

Deixe-me saber se você tem algum problema.

Bem-vindo ao AndroidVille 🙂

AndroidVille é uma comunidade de desenvolvedores de dispositivos móveis, onde compartilhamos conhecimentos relacionados ao desenvolvimento Android, desenvolvimento de vibração, tutoriais nativos do React, Java, Kotlin e muito mais.

Clique neste link para ingressar na área de trabalho do AndroidVille SLACK. É absolutamente grátis!

Se você gostou deste artigo, sinta-se à vontade para compartilhá-lo no Facebook ou LinkedIn. Você pode me seguir LinkedIn, Twitter, Quorae Médio onde respondo perguntas relacionadas ao desenvolvimento móvel, Android e Flutter.