如何在Flutter中等待未来对象再继续执行?

9

我正在使用Flutter编写一段代码,其中使用了SQFlite数据库。我想从资产中插入图像小部件,并且我从数据库中获取了该图像的名称。

    @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Single Line diagram"),backgroundColor: Colors.red.shade700,),
      body: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Align(
          //alignment: Alignment.center,
          child: SingleChildScrollView(
            scrollDirection: Axis.vertical,
            child: Row(
              //crossAxisAlignment: CrossAxisAlignment.center,
              children: imageList(),
            ),
          ),
        )
      ),
    );
  }

上面的代码调用imageList()来显示图像列表。
List<Widget> imageList(){
    List<Widget> singleLineImages = new List();
    List unit;
    for (int i = 0; i <= widget.unitsList.length-1; i++){
      for (int j = 1; j <= int.parse(widget.unitsList[i].quantity); j++){
        print("${widget.unitsList[i].bulletin}, ${widget.unitsList[i].mountType}, ${widget.unitsList[i].disconnect}");
        getfileName(widget.unitsList[i].bulletin, widget.unitsList[i].mountType, widget.unitsList[i].disconnect);
        //if(fileName != null) {
          singleLineImages.add(
              Image.asset("images/SD_Files_2100/$fileName.jpg", height: 400.0, width: 200.0,));
        //}
      }
    }
    return singleLineImages;
  }

我从使用数据库的getFileName()方法中获取文件名。

getfileName(String bulletin, String mountType, String disconnect)async {
    fileNameList = await db.getSDfileName(bulletin, disconnect, mountType);
    fileName = fileNameList[0]['FileName'];
    print("filename: $fileName");
  }

现在,在调用了getFileName()函数之后,程序不会等待获取fileName而是继续进行,这导致filename的值为null。在执行Image.asset代码后可以正确获取filename。有没有办法让程序等待直到获取到正确的filename?

请查看以下内容:异步编程:Futures - pskink
2
使用FutureBuilder或在initState中调用一个方法来调用异步代码,当Future完成时调用setState()以使用新值重新构建。在StackOverflow上有大量类似的问题。(非常常见的问题) - Günter Zöchbauer
有没有办法让程序等待直到它得到正确的文件名?不,没有办法等待Future完成。Dart是单线程的(除非您启动了其他隔离),这将不允许阻塞执行,因为那么Future永远无法完成,因为它也在被阻塞的线程上运行。 - Günter Zöchbauer
2个回答

7

initState()中开始获取列表,并在列表获取完成时异步调用setState。以下是此过程的简化示例。请注意,在获取文件名之前使用了await语句。这确保了代码执行完毕后返回到该代码段。

class ListPage extends StatefulWidget {
  @override
  _ListPageState createState() => _ListPageState();
}

class _ListPageState extends State<ListPage> {
  // This should actually be a List<MyClass> instead of widgets. 
  List<Widget> _list;

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

  Future _fetchList() async {
    List<Widget> singleLineImages = new List();
    List unit;
    for (int i = 0; i <= widget.unitsList.length-1; i++){
      for (int j = 1; j <= int.parse(widget.unitsList[i].quantity); j++){
        print("${widget.unitsList[i].bulletin}, ${widget.unitsList[i].mountType}, ${widget.unitsList[i].disconnect}");
        String fileName = await getfileName(widget.unitsList[i].bulletin, widget.unitsList[i].mountType, widget.unitsList[i].disconnect);
      singleLineImages.add(
          Image.asset("images/SD_Files_2100/$fileName.jpg", height: 400.0, width: 200.0,));
      }
    }

    // call setState here to set the actual list of items and rebuild the widget.
    setState(() {
      _list = singleLineImages;
    });
  }

  @override
  Widget build(BuildContext context) {
    // Build the list, or for example a CircularProcessIndicator if it is null.
  }
}

顺便提一下,你正在对数据库进行大量的调用,这可能是低效的。尝试通过单个数据库调用获取所需数据。但这是另一个话题。


0

在你的类中保留 Future<Widget> _list; 字段。

initState() 函数中添加 _list = _fetchList();。 还要注意,在这种情况下,_fetchList 应该返回 Future<Widget>。 在你的构建函数中使用 FutureBuilder


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接