首页 > 解决方案 > FutureBuilder 不等待异步函数加载

问题描述

编辑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<Uint8List>' can't be assigned to the parameter type 'Uint8List'. 删除 Future 使其运行编译没有错误,但应用程序似乎陷入了永久刷新的状态,不断调用 getQRStr()。

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

标签: flutterdart

解决方案


您不能将 a传递Future给. 你不能在.builderFutureBuilderawaitbuilder

作为一种解决方案,您可以创建一个如下所示的新函数并将其传递给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,
                      ),
                    );
                  },
                ),

推荐阅读