Flutter:setState 在第一次尝试时工作,但在响应 = 等待后没有工作

Posted

技术标签:

【中文标题】Flutter:setState 在第一次尝试时工作,但在响应 = 等待后没有工作【英文标题】:Flutter: setState working on first try but not after response = await 【发布时间】:2019-08-22 03:17:29 【问题描述】:

我正在尝试在异步 Future 中使用 setState 来更改页面上的某些文本

我尝试在不同的行上设置状态。如果我在Response response = await get 之后设置状态,则不会发生任何事情。

try 
    String barcodeRaw = await BarcodeScanner.scan();
    setState(() => barcode = barcodeRaw); // Works great and gives numbers

    Response response = await 
    get('https://www.datakick.org/api/items/'+barcodeRaw);
    setState(() => barcode = barcodeRaw); // Changes the value but does not change the text

    Map<String, dynamic> barcodeJson = jsonDecode(response.body);
    String barcodeNew = "$barcodeJson['brand_name']";
    setState(() => barcode = barcodeNew); // Changes the value but does not change the text

    print(barcode); // Value is updated correctly

所有 3 个 setState 都更改了“barcode”的值,但只有第一个更改了显示的文本。

【问题讨论】:

我似乎找不到您实际为barcodeRaw 分配新值的位置。另外,如果不知道你的 UI 代码,就很难给出任何建议 我没有发现任何问题。如果最后一次打印的打印内容与您在应用程序上看到的内容不同,那么还有其他问题。您可以在构建函数中添加打印语句/断点,以确保正确的值到达构建函数。 【参考方案1】:

发现问题

通过调用 setState(()),Stateful Widget 将触发构建函数一次

因此,我们需要使用此代码在构建函数完全执行后添加一些“回调”

WidgetsBinding.instance.addPostFrameCallback(someFunction);

完整代码

void firstChange() async 
    try 
    String barcodeRaw = await BarcodeScanner.scan();
    setState(() => barcode = barcodeRaw);

    WidgetsBinding.instance.addPostFrameCallback(secondChange); // bind Callback

    print(barcode); 
     catch (e)
      print("error");
    
  
  void secondChange(Duration duration) async 
    try 
      String barcodeRaw = barcode;
      Response response = await http.get('https://www.datakick.org/api/items/' + barcodeRaw );
      setState(() => barcode = barcodeRaw);

      WidgetsBinding.instance.addPostFrameCallback(thirdChange); // bind Callback

    print(barcode); 
     catch (e)
      print("error");
    
  

  void thirdChange(Duration duration) async 
    try 
      Map<String, dynamic> barcodeJson = jsonDecode(response.body);
      String barcodeNew = "$barcodeJson['brand_name']";
      setState(() => barcode = barcodeNew); 
      print(barcode);
     catch (e)
      print("error");
    
  

演示

我强烈建议你去complete code更好地了解。

在我的示例中,我进行 Future.delayed 调用而不是进行我认为其等效的任何 API 调用或 BarcodeScan。

最佳实践

我建议你看看Provider 包。

我也有你可以自己构建的例子here

并使用 notifyListener 简单性而不是难以管理的多个回调

【讨论】:

如果我注释掉前 2 个 setStates 它仍然不会更新文本。 WidgetsBinding.instance.addPostFrameCallback(thirdChange);不会叫你注释掉前2个setState。所以 thirdChange 函数只会在构建后触发。你可以在这里看到生命周期i.stack.imgur.com/zzElL.png 我添加了我的答案和新的演示,希望它有助于更​​好地理解。您可以自己构建它,因为我分享了它的完整回购

以上是关于Flutter:setState 在第一次尝试时工作,但在响应 = 等待后没有工作的主要内容,如果未能解决你的问题,请参考以下文章

setState Flutter 未获取 onChanged 值

setState() 清除表单元素数据flutter中的数据

Flutter 错误 - 在构建期间调用了 setState() 或 markNeedsBuild()

Flutter - setState 不更新内部有状态小部件

Flutter VideoPlayerController “在构建期间调用了 setState() 或 markNeedsBuild()。”

什么时候在 Flutter 中使用 setState?