[英]How can I use Future builder with provider?
我的主要目标是在获得位置地址placename
之前显示一个CircularProgressIndicator
但我不断收到此错误The getter 'placeName' was called on null.
.我确实尝试检查futureBuilder
中的null
值,但我相信我的实现是错误的。 你能看看吗? 这是我的AppData
类
class AppData extends ChangeNotifier {
Address pickUpLocation;
void updatePickUpLocationAddress(Address pickUpAddress) {
pickUpLocation = pickUpAddress;
notifyListeners();
}
}
这是Address
类
class Address {
String placeFormattedAddress;
dynamic placeName;
String placeId;
double latitude;
double longitude;
Address(
{this.placeFormattedAddress,
this.placeName,
this.placeId,
this.latitude,
this.longitude});
}
现在在我的MainScreen
中,我像这样使用它,但错误仍然存在。
@override
Widget build(BuildContext context) {
\\\
body: Stack(
\\\
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FutureBuilder (
future: Provider.of < AppData > (context)
.pickUpLocation
.placeName,
builder: (context, snapshot) {
if (snapshot.data == null) {
return CircularProgressIndicator();
} else {
return Text(
Provider.of < AppData > (context)
.pickUpLocation
.placeName,
style: TextStyle(fontSize: 12.0),
overflow: TextOverflow.ellipsis,
);
}
}),
],
),
)
有几件事需要注意。
Future
并且它没有被写入这样做。 发生的情况是您的pickUpLocation = pickUpAddress
表达式会立即被评估,因为它是一个同步操作,即在Future
转换为实际值之前。Provider
来返回您正在寻找的Future
(这很好),但是这样做是错误的,因为它基本上会“弄乱”您的 Widget 树:假设您的 Provider和Future 有更新已完成:应该先渲染哪个子树?要解决您的情况,您必须:
Future
;以下是我将如何更改您的提供者模型/类:
class AppData extends ChangeNotifier {
Address? pickUpLocation;
Future<void> updatePickUpLocationAddress() async {
// There should be error handling, as well (try-catch-finally clauses)
var pickUpLocation = await Future.delayed(Duration(seconds: 5)); // I'm mocking a request, here
notifyListeners();
}
}
现在,要初始化 Future,您可以在上面的 Provider 中(在AppData
的构造函数中)执行此操作,或者您必须将 Widget 更改为Stateful
以便我们可以访问initState()
方法,在该方法中我们可以初始化未来无需担心多次调用。 在您的(现在Stateful
的)小部件中:
var myFuture;
// ...
void initState() {
myFuture = Provider.of<AppData>(context).updatePickUpLocationAddress();
}
// ...
Widget build (BuildContext context) {
return // ...
FutureBuilder(
future: myFuture, // already initialized, won't re-initalize when build() is called
builder: (ctx, snapshot) => // ...
}
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (Provider.of < AppData > (context)
.pickUpLocation ==
null)
CircularProgressIndicator(),
if (Provider.of < AppData > (context)
.pickUpLocation !=
null)
Text(
Provider.of < AppData > (context)
.pickUpLocation
.placeName,
style: TextStyle(fontSize: 12.0),
overflow: TextOverflow.ellipsis,
),
),
)
对于遇到此问题的任何人,您可以轻松地在 Mac 上单击 Options+enter,然后单击“使用 Builder 包装”,然后将上下文传递给您未来的函数
child: Builder(
builder: (context) {
return FutureBuilder(
future: futureFunctionHere(context),
builder: (context, AsyncSnapshot snapshot) {
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.