您如何将未来列表转换为列表以用作变量而不是小部件?

How do you convert a list future to a list to use as a variable not a widget?

我正在尝试在 flutter 中实现 PaginatedDataTable class。此 class 的构造函数中的必填字段是 class DataTableSource。查看 flutter gallery 示例 here 的 material 部分中的数据 table 示例。 DataTableSource 有一个名为 List<Dessert> _desserts 的成员变量,它的值是硬编码的。在我的实现中,我进行了一个 http 调用并 returning 一些 json 进行解码。

List<Result> parseResults(String responseBody) {
  final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();

  return parsed.map<Result>((json) => Result.fromJson(json)).toList();
}

Future<List<Result>> fetchResults(http.Client client) async {
  final response = await client.get('https://api.myjson.com/bins/j5xau');

  // Use the compute function to run parseResults in a separate isolate
  return compute(parseResults, response.body);

在我的 DataTableSource class 中,我不确定如何实例化列表。

`final List<Result> results = fetchResults(http.Client);` 

无法编译,因为 fetchResults() return 是未来。如果我将 return 类型更改为 future results 会编译,但我需要我的 returned json 类型为 List 以便我可以使用方法像 sort 等。我应该如何将未来转换为列表。

在您的 DataTableSource class 中,只需删除 results 变量。然后在你的 build 函数中,你可以像这样使用 FutureBuilder 小部件:

FutureBuilder<List<Result>>(
  future: fetchResults(http.Client), 
  builder: (BuildContext context, AsyncSnapshot<List<Result>> snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.none:
        return Text('Press button to start.');
      case ConnectionState.active:
      case ConnectionState.waiting:
        return Text('Awaiting result...');
      case ConnectionState.done:
        if (snapshot.hasError)
          return Text('Error: ${snapshot.error}');
        return Text('Result: ${snapshot.data}');
    }
    return null; // unreachable
  },
)

请注意,snapshot.data 现在是 List<Result>,您可以像使用硬编码值时一样使用它。

编辑:

如果您不想使用 FutureBuilder,我建议您使用一个函数,该函数基本上可以在 http 调用完成时修改 results 的值。这是我的意思的一个例子:

使 DessertDataSource 在其构造函数中接受一个 List<Result> 来定义 results 的值,如下所示:

class DessertDataSource extends DataTableSource {
  final List<Result> results;
  DessertDataSource(this.results);
  // rest of the class
}

_DataTableDemoState中,使_dessertsDataSource不再是final,并将其初始值改为DessertDataSource([])。此外,添加一个布尔值,指示何时加载数据。

class _DataTableDemoState extends State<DataTableDemo> {
  // other fields!
  DessertDataSource _dessertsDataSource = DessertDataSource([]);
  bool isLoaded = false;

然后将下面的函数添加到_DataTableDemoState。布尔值确保我们只进行一次 http 调用。

Future<void> getData() async {
  final results = await fetchResults(http.Client);
  if (!isLoaded) {
      setState(() {
        _dessertsDataSource = DessertDataSource(results);
        isLoaded = true;
      });
  }
}

最终在按下按钮或其他触发器时调用该函数,或者可能就在构建函数的开头。

@override
Widget build(BuildContext context) {
    getData();
    return MYWidget();
}

然后,无论何时从 http 调用返回数据,小部件都会自动更新新数据。