Flutter: um novo framework de desenvolvimento mobile:

Por Gabriel Chaves|
Atualizado: Jun 2021 |
Publicado: Mar 2020

O Flutter é um framework de desenvolvimento híbrido para mobile, tanto Android quanto IOS, que trabalha em cima de widgets. Toda aplicação mobile precisa de uma maneira para lidar com chamadas assíncronas e para compartilhar estado entre as telas do aplicativo. E com o Flutter não é diferente, porém ele têm algumas funcionalidades, muito interessantes, para te auxiliar com isso: futures providers.

Pensando em ajudar você a entender melhor como essas funcionalidades funcionam, escrevi um breve tutorial mostrando como implementá-las. Vamos lá?

Futures – a maneira como o flutter lida com funções assíncronas

Imagine que você é um garçom e a cozinha te avisa que um prato foi liberado. Logo, você irá demorar alguns segundos para buscar o prato e realizar a entrega para o cliente que fez esse pedido. Vamos chamar esta ação de buscarPratoNaCozinha. Veja como isso ficaria no formato de um future

class Prato {
    String nome;
    int preco;

    Prato(int preco, String nome){
        this.nome = nome;
        this.preco = preco;
    }
}

Future <Prato> buscarPratoNaCozinha(){
    var prato = Future<Prato>.delayed(
        Duration(seconds: 4),
            () => new Prato(40, "Tropeiro completo"),
    );

    return prato;
}
Quer ver mais conteúdos como esse?

Mas, e ai? Bom, com um future, você consegue renderizar a tela com um FUTURE BUILDER.

Vem que eu te explico como funciona: o Flutter possui essa funcionalidade chamada future builder. Com ela, você altera a tela para o seu usuário, baseado no estado atual da sua requisição assíncrona. Para simplificar, vamos considerar que nossa requisição possui apenas três estados: 

  1. default:, ela ainda não está completa, ou seja, não houve nenhum retorno;
  2. hasData:, que foi um sucesso e sua função assíncrona já retornou o valor;
  3. hasError:, ocorreu um erro na sua função assíncrona. 

No caso da nossa chamada buscarPratoNaCozinha(), temos que: 

  1. default: o garçom ainda não retornou com o prato para a mesa do cliente;
  2. hasData: já nos retornou um prato;
  3. hasError: o garçom deixou o prato cair no caminho para a mesa. 

Veja como ficaria o código e o resultado: 

 FutureBuilder<Prato>(
    future: _future,
    builder: (BuildContext context, AsyncSnapshot<Prato> snapshot){
        if (snapshot.hasData){
            Prato prato = snapshot.data;
            //Widget para o prato.
        } else if (snapshot.hasError){
            //Widget do erro, caso ele aconteça.
        } else{
            //Widget para exibir o progresso.
        }
    }
)

framework de desenvolvimento mobile

Note que um Future Builder recebe um future (a chamada assíncrona que ele irá realizar) e um builder (que ele irá renderizar na tela dependendo do estado da chamada). Toda vez que o estado muda, o Flutter chama o método builder  novamente e identifica qual componente ele tem que renderizar, através das condições que colocamos dentro do builder

Providers – como controlar o estado global da sua aplicação

Agora imagine que a cozinha desse restaurante é dividida em algumas partes, e que cada parte tem uma televisão onde eles veem quais são os pedidos. Por exemplo, uma parte da cozinha cuida do preparo das verduras, e outra cuida do preparo da carne. Como avisar para todos que um novo pedido chegou? 

Existem abordagens diferentes, as mais comuns são: reduxBLoC e provider. Nesse tópico iremos implementar um provider, que foi a abordagem utilizada no nosso projeto em Flutter. Veja como ficou o código para o nosso primeiro provider

class Pedidos with ChangeNotifier {
    final List<Prato> _pedidosPendentes = [];

    UnmodifiableListView<Prato> get pedidos =>
UnmodifiableListView(_pedidosPendentes); void realizarPedido(Prato prato) { _pedidosPendentes.add(prato); notifyListeners(); } }

Nele, temos uma lista privada de pratos, _pedidosPendentes, que será exibida para todas as partes da nossa cozinha, e dois métodos: realizarPedido, que adiciona um prato a nossa lista, e pedidos, que retorna uma instância imutável da lista _pedidosPendentes

Agora, para continuar o fluxo de um provider, precisamos inserir um pedido, por meio do método realizarPedido, veja como fica: 

 void _inserirNovoPrato(BuildContext context, Prato prato){
    Provider.of<PedidosModel>)(context, listen: false).realizarPedido(prato);
}

Widget _blocoPrato(BuildContext context, Prato prato){
    BorderSide borda = BorderSide(width: 2.0, color: Colors.black);

    return InkWell(
        child: Padding(
            padding: EdgeInsets.only(top: 16),
            child: Container(
                padding: EdgeInsets.all(24),
                decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(8),
                    border: Border(
                        top: borda,
                        left: borda,
                        right: borda,
                        bottom: borda,
                    ),
                    color: Colors.white),
                child: Center(child: Text('${prato.nome}')),

            ),
        ),
        onTap: () => {_inserirNovoPrato(context, prato)},
    );
}

flutter

Na parte destacada do código, temos um bloco para representar cada prato que pode ser preparado pela cozinha. Ao clicar no bloco, o método _realizarPedido é chamado, e nele temos o código para chamar o método do nosso provider

Provider.of<PedidosModel>(context, listen:false).realizarPedido(prato);

Agora é quando a mágica acontece! Quando o realizarPedido do nosso provider é chamado, ele insere um registro na nossa lista _pedidosPendentes, e chama a função notifyListeners(). Ela vai avisar para todos aqueles que estão escutando o nosso provider que um novo pedido chegou, ou que a nossa lista mudou. Mas, como fazer para escutar as mudanças do nosso provider? É só criar um consumer

Um consumer é apenas um listener para o nosso provider. Portanto, quando você cria um, você especifica a qual provider ele escutará, e depois implementa o método builder, que será renderizado na tela. Dentro do builder, você consegue acessar todos os métodos e atributos públicos do provider, inclusive o nosso método pedidos, que retorna a nossa lista de pedidosPendentes. Por fim, veja como fica o código de um consumer

Container(
    padding: EdgeInsets.only(top: 100, left: 20, right: 20, bottom: 100),
    color: Colors.white,
    child: Consumer<PedidosModel>(
        itemCount: pratos.length,
        itemBuilder: (BuildContext context, int index){
            return Container(
                    padding: EdgeInsets.all(24),
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(8),
                        border: Border(
                            top: borda,
                            left: borda,
                            right: borda,
                            bottom: borda,
                        ),
                        color: Colors.white
                    ),
                    child: Center(child: Text('${pratos[index].nome}')),
                ),
            ),
        }
    )
)

Bom, termino esse post por aqui. Espero que esse breve tutorial tenha sido muito útil para você, que queria aprender um pouco mais sobre o Flutter!

Até a próxima!

 

Quer saber mais?