Есть ли во Flutter последовательность выполнения?

У меня проблема, и я хочу сохранить данные с моего сайта. Эти данные должны быть переданы только в том случае, если номер телефона был передан. Но программа, которую я написал, не проходит снизу вверх, и я получаю сообщение об ошибке «Вызвано другое исключение: NoSuchMethodError: метод '[]' был вызван при нулевом значении». В отладчике я увидел, что после «if (!await MobileNumber.hasPhonePermission)» он переходит непосредственно к сборке виджета, где пытается отобразить _loadHtml, который еще не готов. Есть ли способ изменить порядок фьючерсов во Flutter или есть лучшее решение для решения этой проблемы?

Future<void> getDataFromServer() async {
    final responsew = await initMobilNumberState();
    final response = await _fetchSampleData();

    if (response.statusCode == 200) {
      Map<String, dynamic> data = json.decode(response.body);
      _list = data.values.toList();
    } else {
      // If the server did not return a 200 OK response,
      // then throw an exception.
      showAlertNoInternet(context);
      print('Failed to load data from server');
    }
  }

  Future<http.Response> _fetchSampleData() async {
    String s = _mobileNumber;
    print(s);
    return http.get('http://test-site' + _mobileNumber);
  }

  Future<void> initMobilNumberState() async {
    if (!await MobileNumber.hasPhonePermission) {
      await MobileNumber.requestPhonePermission;
      return;
    }
    String mobileNumber = '';

    try {
      mobileNumber = await MobileNumber.mobileNumber;
      _simCard = await MobileNumber.getSimCards;
    } on PlatformException catch (e) {
      debugPrint("Failed to get mobile number because of '${e.message}'");
    }

    if (!mounted) return;
    setState(() {
      var re = RegExp(r'\+[^]*');
      _mobileNumber = mobileNumber.replaceRange(0, 3, ''.replaceAll(re, '+'));
    });
  }


  Widget build(BuildContext context) {
    String _loadHtml(String) {
      return r'''
''' +
          _list[1][0] +
          '''
</body>
</html>
''';
    }

    String _loadHtml2(String) {
      var foo = '';
      for (int i = 0; i < _list[0].length; i++) {
        foo += r'''
          ''' +
            _list[0][i] +
            '''
          </body>
          </html>
          ''';
      }

      return foo;
    }

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Color.fromRGBO(35, 31, 32, 1),
        actions: <Widget>[
          NavigationControls(_controller.future),
        ],
      ),
      body: Builder(builder: (BuildContext context) {

        return WebView(
          initialUrl:

              new Uri.dataFromString(_loadHtml(String), mimeType: 'text/html')
                      .toString() +
                  _loadHtml2(String),

          ///
          javascriptMode: JavascriptMode.unrestricted,
          onWebViewCreated: (WebViewController webViewController) {
            _controller.complete(webViewController);
          },
          javascriptChannels: <JavascriptChannel>[
            _toasterJavascriptChannel(context),
          ].toSet(),

          navigationDelegate: (NavigationRequest request) {
            for (int i = 0; i < _list[2].length; i++) {
              if (request.url.startsWith(_list[2][i])) {
                print('allowing navigation to $request}');
                return NavigationDecision.navigate; //prevent

              }
            }
            return NavigationDecision.prevent;
          },
          onPageStarted: (String url) {
            print('Page started loading: $url');
          },
          onPageFinished: (String url) {
            print('Page finished loading: $url');
          },
          gestureNavigationEnabled: true,
        );
      }),
    );
  }

Обновлять:

  @override
  Widget build(BuildContext context) {
    String _loadHtml(String) {
      return r'''
''' +
          _list[1][0] +
          '''
</body>
</html>
''';
    }

    String _loadHtml2(String) {
      var foo = '';
      for (int i = 0; i < _list[0].length; i++) {
        foo += r'''
          ''' +
            _list[0][i] +
            '''
          </body>
          </html>
          ''';
      }

      return foo;
    }

    FutureBuilder<String>(
      future: getDataFromServer(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return WebView(
            initialUrl:

                /// Hier werden die HTML Strings eingelesen und als Website angezeigt.
                new Uri.dataFromString(_loadHtml(String), mimeType: 'text/html')
                        .toString() +
                    _loadHtml2(String),

            ///
            javascriptMode: JavascriptMode.unrestricted,
            onWebViewCreated: (WebViewController webViewController) {
              _controller.complete(webViewController);
            },
            javascriptChannels: <JavascriptChannel>[
              _toasterJavascriptChannel(context),
            ].toSet(),

            /// In der [navigationDelegate] wird die WhiteList durch einen for loop durchgeangen.
            navigationDelegate: (NavigationRequest request) {
              for (int i = 0; i < _list[2].length; i++) {
                if (request.url.startsWith(_list[2][i])) {
                  print('allowing navigation to $request}');
                  return NavigationDecision.navigate; //prevent

                }
              }
              return NavigationDecision.prevent;
            },
            onPageStarted: (String url) {
              print('Page started loading: $url');
            },
            onPageFinished: (String url) {
              print('Page finished loading: $url');
            },
            gestureNavigationEnabled: true,
          );
        }
        return CircularProgressIndicator();
      },
    );
  }

0
0
468
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что в заявлении:

if (!await MobileNumber.hasPhonePermission)

Этот оператор является асинхронным оператором, т. е. пока он завершается, управление переходит к следующему оператору, а условие if становится ложным, поскольку оператор await на данный момент вернул null. Лучшим решением было бы использовать будущий построитель для таких асинхронных операторов и отображать индикатор выполнения в ожидании завершения асинхронных задач.

Хорошо, спасибо за ответ @Nandan Wewhare. Как это может выглядеть в моем примере? Извините за глупый вопрос, но я никогда раньше не работал с будущим строителем.

MarcelK 17.12.2020 10:45

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

Yadu 17.12.2020 10:48

@Yadu Хорошо, я пытался, но продолжаю получать сообщения об ошибках. Перезагружается, но что-то не так.

MarcelK 17.12.2020 11:17

список или итерация, которую вы используете, имеют значение null, в какой строке возникает ошибка

Yadu 17.12.2020 13:22

@MarcelK проверьте эту ссылку: api.flutter.dev/flutter/widgets/FutureBuilder-class.html. Очень рекомендую посмотреть видео виджета недели.

Nandan Wewhare 17.12.2020 14:04

Другие вопросы по теме