首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Flutter中的await关键字不是waiting

Flutter中的await关键字不是waiting
EN

Stack Overflow用户
提问于 2020-12-29 00:24:38
回答 2查看 206关注 0票数 2

我正在用一个小的移动应用程序学习Dart和Flutter。我已经阅读了我找到的关于await关键字的所有内容,但我仍然有一些我不理解的问题。下面是简化的代码。为了理解我的问题,我删除了所有我认为不必要的东西。如果遗漏了什么重要的东西,请告诉我。

我的问题是TODO下面的行(第7行):List locations = await _useCaseManager.findLocations();在这个方法中,我查询数据库。我希望应用程序等待,直到查询完成并返回数据。

我在build()方法中调用_findFirstLocation()方法。但Flutter并不等待数据。它继续执行其余的代码,特别是createNextAppointmentsList()方法。在这个方法中,我需要应用程序等待将来使用的数据--属性_selectedLocation。但是因为Flutter不等待,所以_selectedLocation为空。

这是类的相关部分。

代码语言:javascript
运行
复制
class _AppointmentsOverviewScreenState extends State<AppointsmentsOverviewScreen> {
  UseCaseManager _useCaseManager;
  Location _selectedLocation;

  void _findFirstLocation() async {
    // TODO Hier wartet er schon wieder nicht.
    List<Location> locations = await _useCaseManager.findLocations();
    _selectedLocation = locations.first;
    print(_selectedLocation);
  }

  @override
  Widget build(BuildContext context) {
    _useCaseManager = UseCaseManager.getInstance();
    _findFirstLocation();
    
    return Scaffold(
      appBar: AppBar(
        title: Text(LabelConstants.TITLE_APPOINTMENT_OVERVIEW),
      ),
      body: Column(
        children: <Widget>[
          Container(child: createNextAppointmentsList(),)
        ],
      ),
    );
  }

  Widget createNextAppointmentsList() {
    return FutureBuilder<List<Appointment>>(
      future: _useCaseManager.findAppointmentsForActiveGarbageCans(_selectedLocation.locationId),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return ListView.builder(
            itemCount: snapshot.data.length,
            itemBuilder: (BuildContext context, int index) {
              return ListTile(title: Text(snapshot.data[index].garbageCanName),
                subtitle: Text(snapshot.data[index].date),
              );
            },
          );
        } else if (snapshot.hasError) {
          return Text(snapshot.error.toString());
        }
        return Center(child: CircularProgressIndicator());
      },
    );
  }
}

在方法_findFirstLocation中,有以下方法和一个名为的数据库查询。

代码语言:javascript
运行
复制
  Future<List<Location>> findLocations() async {
    final db = await database;

    final List<Map<String, dynamic>> maps = await db.query(DatabaseConstants.LOCATION_TABLE_NAME);
    
    return List.generate(maps.length, (i) {
      Location location = Location(
        locationId: maps[i][DatabaseConstants.COLUMN_NAME_LOCATION_ID],
        street: maps[i][DatabaseConstants.COLUMN_NAME_STREET],
        houseNumber: maps[i][DatabaseConstants.COLUMN_NAME_HOUSENUMBER],
        zipCode: maps[i][DatabaseConstants.COLUMN_NAME_ZIP_CODE],
        city: maps[i][DatabaseConstants.COLUMN_NAME_CITY],
      );
      return location;
    });
  }

因为我已经遇到了await的问题,而导致这些问题的原因是具有lambda表达式的foreach(),所以我尝试了另一种类型的for循环作为替代:

代码语言:javascript
运行
复制
  Future<List<Location>> findLocations() async {
    final db = await database;

    final List<Map<String, dynamic>> maps = await db.query(DatabaseConstants.LOCATION_TABLE_NAME);
    final List<Location> locations = List();

    for (int i = 0; i < maps.length; i++) {
      var locationFromDatabase = maps[i];
      Location location = Location(
          locationId: maps[i][DatabaseConstants.COLUMN_NAME_LOCATION_ID],
          street: maps[i][DatabaseConstants.COLUMN_NAME_STREET],
          houseNumber: maps[i][DatabaseConstants.COLUMN_NAME_HOUSENUMBER],
          zipCode: maps[i][DatabaseConstants.COLUMN_NAME_ZIP_CODE],
          city: maps[i][DatabaseConstants.COLUMN_NAME_CITY],
      );
      locations.add(location);
    }
    return locations;
}

但在这两种情况下,应用程序都没有等待数据,我不明白其中的原因。

提前谢谢你。

克里斯托弗

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-12-29 00:35:14

您的代码中有几个问题:

首先,如果你想' await‘,当你想让流程等待的时候,你必须使用await这个词。您可以在_findFirstLocation()函数中执行此操作,但在调用它时并未执行此操作,因此,您应该这样调用它:

代码语言:javascript
运行
复制
await _findFirstLocation();

但即使这样也是不正确的,因为您正在尝试阻止UI线程,这是完全禁止的(这将导致UI冻结,用户体验很差)。

在这种情况下,您需要的是一个FutureBuilder,您可以在其中指定在后台进程运行时应该发生什么,当它抛出错误时应该发生什么,以及在返回结果时应该发生什么。

最后,我建议您不要在build()方法中初始化变量,因为它可以被多次调用:

代码语言:javascript
运行
复制
_useCaseManager = UseCaseManager.getInstance();

如果可能,我会将其移到类的主体中,如果不可能,则将其放入initState()方法中。

票数 1
EN

Stack Overflow用户

发布于 2020-12-29 00:32:52

在调用方法_findFirstLocation();的地方,不要对它执行await操作。这意味着调用不会等待结果,它只会转到下一条指令并继续执行。

在这种特殊情况下,您实际上不能await它,因为build方法不是async,并且您不能更改它。在这种情况下,您需要一个FutureBuilder来显示微调器或等待对话框,直到加载结果。

您可以在此处找到更多信息:

What is a Future and how do I use it?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65480712

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档