Невозможно связаться с глобальными переменными в функциях asyn c в Flutter - PullRequest
0 голосов
/ 21 января 2020

Я работаю во Flutter, и у меня проблема с взаимодействием с остальной частью моей программы из асинхронной функции. В спецификациях c я использую http-запрос (который должен быть асинхронной функцией, так что это не вариант по-другому) и пытаюсь (после завершения асинхронизации c) УСТАНОВИТЬ ранее созданную глобальную переменную, равную на часть ответа от http запроса.

Чтобы попытаться разобрать проблему, я создал пример минимального кода из проекта флаттера basi c.

Пример кода, который необходимо выполнить.

String username = 'xxx';
String password = 'xxx';
String basicAuth = 'Basic ' + base64Encode(utf8.encode('$username:$password'));
String url = 'xxx';
String user_phone = '5555555555';
String locationId1 = 'xxx';
String locationId2 = 'xxx';
Map info;



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

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(

        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);


  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(

        title: Text(widget.title),
      ),
      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Session ID:',
            ),
            Text(
              '$sessionID',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: createSessionID,
        tooltip: 'Create Session ID',
        child: Icon(Icons.add),
      ), 
    );
  }
}

Future<void> createSessionID() async {

  http.Response response = await http.post(
    url,
    headers: <String, String>{'authorization': basicAuth},
    body: {'user_phone': user_phone, 'locationId1': locationId1, 'locationId2': locationId2},

  );
  info  = jsonDecode(response.body);
  sessionID = info['session_id'];
  print (info['session_id']);
  return info;
}

По сути, проблема в том, что я могу ПЕЧАТЬ значения на консоли отладки внутри функции asyn c, НО, если я пытаюсь установить для этой глобальной переменной Map что-либо, она постоянно равна нулю и никогда не устанавливается.

Я пытался установить его как Future и вернуть переменную, но это не меняет того факта, что он все еще не установлен должным образом, поскольку он возвращает ноль по неизвестной причине.

Так что в В приведенном выше примере, если я изменю его на:

Future<Map> createTrip() async { 
  <Same Code, but with 

  Map data = jsonDecode(response.body);
  return data;

  > 
}

<void> updateInfo() async {
  info = await createSessionID();
}

И затем напечатаю значения внутри информации, он все равно говорит мне то же самое, что сама информация является нулевой. Er go никогда не устанавливается внутри асинхронной функции. И я просто не понимаю, почему.

Мысли? Идеи?

(Отредактировано дважды, чтобы добавить оригинальный код и устранить путаницу)

Ответы [ 2 ]

0 голосов
/ 20 февраля 2020

Итак, проблема в том, что я не правильно понял концепцию будущего. (И, честно говоря, я, вероятно, до сих пор не понимаю, смеется).

Так что я подумал, что если вы будете ждать ответа, он автоматически изменит Future типа переменной на переменную того типа, который был должно быть.

Этого ... не происходит.

Поэтому вместо этого вам нужно по-разному взаимодействовать с различными частями вашей программы. Решение, которое я в конечном итоге использовал (вероятно, не самое лучшее, но оно работает, поэтому shrug достаточно хорошо для меня) заключалось в том, чтобы использовать глобальные переменные для хранения информации, а затем использовать геттеры, чтобы установить локальную переменную, в которой моя программа нуждается в равной глобальная переменная, для которой использовался вызов сервера.

Вот пример этого:

Map data;  // Set globally, outside the function;

Future<void> createTrip() {
  // Code for server call
  data = jsonDecode(response.body);
  return;
}

Map getData () {
  return data;
}

Таким образом, устраняется проблема с попыткой вернуть будущее и декодировать его. полностью. Опять же, это, вероятно, весьма неэффективно, я предполагаю, что есть лучшие способы сделать это ... Но, по крайней мере, это работает, смеется.

0 голосов
/ 21 января 2020

Я почти уверен, что у вас все правильно, вы просто не говорите Flutter обновить виджет теперь, когда вы обновили значение.

Убедитесь, что вы звоните setState со своим новым назначения.

Future<void> createSessionID() async {

  http.Response response = await http.post(
    url,
    headers: <String, String>{'authorization': basicAuth},
    body: {'user_phone': user_phone, 'locationId1': locationId1, 'locationId2': locationId2},

  );
  info  = jsonDecode(response.body);
  setState(() => sessionID = info['session_id']); // <--------new code
  print (info['session_id']);
  return info;
}
...