即使我测试了数据是否正确,Flutter Provider 也没有更新我的 Widget?

标签 flutter dart

问题:我正在尝试构建一个从 JSON 文件获取数据的小部件,但我不确定为什么提供程序不更新该小部件。 (调试时没有错误,只是小部件没有更新。)

这是应该显示 JSON 数据的小部件。

class CatalogPage extends StatefulWidget {
  @override
  _CatalogPageState createState() => _CatalogPageState();
}

class _CatalogPageState extends State<CatalogPage>
    with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true; // needed for keepAlive

  @override
  Widget build(BuildContext context) {
    super.build(context); // needed for keepAlive
    bool _loading = Provider.of<Screen1Provider>(context, listen: true).getLoading;
    List _catalogItems =
        Provider.of<Screen1Provider>(context, listen: false).getCatalogItems;
    return Scaffold(
        body: _loading == true
            ? Center(
                child: CircularProgressIndicator(),
              )
            : ListView.builder(
                itemCount: _catalogItems.length,
                itemBuilder: (context, index) {
                  return Card(
                    child: ListTile(
                      title: Text(_catalogItems[index].code.toString()),
                    ),
                  );
                },
              ));
  }

  @override
  void initState() {
    print('hi from catalogPage!');
    Screen1Provider().updateJsonCatalog();
    super.initState();
  }
}

这是上述小部件的提供者数据

class Screen1Provider with ChangeNotifier {
  int _catalogPageIndex = 1;
  int _medidasPageIndex = 0;
  List _itemsCatalog = [];
  List _itemsMedidas = [];
  List _itemsExcluded = [];
  bool _loading = true;

  int get getCatalogPageIndex => _catalogPageIndex;

  bool get getLoading => _loading;

  void setLoading(bool boolean) {
    _loading = boolean;
    notifyListeners();
  }

  void setCatalogPageIndex(int index) {
    _catalogPageIndex = index;
    notifyListeners();
  }

  void setItemsCatalog(data) {
    _itemsCatalog = data;
    print('> setItemsCatalog');
    print(_itemsCatalog[0].code); //printing correctly here as well
    getItemsCatalog;
  }

  List get getItemsCatalog {
    print('> getItemsCatalog');
    if (_itemsCatalog.length > 0) {
      print(_itemsCatalog[0].desc); //printing correctly here as well
    }
    return _itemsCatalog;
  }

  void setItemsMedidasGroup(data) {
    // _itemsMedidas.addAll(data);
    // _itemsMedidas = data;
  }

  void setItemsExcluded(data) {
    // _itemsExcluded.addAll(data);
    // _itemsExcluded = data;
  }

  void updateJsonCatalog() {
    print('updating catalog');
    setLoading(true);
    _itemsCatalog.clear();
    _itemsMedidas.clear();
    _itemsExcluded.clear();

    getJsonCatalog().then((data) {
      setItemsCatalog(data[0]);
      // setItemsMedidasGroup(data[1]);
      // setItemsExcluded(data[2]);
      setLoading(false);
      print('> is loading?: $_loading');
    });
  }

  // Function to get catalog in json
  Future<List> getJsonCatalog() async {
    print('trying to download catalog...');
    List _returnList = [];
    String _url =
        'https://www.dropbox.com/s/qubo8rigrkkvnqm/DummyJsonTest.json?dl=1';
    try {
      var r = await http.get(_url);

      var jsonData = json.decode(r.body);

      // this is used to prevent Price error when it's empty
      // messes up with double.parse formulas
      String tempPrice;

      for (var header in jsonData) {
        if (header["CODIGO"] == '') {
          // skip if empty
          continue;
        }
        if (header["PRECIO"] == '') {
          tempPrice = '0.00';
        } else {
          tempPrice = header["PRECIO"];
        }
        CatalogItems item = CatalogItems(
          header["CODIGO"],
          header["DESCRIPCION"],
          header["INVENT"],
          double.parse(tempPrice).toStringAsFixed(2).toString(),
          header["COD.ALT."],
          header["DESC.ALT."],
          header["GRUPO"],
          (double.parse(tempPrice) * 0.8).toStringAsFixed(2).toString(),
        );
        // only add if item in CatalogItems.groups
        if (CatalogItems.groups.contains(header["GRUPO"])) {
          _itemsCatalog.add(item);
        } else if (CatalogItems.medidaGroups.contains(header["GRUPO"])) {
          _itemsMedidas.add(item);
        } else {
          _itemsExcluded.add(item);
        }
      }
    } catch (e) {
      print('error');
      print(e);
    } finally {
      // this triggers even if catalog failed to download
    }
    // below will NOT trigger if an error was catched
    print('no errors while downloading JSON');
    print('${_itemsCatalog[0].code}|${_itemsCatalog[0].desc}|${_itemsCatalog[0].price}'); // prints correctly here
    _returnList = [_itemsCatalog, _itemsMedidas, _itemsExcluded];
    return _returnList;
  }
}

请告诉我是否有更好的方法来做到这一点,因为我刚刚了解该提供商。

编辑:项目链接[ https://www.dropbox.com/sh/k8v8d730p0qmbvl/AABG1jcPC_Zpu7O2yLk_idmxa?dl=0][1]如果有错误,请注释掉 pubspec.yaml 文件中的资源。

EDIT2:向项目添加了虚拟 json 数据链接,因此请随意运行它。否则这是 json 数据:

[{"CODIGO": "13271190", "DESCRIPCION": "A/A CHE TRAX 13- GITY 2014-
SONI 13396514 95152912 52420930 CUK2", "INVENT": "890", "PRECIO": "3.54", "COD.ALT.": "AC9205", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27274-7J125 SET", "DESCRIPCION": "A/A NIS PATHFINDER NEW 2015 - 2PC 27275-1N605", "INVENT": "637", "PRECIO": "4.42", "COD.ALT.": "AC2503 SET", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27274-EA000 SET", "DESCRIPCION": "A/A NIS FRONTIER VQ40 YD25 PATHFIADER D40 VITARRA J20 27274-EL00A 27277-4JA0A", "INVENT": "1072", "PRECIO": "4.25", "COD.ALT.": "AC2507SET", "DESC.ALT.": "27277-4JA0A GRAN VITARRA J20", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27274-EB700-F SET", "DESCRIPCION": "A/A NIS NAVARA D40T DELGADA 2 PCS CA18320", "INVENT": "1117", "PRECIO": "4.22", "COD.ALT.": "AC22005 SET", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27275-1N601", "DESCRIPCION": "A/A NIS FRONTIER VQ25D -02 QG 16 ZD30 QD32", "INVENT": "314", "PRECIO": "4.95", "COD.ALT.": "AC2502SET", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27277-00A26", "DESCRIPCION": "A/A NIS TIIDA C13 HR16 15- JUKE 2015- HR16DE VERSA 27277-1KA0A", "INVENT": "2061", "PRECIO": "3.65", "COD.ALT.": "AC0182", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27277-1HA0A", "DESCRIPCION": "A/A NIS QASHQAI 13- VERSA 14- MARCH 13- ALMERA 11- K1267 27277-4BA0A", "INVENT": "1777", "PRECIO": "3.82", "COD.ALT.": "AC2513", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27277-1KK0A", "DESCRIPCION": "A/A NIS VERSA 2015- HOT", "INVENT": "2642", "PRECIO": "4.95", "COD.ALT.": "", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27277-3JC1B", "DESCRIPCION": "A/A NI MURANO 14- PATHFINDER 2013- QR25D ALTIMA 12-", "INVENT": "451", "PRECIO": "4.65", "COD.ALT.": "AC0208", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27277-4BA0A", "DESCRIPCION": "A/A NIS XTRAIL 13- RENAULT CA18361 27277-1HA0A", "INVENT": "426", "PRECIO": "3.71", "COD.ALT.": "A2514", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}, {"CODIGO": "27277-4KH0A", "DESCRIPCION": "A/A NI URBAN NV350 12- PASTROL 10- PATHFHANER 16- OF", "INVENT": "1420", "PRECIO": "3.89", "COD.ALT.": "27277-5JJ0A", "DESC.ALT.": "", "GRUPO": "10.FILTRO A/A"}]

Edit3:改进了调试打印,验证了 bool 触发器是否正确。但小部件仍然没有更新(CircularProgressIndicator() 应该只显示 bool 值是否为 false,但它会永远旋转)

I/flutter ( 5948): hi from catalogPage!
I/flutter ( 5948): updating catalog
I/flutter ( 5948): trying to download catalog...
I/flutter ( 5948): > getItemsCatalog
I/flutter ( 5948): no errors, done
I/flutter ( 5948): 13271190|A/A CHE TRAX 13- GITY 2014-   SONI  13396514   95152912  52420930 CUK2|3.54
I/flutter ( 5948): > setItemsCatalog
I/flutter ( 5948): 13271190
I/flutter ( 5948): > getItemsCatalog
I/flutter ( 5948): A/A CHE TRAX 13- GITY 2014-   SONI  13396514   95152912  52420930 CUK2
I/flutter ( 5948): > is loading?: false

最佳答案

错误出现在 CatalogPage() 类中的这段代码中:

  void initState() {
    print('hi from catalogPage!');
    Screen1Provider().updateJsonCatalog();  // <----- The culprit
    super.initState();
  }

我发现它的方法是向 Screen1Provider 添加一个构造函数,如下所示:

Screen1Provider(){
   print("***started provider***");
}

我注意到该行被打印了两次......并且提供者仅在第一次使用后实例化一次。

当您调用 Screen1Provider().updateJsonCatalog() 时,它在 main.dart 文件中的 ChangeNotifierProvider() 之外创建了一个 ScreenProvider 的新实例。这就是破坏notifyListeners调用的原因。为了调用代码,您需要运行:

Provider.of<Screen1Provider>(context, listen: false).updateJsonCatalog();

之后,代码运行得很好......好吧......仍然有一些机会,但我能够看到这一点: enter image description here

哇。这真是一个微妙的错误! (我还通过查看您的代码学到了一些东西......所以它一直都是双赢!

关于即使我测试了数据是否正确,Flutter Provider 也没有更新我的 Widget?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60368340/

相关文章:

listview - 实现 ListTile 时 Flutter Dead code Listview

flutter - Flutter 中的高效 Canvas 渲染

asynchronous - 返回void与返回Future <void>有什么区别?

dart - 如何使用 anchor 布局

android - 应用程序语言更改后的Firebase远程配置即时本地化

flutter - Dart map : Cannot retrieve item from with the same key it was added with

flutter - 支持 srt/vtt 字幕和视频播放器同步同步

dart - 何时在 Dart 小部件中使用 "new"关键字

dart - Windows的dart-protoc-plugin的替代品

dart - import 语句中的 "show"和 "as"有什么区别?