Dart 如何在小部件构建方法中调用async属性
我不熟悉颤振和飞镖,我正在尝试构建一个颤振应用程序,在屏幕上显示设备信息。为此,我尝试使用以下库:“设备信息”: 在MyApp类的“build”方法中,我试图实例化“device_info”包中的对象,并调用一个碰巧是异步属性的属性。由于默认的构建方法不是异步的,因此如何在构建方法中调用此属性?以下是我的代码:Dart 如何在小部件构建方法中调用async属性,dart,flutter,Dart,Flutter,我不熟悉颤振和飞镖,我正在尝试构建一个颤振应用程序,在屏幕上显示设备信息。为此,我尝试使用以下库:“设备信息”: 在MyApp类的“build”方法中,我试图实例化“device_info”包中的对象,并调用一个碰巧是异步属性的属性。由于默认的构建方法不是异步的,因此如何在构建方法中调用此属性?以下是我的代码: class MyApp extends StatelessWidget { @override Widget build(BuildContext context) {
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
AndroidDeviceInfo androidDeviceInfo = await deviceInfoPlugin.androidInfo;
return MaterialApp(
title: 'My Device Info',
home: Scaffold(
appBar: AppBar(
title: Text('My Device Info'),
),
body: Center(
child: Text('Device model:' + 'Moto'),
),
),
);
}
}
您可以使用wait/async(作者@Günter Zöchbauer说,根据dart的最新版本,不需要导入lib) 并在生成方法外调用函数
_getAndroidDeviceInfo() async{
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
print(androidInfo.device);
}
_get_iOS_DeviceInfo() async{
IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo;
print(iosDeviceInfo.model);
}
build()
需要同步结果,因此在build()
中使用async
/wait
是不合适的
在异步结果不可用时返回占位符
Container()
的位置使用,或者将异步代码移动到initState()
并在值可用时使用setState
更新状态,以便再次执行build
。我建议您使用FutureBuilder
:
import 'package:flutter/material.dart';
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// save in the state for caching!
DeviceInfoPlugin _deviceInfoPlugin;
@override
void initState() {
super.initState();
_deviceInfoPlugin = DeviceInfoPlugin();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Device Info',
home: Scaffold(
appBar: AppBar(
title: Text('My Device Info'),
),
body: FutureBuilder<AndroidDeviceInfo>(
future: _deviceInfoPlugin.androidInfo,
builder: (BuildContext context, AsyncSnapshot<AndroidDeviceInfo> snapshot) {
if (!snapshot.hasData) {
// while data is loading:
return Center(
child: CircularProgressIndicator(),
);
} else {
// data loaded:
final androidDeviceInfo = snapshot.data;
return Center(
child: Text('Android version: ${androidDeviceInfo.version}'),
);
}
},
),
),
);
}
}
您不必为此导入
dart:async
。有一些类,如StreamSubscription
,Completer
。。。需要进口的地方。在以前的版本中,当您使用类型Stream
和Future
时,它是必需的,但在最新的Dart中,这些类型是从Dart:core
导出的,因此可以自动使用。@GünterZöchbauer-感谢您的帮助。我会更新答案如果你必须返回到构建方法怎么办??异步方法应该始终返回未来的对象。这不是与问题匹配的正确答案。再次查看问题中的问题描述。问题是如何在无状态小部件中调用aync函数。来自@boformer的回答是正确的,即使在这种情况下使用无状态小部件是不可能的。谢谢你,boformer,我能够使用你建议的代码更改构建应用程序。但是,当我在emulator上运行应用程序时,${androidDeviceInfo.version}的值打印文本“AndroidBuilderVersion的实例”。我在这里遗漏了什么吗?没关系,我通过访问AndroidBuildVersion对象的属性修复了上述问题。非常感谢。你救了我在凌晨4点发疯!initState()+setState是FutureBuilder在父对象需要来自其他建筑对象的数据来构建子对象的情况下的最佳选择。好的一面是,initState和setState都不能是异步的…您可以从initState
调用异步的方法。只需将您试图执行的代码移动到另一个函数,并从initState
调用它即可。无需在initState()
中等待它。异步执行完成后,只需调用setState(…)
。
import 'package:flutter/material.dart';
class FooWidget extends StatefulWidget {
@override
_FooWidgetState createState() => _FooWidgetState();
}
class _FooWidgetState extends State<FooWidget> {
Future<int> _bar;
@override
void initState() {
super.initState();
_bar = doSomeLongRunningCalculation();
}
void _retry() {
setState(() {
_bar = doSomeLongRunningCalculation();
});
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
FutureBuilder<int>(
future: _bar,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
if (snapshot.hasData) {
return Text('The answer to everything is ${snapshot.data}');
} else {
return Text('Calculating answer...');
}
},
),
RaisedButton(
onPressed: _retry,
child: Text('Retry'),
)
],
);
}
}
Future<int> doSomeLongRunningCalculation() async {
await Future.delayed(Duration(seconds: 5)); // wait 5 sec
return 42;
}