John
John

Reputation: 2801

Call multiple http endpoints concurrently, combine the results and return to a single futurebuilder in dart

I need to call two api endpoints from a single futurebuilder and combine there results into a single return list variable. I can call a single http endpoint and return the results, I'm not sure how to do two separate http calls concurrently from a single request.

Upvotes: 4

Views: 7652

Answers (2)

Logemann
Logemann

Reputation: 2973

Richard Heap's answer is pretty on point and therefore the correct one. If people struggling with testing their scenarios and dont want to do REST calls, i created kind of mock futures where its easy to play with. You can define how long those two futures run and see the results by playing around with the code.

The application should be runnable on the device without changing something.

import 'dart:async';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData.dark(),
      initialRoute: MyHomePage.id,
      routes: {
        MyHomePage.id: (context) => MyHomePage(),
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  static const String id = "HOMESCREEN";

  Future<String> createFuture(String name, int seconds) {
    final c = new Completer<String>();
    new Timer(Duration(seconds: seconds), () {
      c.complete("$name resultString");
    });
    return c.future;
  }

  Future myFutureMethodOverall() async {
    Future<String> future1 = createFuture("Future1", 1); // will take 1 sec
    Future<String> future2 = createFuture("Future2", 3); // will take 3 secs
    return await Future.wait([future1, future2]);
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Container(
          child: FutureBuilder(
              future: myFutureMethodOverall(),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                print(snapshot.connectionState);
                if (snapshot.hasData) {
                  if (snapshot.data != null) {
                    return Container(
                        child:
                            Text("Futures complete with Data ${snapshot.data}"));
                  } else {
                    return Row(
                      children: <Widget>[
                        Container(
                            width: 300,
                            child: Text(
                                "Waiting for both Futures to complete...")),
                        new CircularProgressIndicator(),
                      ],
                    );
                  }
                } else {
                  return Row(
                    children: <Widget>[
                      Container(
                          width: 300,
                          child: Text(
                              "Waiting for both Futures to complete...")),
                      new CircularProgressIndicator(),
                    ],
                  );
                }
              })),
    );
  }
}

At least this code helped me understand better the way futures work when having two of them which should be aligned somehow.

Upvotes: 2

Richard Heap
Richard Heap

Reputation: 51751

Each HTTP request will return a future. In an async method, add both futures to a list. Then wait for both to complete with await Future.wait(theList).

Then process both return codes, bodies, etc, combining the results however you'd like, and return the processed, combined value. In your future builder you'll receive this result.

See Dartlang wait more than one future

For example:

Future<List<Map<String, dynamic>>> getDoubleData() async {
  var value = <Map<String, dynamic>>[];
  var r1 = http.get('https://www.dart.dev');
  var r2 = http.get('https://www.flutter.dev');
  var results = await Future.wait([r1, r2]); // list of Responses
  for (var response in results) {
    print(response.statusCode);
    // todo - parse the response - perhaps JSON
    value.add(json.decode(response.body));
  }
  return value;
}

Upvotes: 8

Related Questions