Как передать значение обновления пользовательского интерфейса в buildResults SearchDelegate? - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь показать в реальном времени http json данные mtgCardNames, используя buildResults. Кажется, что данные успешно переданы (они распечатаны правильно), но почему-то они не отображаются на экране. Чтобы понять ситуацию, я попытался отобразить некоторые другие данные (поиск query и testList), они отображаются на экране, как и ожидалось.

Почему это происходит?

Я переопределил все необходимые 4 метода, но только кратко вставил buildResults здесь.

  @override
  Widget buildResults(BuildContext context) {
    List<MTGCard> mtgCards = [];
    List<Text> mtgCardNames = [];
    GetHTTP getHTTP = GetHTTP();
    getHTTP.getData().then((usersFromServer) {
      mtgCards = usersFromServer;
      for (MTGCard c in mtgCards){
        print(c.name);    // <= can print out as expected
        mtgCardNames.add(Text(c.name));
      }
    });
    List<Text> testList = [
      Text('a'),
      Text('aa'),
      Text('aaa'),
    ];

    return Column(
      children: <Widget>[
        Text(query),
        Column(
          children: mtgCardNames,
        ),
        Column(
          children: testList,
        ),
      ],
    );
  }

UI

На данный момент http-данные не основаны на запросе, это жестко закодированный URL-адрес, но данные в реальном времени. Я бегу на Ubuntu, и мой трепетный доктор не показывает никаких проблем.

Любое предложение или помощь высоко ценится!

1 Ответ

1 голос
/ 10 апреля 2020

Проблема в том, что сетевой вызов getData() выполняется асинхронно:

1) Вы вызываете getData()

2) Синхронный код продолжает выполняться: return Column(...) вызывается, пока mtgCardNames еще пусто

3) Вы видите пустой столбец на экране

4) Сетевой вызов завершается, then(...) выполняется и mtgCardNames заполняется


Чтобы отобразить столбец с данными сетевого вызова, вы должны вернуть один виджет во время его загрузки, а другой - после. Одним из способов является использование FutureBuilder. Базовая c идея - это

@override
Widget buildResults(BuildContext context) {
  GetHTTP getHTTP = GetHTTP();
  return FutureBuilder<List<MTGCard>>(
    future: getHTTP.getData(),
    builder: (context, snapshot) {
      if (!snapshot.hasData)
        return Text('Loading...');
      return Column(
        children: <Widget>[
          Text(query),
          for (MTGCard c in snapshot.data)
            Text(c.name),
        ],
      );
    },
  );
}

Но есть еще некоторые детали. Например, не стоит помещать сетевой вызов в метод build (). Также вы можете показать некоторые ошибки виджет, если сетевой вызов не удается. Подробности в учебнике

...