Как я могу дождаться возврата данных с экрана или диалогового окна с использованием FutureBuilder?

#flutter

#flutter

Вопрос:

Я бы хотел, чтобы FutureBuilder дождался, пока пользователь сделает выбор в маршруте или диалоговом окне (пример ниже), а затем вернул эти данные в конструктор. Однако диалоговое окно никогда не появляется.

Как я могу дождаться возврата данных с экрана или диалогового окна с использованием 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('')),
        );
      },
    );
  }
}
  

Ответ №1:

Вы можете скопировать вставить выполнить полный код ниже
Шаг 1: вам нужно использовать addPostFrameCallback
Шаг 2: переход MaterialApp на верхний уровень
Шаг 3: проверка ConnectionState
фрагмент кода

 @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);
  }
  

рабочая демонстрационная ссылка на dartpad

введите описание изображения здесь

полный код

 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);
  }
}
  

Ответ №2:

Спасибо за возврат используйте future Completer для получения данных из диалога

создайте более полный экземпляр

 var dialogueFuture = Completer();
  

передайте future of completer в Future builder

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

в функции показать диалог завершите будущее следующим образом

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

смотрите панель для рисования здесь

Комментарии:

1. Navigator.pop() не возвращает Future, поэтому его нельзя await редактировать.

2. добавлена ссылка на dartpad

3. ShowDialog возвращает Future<bool?>. Это то, чего он ждет.