flutter Dart Future.等待多个Future并返回不同类型的结果

juzqafwq  于 2022-11-17  发布在  Flutter
关注(0)|答案(5)|浏览(357)

我使用Flutter从服务器上下载了3组不同的数据,然后对这3组数据进行处理。我可以这样做:

List<Foo> foos = await downloader.getFoos();
List<Bar> bars = await downloader.getBars();
List<FooBars> foobars = await downloader.getFooBars();

processData(foos, bars, foobars);

但我更喜欢异步并行下载所有3个数据集。我已经看到Dart有这样的Future.wait method

Future<List<T>> wait <T>(
   Iterable<Future<T>> futures, {
   bool eagerError: false, 
   void cleanUp(
      T successValue
   )
})

然而,它看起来只会返回相同类型(T)的值。我有3个不同的类型,所以我不知道如何使用它,并得到我的3个数据集回来。
实现这一目标的最佳替代方法是什么?
谢谢你!

thigvfpy

thigvfpy1#

您需要将每个Future<T>修改为Future的公共类型。您可以使用Future<void>并分配结果,而不是依赖于返回值:

late List<Foo> foos;
late List<Bar> bars;
late List<FooBars> foobars;

await Future.wait<void>([
  downloader.getFoos().then((result) => foos = result),
  downloader.getBars().then((result) => bars = result),
  downloader.getFooBars().then((result) => foobars = result),
]);

processData(foos, bars, foobars);

或者,如果您更喜欢await而不是.then(),则Future.wait调用可以是:

await Future.wait<void>([
  (() async => foos = await downloader.getFoos())(),
  (() async => bars = await downloader.getBars())(),
  (() async => foobars = await downloader.getFooBars())(),
]);
i7uaboj4

i7uaboj42#

我认为正确的答案是使用官方的async包和FutureGroup

void main()  {
  Future<String> future1 = getData(2);
  Future<String> future2 = getData(4);
  Future<String> future3 = getData(6);
  FutureGroup futureGroup = FutureGroup();
  futureGroup.add(future1);
  futureGroup.add(future2);
  futureGroup.add(future3);
  futureGroup.close();
  futureGroup.future.then((value) => {print(value)});
}

Future<String> getData(int duration) async {
  await Future.delayed(Duration(seconds: duration)); //Mock delay
  return "This a test data";
}
v64noz0r

v64noz0r3#

我认为这是不可能做到的,你能做的就是这样:

void main() async {
  List<List<dynamic>> result = await Future.wait<List<dynamic>>([
    getStringData(),
    getIntData(),
  ]);

  print(result[0]);
  print(result[1]);
}

Future<List<String>> getStringData() {
  return Future.value(["a", "b"]);
}

Future<List<int>> getIntData() {
  return Future.value([1, 2]);
}
mepcadol

mepcadol4#

我做了一个helper函数,它利用了其他答案中的一些逻辑。它使用tuple包,但是你可以很容易地自己编写它(包括在下面)。

// Put this in future_utils.dart

/// Represents a 2-tuple, or pair.
class Tuple2<T1, T2> {
  /// Returns the first item of the tuple
  final T1 item1;

  /// Returns the second item of the tuple
  final T2 item2;

  /// Creates a new tuple value with the specified items.
  const Tuple2(this.item1, this.item2);
}

Future<Tuple2<T1, T2>> await2<T1, T2>(
    Future<T1> Function() firstFuture,
    Future<T2> Function() secondFuture) async {
  late T1 item1;
  late T2 item2;
  await Future.wait<void>([
    (() async => item1 = await firstFuture())(),
    (() async => item2 = await secondFuture())(),
  ]);
  return Tuple2(item1, item2);
}

便叫它:

Future<List<Foo>> foos = downloader.getFoos;
Future<List<Bar>> bars = downloader.getBars;

// Will run in parallel
Tuple2<List<Foo>, List<Bar>> results = await await2(foos, bars);
// Do stuff with the results since both are complete
print(results.item1[0]);
print(results.item2[0]);

现在如果你想要一个3个参数,4个,或者更多,你可以复制并粘贴(await3await4)。这不是一个太疯狂的模式,我已经用它为multiple lets in Kotlin和元组库我链接。

oxcyiej7

oxcyiej75#

类型T是泛型类型
你知道你的类型,所以你可以和他们一起工作。
如果您使用的是FutureBuilder,则可以使用此方法访问不同的结果。(与您在Future.wait方法中放置它们的顺序相同)

snapshot.data[0] // maybe type List<Foo>
snapshot.data[1] // maybe type List<Bar>
snapshot.data[2] // maybe type String

相关问题