State Management with Flutter

Asked

Viewed 164 times

0

Good afternoon, I have a problem, I have my code below, and in it I do the following, when it opens the screen for the first time it searches data from an api and saved in the database. Soon the user can close the app and open it again, when he opens the screen and already has the data he searches directly in the database and fills the Paginateddatatable, calms the second option works properly, the database data are fine, the problem is when I run the api, inside the api already has the process of saving in the bank, saved right without problems, but wait there and do not fill my Paginateddatatable, follow the code below all, thanks for the help.

import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:....../conexao/endpoints_api.dart';
import 'package:....../api/produtos/produto.dart';
import 'package:balanco_app/helpers/database_helper.dart';
import 'package:balanco_app/models/dados_acesso.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class ListaDeProdutos extends StatefulWidget {
  @override
  _ListaDeProdutosState createState() => _ListaDeProdutosState();
}

class _ListaDeProdutosState extends State<ListaDeProdutos> {

  DatabaseHelper db = DatabaseHelper();
  Endpoints endpoints = Endpoints();
  bool sort;
  Color primaryColor;
  int _rowPerPage = PaginatedDataTable.defaultRowsPerPage;
  String sCnpj;
  String sUser;
  String sChave;

  @override
  void initState() {
    super.initState();

    resgataDados();
    sCnpj = context.read<DadosAcesso>().cnpjInicial;
    sUser = context.read<DadosAcesso>().usuario;
    sChave = context.read<DadosAcesso>().codAcesso;
  }


  @override
  Widget build(BuildContext context) {
    primaryColor = Theme.of(context).primaryColor;
    DTS dts = DTS(context.read<DadosAcesso>().listProd);

    setState(() {
      dados();
    });

    return FutureBuilder(
      future: db.getAllProdutos(),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData) {
          return Container(
            child: ListView(
              children: [
                PaginatedDataTable(
                  sortColumnIndex: 1,
                  columnSpacing: 3,
                  dataRowHeight: 55,
                  horizontalMargin: 3,
                  headingRowHeight: 30,
                  header: Text('Lista de Produtos'),
                  columns: [
                    DataColumn(
                      label: Text(
                        'Cód.',
                        style: TextStyle(
                            fontStyle: FontStyle.normal,
                            fontWeight: FontWeight.bold,
                            fontSize: 15),
                      ),
                    ),
                    DataColumn(
                      label: Text(
                        'Descrição',
                        style: TextStyle(
                            fontStyle: FontStyle.normal,
                            fontWeight: FontWeight.bold,
                            fontSize: 18),
                      ),
                    ),
                    DataColumn(
                      label: Text(
                        'QTDE',
                        style: TextStyle(
                            fontStyle: FontStyle.normal,
                            fontWeight: FontWeight.bold,
                            fontSize: 16),
                      ),
                    ),
                  ],


                  source: dts,
                  onRowsPerPageChanged: (r) {
                    setState(() {
                      _rowPerPage = r;
                    });
                  },
                  rowsPerPage: _rowPerPage,
                ),
              ],
            ),
          );
        } else {
          return circularProgressGP();
        }
      },
    );
  }

  resgataDados() async {
    List linhas = await db.getDsDados();
    for (var linha in linhas) {
      sCnpj = linha['cnpjInicial'].toString();
      sUser = linha['usuario'].toString();
      sChave = linha['codAcesso'].toString();
    }
  }

  dados() async {

      await db.getAllProdutos().then((value) async{
        value.forEach((element) {
          context.read<DadosAcesso>().listProd.add(Produto(
              codbarras: element['codbarras'],
              desproduto: element["desproduto"]));
        });


        print('Lista length: ${context.read<DadosAcesso>().listProd.length}');

    if(context.read<DadosAcesso>().listProd.length == 0){
      await endpoints.resgata_produtos(sUser, sCnpj, sChave);

      context.read<DadosAcesso>().listProd.clear();

      await db.getAllProdutos().then((value) {
        value.forEach((element) {
          context.read<DadosAcesso>().listProd.add(Produto(
              codbarras: element['codbarras'],
              desproduto: element["desproduto"]));
        });
      }).catchError((error) {
        print(error);
      });
    }
      }).catchError((error) {
        print(error);
      });
    }
    
}

circularProgressGP() {
  return Container(
    color: Colors.white,
    child: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            SizedBox(
              height: 100,
            ),
            SizedBox(
              height: 90,
              width: 90,
              child: CircularProgressIndicator(backgroundColor: Colors.white),
            ),
            SizedBox(
              height: 40,
            ),
            RotateAnimatedTextKit(
                duration: const Duration(milliseconds: 2000) ,
                onTap: () {},
                text: ["Conectando...", "Buscando Dados...", "Aguarde..."],
                textStyle: TextStyle(fontSize: 30, color: Colors.black),
                textAlign: TextAlign.start
            ),

          ],
        )
    ),
  );
}

class DTS extends DataTableSource{
  DTS(this.listProd);

  DatabaseHelper db = DatabaseHelper();
  Material material = Material();
  final List<Produto> listProd;

  @override
  DataRow getRow(int index) {

    assert(index >= 0);

    if (index >= listProd.length) return null;
    final row = listProd[index];

    print('Index: $index');

    return DataRow.byIndex(
        index: index,
        color: MaterialStateProperty.resolveWith<Color>(
                (Set<MaterialState> states) {
              if (states.contains(MaterialState.selected))
                return material.color.withOpacity(0.08);
              if (index % 2 == 0) return Colors.grey.withOpacity(0.3);
              return null;
            }),
        cells: [
          DataCell(
            Container(
              constraints: BoxConstraints(maxWidth: 150),
              child: Text(row.codbarras),
            ),
          ),
          DataCell(
            Container(
              constraints: BoxConstraints(maxWidth: 150),
              child: Text(
                row.desproduto,
                style: TextStyle(fontSize: 15),
              ),
            ),
          ),
          DataCell(
            Center(
              child: Container(
                constraints: BoxConstraints(maxWidth: 110),
                child: TextField(
                  keyboardType: TextInputType.number,
                  //controller: qtde_controller,
                  onChanged: (text) {
                    print("Texto digitado:  $text");
                  },
                  onTap: (){

                  },
                ),
              ),
            ),
          ),
        ]);
  }

  @override
  bool get isRowCountApproximate => true;

  @override
  int get rowCount => 10;

  @override
  int get selectedRowCount => 0;
}

What I’m doing wrong, because whenever the api runs and pulls the data and saved in the database, but does not present to me on screen, the api is right, I believe it should be something from Paginateddatatable, I appreciate the help.

  • What is within the method db.getAllProdutos()? Your screen will only be updated when you return any valid data in the call of that method that the Futurebuilder is listening... the way you did calling the method setState(() { dados(); }); will not draw anything on screen, because inside the Futurebuilder you are validating if it has some data and not the properties of the screen itself.

  • The method has the following: Future<List<Map<String, Dynamic>>> getAllProducts() async { Database db = await this.database; print('passing...'); Return await db.rawQuery('SELECT * FROM product'); }

  • What I could do is put the data() directly into the Futrebuilder, it may be for sure. But then he keeps processing and the information doesn’t come. I’m lost....

  • Fernando, do not edit the question by adding "[solved]" to the title. [pt.so] is not a discussion forum. You have your own tools to signal that the question has been answered. See What should I do if someone answers my question?. If the current answer does not meet 100%, make your answer explaining the solution.

1 answer

1

You’ve lost yourself in the midst of asynchronous methods await and then()...

There are two ways to do what you want, but I will focus on the Futurebuilder.

First let’s modify your method Dice() as follows:

List<Produtos> dados() async {

    List<Produtos> produtos = []; 
    
    produtos = await db.getAllProdutos(); 
  
    if(produtos.isEmpty()){
      await endpoints.resgata_produtos(sUser, sCnpj, sChave);

      context.read<DadosAcesso>().listProd.clear();

      produtos = await dados();
    } else {
        produtos.forEach((element) {
          context.read<DadosAcesso>().listProd.add(Produto(
              codbarras: element['codbarras'],
              desproduto: element["desproduto"]));
        });
    }
    
    return produtos;
}

Thus, using only the await, your method will wait for each call to then return to your Futurebuilder all available data.

Now it is necessary to adjust your Futurebuilder, Let’s do it this way:

FutureBuilder(
      future: dados(),
      builder: (BuildContext context, AsyncSnapshot<List<Map<String, dynamic>>> snapshot) {
        if (snapshot.hasData) {
          DTS dts = DTS(snapshot.data);
            
          return Container(
            child: ListView(
              children: [
                PaginatedDataTable(
                  sortColumnIndex: 1,
                  columnSpacing: 3,
                  dataRowHeight: 55,
                  horizontalMargin: 3,
                  headingRowHeight: 30,
                  header: Text('Lista de Produtos'),
                  columns: [
                    DataColumn(
                      label: Text(
                        'Cód.',
                        style: TextStyle(
                            fontStyle: FontStyle.normal,
                            fontWeight: FontWeight.bold,
                            fontSize: 15),
                      ),
                    ),
                    DataColumn(
                      label: Text(
                        'Descrição',
                        style: TextStyle(
                            fontStyle: FontStyle.normal,
                            fontWeight: FontWeight.bold,
                            fontSize: 18),
                      ),
                    ),
                    DataColumn(
                      label: Text(
                        'QTDE',
                        style: TextStyle(
                            fontStyle: FontStyle.normal,
                            fontWeight: FontWeight.bold,
                            fontSize: 16),
                      ),
                    ),
                  ],


                  source: dts,
                  onRowsPerPageChanged: (r) {
                    setState(() {
                      _rowPerPage = r;
                    });
                  },
                  rowsPerPage: _rowPerPage,
                ),
              ],
            ),
          );
        } else {
          return circularProgressGP();
        }
      },
    );

Explanation

The Futurebuilder will call the method Dice(), which in turn will fetch in the database all the necessary information, if not found will try to request to the API. Once this is done, it will return the available data to the Futurebuilder which will make the figures available within snapshot.data which in your case is a list of Maps.

That way, try to Futurebuilder after handling all requests, you can make the call from your class DTS, if information is available.

Obs.: Since you did not inform us the type of the list of products, I played something generic List<Produtos>, then you make the necessary modifications...

  • Opa, I appreciate the help, I did all the modification and the procedures you indicated, but I did not succeed, I did a print on the return of the Builder to see the snapshot, print(snapshot.data); and null return, which could be wrong?

  • Man I hadn’t seen the method resgatarDados(), I modified my answer, take a look... I took the content of the method resgatarDados() and put inside the method dados(). If you test and stay always "Loading" you will have to debug and analyze better where the problem is in the database data call. The Flow of precediment in general is what is in my answer.

  • Good morning, look at this function of rescued data(), serves only to take the data for endpoint execution, has no relevancy, the first version of the answer you put got better, but still does not show on screen, It’s as if Futurebuilder wasn’t standing there looking at the result because the snapshot.data always returns null. I made some modifications there in the function until I return, but returns only if you already have data in database, if you execute the endpoint and then have the data saved...

  • End in a way that worked, but now I’m with another problem kkkk, if you have too much data it takes to present.. Would you know how to fix it? Thanks a lot.

  • Oops, if I was going to trade this for a Streanbuilder, like it would be, because there’s going to be a search field and I need to update the Paginateddatatable, so I really think only with Stranbuilder right?

  • Man, the questions here on the site are for direct questions to a problem. You’re already having doubts on several points... Stop and think if this change is really necessary and study a little about the Widgets cited, so if necessary create new questions. (Maybe a state management like Bloc or Mobx can help you, worth take a look)

  • Thanks for reply VERY DIRECT, "man". Thank you.

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.