【问题标题】:FutureBuilder not waiting for async function to loadFutureBuilder 不等待异步函数加载
【发布时间】:2020-09-02 20:47:25
【问题描述】:

编辑 3:这是现在的样子

  @override
  void initState() {
    super.initState();
    myFuture = genCode();
  }
Future<Uint8List> genCode() async {
print('This should be the start')
Obj o = await _getAsyncData();
print('This should be the end');
return await scanner.generateBarCode(o.str);
}

Future<Obj> _getAsyncData() async {
Obj o = await addObj();
print('Hello');
print(o.str);
return o;
}

Future<Obj> addObj() async {
final String url = 'APIURL';
final client = new http.Client();
final response = await client.post(
url,
headers: {HttpHeaders.contentTypeHeader: 'application/json',
);
print('Obj added. Received response.');
Obj o = Obj.fromJSON(json.decode(response.body));
print(o.str);
return o;
}

打印

I/flutter (12991): This should be the start
I/flutter (12991): This should be the end
I/flutter (12991): Obj added. Received response.
I/flutter (12991): 12345
I/flutter (12991): Hello
I/flutter (12991): 12345

FutureBuilder 小部件直接进入此代码块

if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
}

它显示感叹号并在屏幕上打印:

Error: NoSuchMethodError: The getter 'str' was called on null.
Receiver: null
Tried calling: str

不知何故,它忽略了异步函数仍在后台运行的事实。

FutureBuilder(
                  future: myFuture, // a previously-obtained Future<String> or null
                  builder: (BuildContext context, AsyncSnapshot snapshot) {
                    List<Widget> children;
                    if (snapshot.hasData) {
                      children = <Widget>[
                        QRDisplayWidget(title: '', bytes: snapshot.data),
                      ];
                    } else if (snapshot.hasError) {
                      children = <Widget>[
                        Icon(
                          Icons.error_outline,
                          color: Colors.red,
                          size: 60,
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: 16),
                          child: Text('Error: ${snapshot.error}'),
                        )
                      ];
                    } else {
                      children = <Widget>[
                        SizedBox(
                          child: CircularProgressIndicator(),
                          width: 60,
                          height: 60,
                        ),
                        const Padding(
                          padding: EdgeInsets.only(top: 16),
                          child: Text('Awaiting result...'),
                        )
                      ];
                    }
                    return Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: children,
                      ),
                    );
                  },
                ),

原代码:

错误:参数类型 'Future Function(BuildContext, AsyncSnapshot)' 不能分配给参数类型'Widget Function(BuildContext, AsyncSnapshot)'。

我错过了什么?代码与文档完全相同

                FutureBuilder<String>(
                  future: getQRStr(), // a previously-obtained Future<String> or null
                  builder: (BuildContext context, AsyncSnapshot<String> snapshot) async {
                    List<Widget> children;
                    if (snapshot.hasData) {
                      children = <Widget>[
                        QRDisplayWidget(title: '', bytes: getBytes(snapshot)),
                      ];
                    } else if (snapshot.hasError) {
                      children = <Widget>[
                        Icon(
                          Icons.error_outline,
                          color: Colors.red,
                          size: 60,
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: 16),
                          child: Text('Error: ${snapshot.error}'),
                        )
                      ];
                    } else {
                      children = <Widget>[
                        SizedBox(
                          child: CircularProgressIndicator(),
                          width: 60,
                          height: 60,
                        ),
                        const Padding(
                          padding: EdgeInsets.only(top: 16),
                          child: Text('Awaiting result...'),
                        )
                      ];
                    }
                    return Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: children,
                      ),
                    );
                  },
                ),

编辑:所以我让 FutureBuilder 停止抛出错误,但在获取数据之前仍会检索 String 值。

  Future<String> getQRStr() async{
    String str = await _asyncFetchData();
    return Future.value(str); // return your response
  }

  Future<Uint8List> getBytes(AsyncSnapshot snapshot) async{
    return await scanner.generateBarCode(snapshot.data);
  }

编辑 2: 我把它编辑成我现在所拥有的。如果我在 getBytes 上使用 Future,我会得到 Error: The argument type 'Future&lt;Uint8List&gt;' can't be assigned to the parameter type 'Uint8List'。删除 Future 使其运行编译没有错误,但应用程序似乎陷入了永久刷新的状态,不断调用 getQRStr()。

在 _asyncFetchData 函数下,我有一个打印函数,它在成功检索数据后打印数据,然后返回值。那打印得很好。但 FutureBuilder 打印返回的值为 null。

【问题讨论】:

  • 在您的编辑中,“数据已获取”是什么意思?此外,您无需返回Future.value。你可以做return str
  • 您的编辑似乎描述了一个不同的问题。如果是这样,您应该接受这个问题的答案,并为您的新问题制​​作一个新答案。
  • @ChristopherMoore 为了更清晰,我对其进行了编辑
  • 据我所知,您仍在错误地实现FutureBuilder 中的未来。看我的回答。

标签: flutter dart


【解决方案1】:

您不能将Future 传递给FutureBuilderbuilder 参数。您不能在 builder 中的任何内容上使用 await

作为一种解决方案,您可以创建如下所示的新函数并将其传递给FutureBuilder

Future<Uint8List> genCode() async {
  return await scanner.generateBarCode(await getQRStr());
}

其他部分:

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

    myFuture = genCode();
  }
......
                FutureBuilder(
                  future: myFuture, 
                  builder: (BuildContext context, AsyncSnapshot snapshot) {
                    List<Widget> children;
                    if (snapshot.hasData) {
                      children = <Widget>[
                        QRDisplayWidget(title: '', bytes: snapshot.data),
                      ];
                    } else if (snapshot.hasError) {
                      children = <Widget>[
                        Icon(
                          Icons.error_outline,
                          color: Colors.red,
                          size: 60,
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: 16),
                          child: Text('Error: ${snapshot.error}'),
                        )
                      ];
                    } else {
                      children = <Widget>[
                        SizedBox(
                          child: CircularProgressIndicator(),
                          width: 60,
                          height: 60,
                        ),
                        const Padding(
                          padding: EdgeInsets.only(top: 16),
                          child: Text('Awaiting result...'),
                        )
                      ];
                    }
                    return Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: children,
                      ),
                    );
                  },
                ),

【讨论】:

  • 那我如何让它等待异步scanner.generateBarCode()函数呢?
  • QRDisplayWidget 采用常规 Uint8List。不转换字符串,我得到错误Error: The argument type 'Future&lt;Uint8List&gt;' can't be assigned to the parameter type 'Future&lt;String&gt;'
  • 行future: genCode() 仍然抛出错误Error: The argument type 'Future&lt;Uint8List&gt;' can't be assigned to the parameter type 'Future&lt;String&gt;'
  • 我也通过删除上面的 来修复它。但它仍在进行永久刷新。出于某种原因,它不断地一遍又一遍地调用 getQRStr()。
  • @Josh “永久刷新”是什么意思?
【解决方案2】:

请从您的代码中删除异步,然后重试。 但在这种情况下,您需要处理 QRDisplayWidget 小部件,因为它具有字节等待功能,但您可以在构建器之外声明它然后调用它,如下所示。

getBytes()async{
var snaphot.data;
 await scanner.generateBarCode(snapshot.data)
}    

FutureBuilder<String>(
                      future: getQRStr(), // a previously-obtained Future<String> or null
                      builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
                        List<Widget> children;
                    if (snapshot.hasData) {
                      children = <Widget>[
                        QRDisplayWidget(title: '', bytes: getBytes()),
                      ];
                    } else if (snapshot.hasError) {

【讨论】:

    猜你喜欢
    • 2023-03-13
    • 1970-01-01
    • 2019-11-28
    • 2019-06-16
    • 2018-02-03
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 2020-03-24
    相关资源
    最近更新 更多