У меня проблема, и я хочу сохранить данные с моего сайта. Эти данные должны быть переданы только в том случае, если номер телефона был передан. Но программа, которую я написал, не проходит снизу вверх, и я получаю сообщение об ошибке «Вызвано другое исключение: 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();
},
);
}
Проблема в том, что в заявлении:
if (!await MobileNumber.hasPhonePermission)
Этот оператор является асинхронным оператором, т. е. пока он завершается, управление переходит к следующему оператору, а условие if становится ложным, поскольку оператор await на данный момент вернул null. Лучшим решением было бы использовать будущий построитель для таких асинхронных операторов и отображать индикатор выполнения в ожидании завершения асинхронных задач.
поищите, как использовать Future Builder во флаттере, уже существует много ответов, одна вещь во флаттере: вы не можете дождаться поступления данных перед созданием пользовательского интерфейса, но вы можете обновить пользовательский интерфейс после поступления данных.
@Yadu Хорошо, я пытался, но продолжаю получать сообщения об ошибках. Перезагружается, но что-то не так.
список или итерация, которую вы используете, имеют значение null, в какой строке возникает ошибка
@MarcelK проверьте эту ссылку: api.flutter.dev/flutter/widgets/FutureBuilder-class.html. Очень рекомендую посмотреть видео виджета недели.
Хорошо, спасибо за ответ @Nandan Wewhare. Как это может выглядеть в моем примере? Извините за глупый вопрос, но я никогда раньше не работал с будущим строителем.