Flutter 有执行顺序吗?
Is there an execution order sequence in Flutter?
我有问题,我想保存我网站的数据。仅当传输 phone 号码时才应传输此数据。但是我编写的程序并没有从下到上执行,我收到错误消息“抛出了另一个异常: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 条件求助于 false,因为 await 语句暂时返回 null。
更好的解决方案是为此类异步语句使用未来构建器,并在等待异步任务完成时显示进度指示器。
我有问题,我想保存我网站的数据。仅当传输 phone 号码时才应传输此数据。但是我编写的程序并没有从下到上执行,我收到错误消息“抛出了另一个异常: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 条件求助于 false,因为 await 语句暂时返回 null。 更好的解决方案是为此类异步语句使用未来构建器,并在等待异步任务完成时显示进度指示器。