Flutter State.initState()必须是没有'async'关键字的void方法

Flutter State.initState()必须是没有'async'关键字的void方法,flutter,dart,Flutter,Dart,@覆盖 Future initState()异步{ //TODO:实现initState super.initState(); _当前位置(); BitmapDescriptor.fromAssetImage( 图像配置(devicePixelRatio:2.5), “assets/fff.png”)。然后((onValue){ pinLocationIcon=onValue; }); //创建自定义标记(上下文); //final Marker=Marker(图标:BitmapDescript

@覆盖
Future initState()异步{
//TODO:实现initState
super.initState();
_当前位置();
BitmapDescriptor.fromAssetImage(
图像配置(devicePixelRatio:2.5),
“assets/fff.png”)。然后((onValue){
pinLocationIcon=onValue;
});
//创建自定义标记(上下文);
//final Marker=Marker(图标:BitmapDescriptor.fromBytes(markerIcon));
DatabaseReference ref=FirebaseDatabase.instance.reference();
ref.child('users').once()。然后((DataSnapshot快照){
映射值=snapshot.value;
打印(values.toString());
forEach值((k,v){
所有标记。添加(标记)(
markerId:markerId(k),
可拖动:错误,
图标:pinLocationIcon,
位置:纬度(v[“纬度”]、经度(v[“经度”),
infoWindow:infoWindow(标题:v[“名称]),
onTap:(){
_在markertapped(v[“name”]);
},
),);
});
});
}
initState
必须是不接受参数并返回
void
的方法。这是因为它覆盖了超类中同名的方法(无论是
无状态小部件
还是
状态
。因此,此限制是一个固定且有约束力的契约;您不能更改它

当然,这也意味着
initState
不能标记为
async
。这是因为标记为
async
的任何方法都将隐式返回
Future
,但如果该方法返回任何内容,则其返回类型不能为
void
,这会破坏覆盖契约

如果需要从
initState
中调用
async
方法,只需不等待它即可:

@覆盖
void initState(){
super.initState();
doSomeAsyncStuff();
}
Future doSomeAsyncStuff()异步{
...
}
但是,如果您需要小部件的
async
方法中的数据,那么您不能简单地等待
未来
返回,然后再构建小部件。Flatter不允许这样做,因为不知道未来返回需要多长时间,而暂停小部件构建直到那时可能会发生错误tially阻止你的整个应用程序

相反,您需要让您的小部件正常构建,然后在
未来
返回时通知您的小部件进行更新。使用
未来构建器
最容易做到这一点:

@覆盖
小部件构建(构建上下文){
回归未来建设者(
future:doSomeAsyncStuff(),
生成器:(上下文,快照){
如果(!snapshot.hasData){
//Future尚未完成,请返回占位符
返回文本(“加载”);
}
返回文本('加载完成:${snapshot.data}');
}
);
}
(请注意,在构建过程中,我不是从
initState
调用
async
方法,而是从
FutureBuilder
调用它。)


编辑:正如所指出的,这种方法只适用于OP的情况,即等待的未来最终总是会返回一个值。情况并非总是如此——有时未来根本不会返回值,只是一个长期运行的过程。有时未来可能返回空值,而不是具体的数据。有时未来可能会返回结果在错误中,而不是成功完成。在任何情况下,
snapshot.data
在将来完成后将为空,在这种情况下,
snapshot.hasData
将始终为假

在这些情况下,您可以使用
snapshot.connectionState
来监视未来本身的状态,而不是依靠
snapshot.hasData
等待数据出现:

@覆盖
小部件构建(构建上下文){
回归未来建设者(
future:doSomeAsyncStuff(),
生成器:(上下文,快照){
if(snapshot.connectionState!=connectionState.done){
//Future尚未完成,请返回占位符
返回文本(“加载”);
}
返回文本(“加载完成”);
}
);
}

您可能正在尝试运行异步函数(可能是带有wait的http请求?)在initstate中,您不能直接执行此操作。如果您发送代码,我们可以提供更多帮助。创建一个单独的异步函数返回Future,然后在initstate中调用该函数。问题的答案是updategreat。我想后者比fire and forget Future更好。顺便说一句,在您的最后一段代码中有一个额外的点(最后第三行)。我是个新手。但根据我的实践,使用
snapshot.connectionState=connectionState.done
有效,因为snapshot.hasData在我看来总是错误的。@Vincent
snapshot.hasData
snapshot.data
不为空时将为真。如果你等待的未来实际上没有返回任何东西或有机会重新创建如果设置为null,则即使在将来完成后,
snapshot.hasData
也可能为false,在这种情况下,您应该使用
snapshot.connectionState
。@Abion47感谢您的解释。
@override
  Future<void> initState() async {
    // TODO: implement initState
    super.initState();
    _current_location();
    BitmapDescriptor.fromAssetImage(
        ImageConfiguration(devicePixelRatio: 2.5),
        'assets/fff.png').then((onValue) {
      pinLocationIcon = onValue;
    });
    //createCustomMarker(context);

   // final Marker marker = Marker(icon: BitmapDescriptor.fromBytes(markerIcon));
    DatabaseReference ref = FirebaseDatabase.instance.reference();
    ref.child('users').once().then((DataSnapshot snapshot) {
      Map<dynamic, dynamic> values = snapshot.value;
      print(values.toString());
      values.forEach((k, v) {
        allMarkers.add(Marker(
          markerId: MarkerId(k),
          draggable: false,
          icon: pinLocationIcon,
          position: LatLng(v["latitude"], v["longitude"]),
          infoWindow: InfoWindow(title: v["name"]),
          onTap: () {
            _onMarkerTapped(v["name"]);
          },
        ),);
      });
    });
  }