Ryan R
Ryan R

Reputation: 8461

How can I await for data to be returned from a screen or dialog using a FutureBuilder?

I'd like a FutureBuilder to wait for the user to make a selection in a route or dialog (example below) and then return that data to the builder. However, the dialog never appears.

How can I await for data to be returned from a screen or dialog using a FutureBuilder?

DartPad

import 'package:flutter/material.dart';

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

class HomeScreen extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: FutureBuilder(
            future: launch(context),
            builder: (context, snapshot) {
              // use result from screen or dialog in snapshot.data
              return Center(child: Text(snapshot.data));
            }),
      ),
    );
  }

  Future launch(BuildContext context) async {
    return await showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          actions: <Widget>[
            FlatButton(
              child: Text('Send Data'),
              onPressed: () {
                // return some data
                Navigator.pop(context, 'Some data!');
              },
            ),
          ],
          content: Container(child: Text('')),
        );
      },
    );
  }
}

Upvotes: 1

Views: 731

Answers (2)

Yadu
Yadu

Reputation: 3305

Thanks for reverting use the future Completer to get the data from Dialogue

create a Completer instance

var dialogueFuture = Completer();

feed the future of completer to Future builder

FutureBuilder{
future : dialogueFuture.future,
...
}

in show dialogue function complete the Future like this

var theData = await showDialogue(...)
dialogFuture.complete(theData);

see the dartpad here

Upvotes: 2

chunhunghan
chunhunghan

Reputation: 54397

You can copy paste run full code below
Step 1: You need to use addPostFrameCallback
Step 2: move MaterialApp to upper level
Step 3: check ConnectionState
code snippet

@override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {
        _future = launch(context);
      });
    });

    super.initState();
  }

Future<String> launch(BuildContext context) async {
    var result = await showDialog(
     ...

    print("result $result");
    return Future.value(result);
  }

working demo dartpad link

enter image description here

full code

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  Future<String> _future;

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {
        _future = launch(context);
      });
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: FutureBuilder(
            future: _future,
            builder: (context, AsyncSnapshot<String> snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                  return Text('none');
                case ConnectionState.waiting:
                  return Center(child: CircularProgressIndicator());
                case ConnectionState.active:
                  return Text('');
                case ConnectionState.done:
                  if (snapshot.hasError) {
                    return Text(
                      '${snapshot.error}',
                      style: TextStyle(color: Colors.red),
                    );
                  } else {
                    return Center(child: Text("his this is ${snapshot.data}"));
                  }
              }
            }),
      ),
    );
  }

  Future<String> launch(BuildContext context) async {
    var result = await showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          actions: <Widget>[
            FlatButton(
              child: Text('Send Data'),
              onPressed: () {
                // return some data
                Navigator.pop(context, 'Some data!');
              },
            ),
          ],
          content: Container(child: Text('')),
        );
      },
    );

    print("result $result");
    return Future.value(result);
  }
}

Upvotes: 2

Related Questions