昨天我制作了一个简单的小部件来获取数据以显示一些基本信息,但我注意到当我弹回列表时,数据通常不存在,我只得到我的错误文本。
我认为这是因为这些小部件最初是无状态的,所以我试图将它们转换为有状态,以便在加载页面时重新加载数据。
这是我收集我的小部件数据的方式:
class BasicDogWidget extends StatefulWidget {
String URL;
BasicDogWidget(this.URL);
@override
createState() => new BasicDogWidgetState(URL);
}
class BasicDogWidgetState extends State<BasicDogWidget> {
String URL;
BasicDogWidgetState(this.URL);
var result;
var imageLink;
var dogName;
var dogType;
var dogColor;
var dogGender;
var dogAge;
@override
initState() {
fetchImageLink(URL).then((result) {
setState(imageLink = result);
});
fetchDogInfo(URL, 'datas-nev').then((result) {
setState(dogName = result);
});
fetchDogInfo(URL, 'datas-tipus').then((result) {
setState(dogType = result);
});
fetchDogInfo(URL, 'datas-szin').then((result) {
setState(dogColor = result);
});
fetchDogInfo(URL, 'datas-nem').then((result) {
setState(dogGender = result);
});
fetchDogInfo(URL, 'datas-kor').then((result) {
setState(dogAge = result);
});
super.initState();
}
@override
Widget build(BuildContext context) {
if (imageLink == null) {
return new Container();
}
if (dogName == null) {
return new Container();
}
if (dogType == null) {
return new Container();
}
if (dogColor == null) {
return new Container();
}
if (dogGender == null) {
return new Container();
}
if (dogAge == null) {
return new Container();
}
return buildBasicWidget(
imageLink, dogName, dogType, dogColor, dogGender, dogAge, URL);
}
}
但是,fetchDogInfo
收集的数据似乎无法在setState
方法中传递,因为它是一个字符串。
E/flutter (12296): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (12296): type 'String' is not a subtype of type 'VoidCallback' of 'fn' where
E/flutter (12296): String is from dart:core
E/flutter (12296):
E/flutter (12296): #0 State.setState (package:flutter/src/widgets/framework.dart:1086)
E/flutter (12296): #1 BasicDogWidgetState.initState.<anonymous closure> (package:osszefogasaszanhuzokert/dog.dart:230)
有没有办法绕过这个问题?
答案 0 :(得分:1)
您正在执行异步代码
fetchImageLink(URL).then((result) {
这意味着fetchImageLink(URL)
最终将返回一个值,然后执行then(...)
,但此调用是异步的,这意味着它被添加到事件队列中以便稍后执行,并且代码同步继续执行,直到initState
然后build
结束,直到此同步代码运行完成,然后执行事件队列中的下一个“任务”,这可能是您的then(...)
部分fetchImageLink()
如果已经完成,则会致电。
但这应该不是问题 您可以检查值是否可用
@override
Widget build(BuildContext context) {
if(imageLink == null) {
return new Container(); // dummy widget until there is something real to render
}
... // your other build code
答案 1 :(得分:1)
Flutter有FutureBuilder级。它提供了一个小部件,可以完成所有繁重工作以支持异步Future对象。 FutureBuilder的优点是可以直接添加到小部件树中,并且根据连接的当前状态,可以显示相关的UI以指示进度,结果或错误。
示例:
class JokePageState extends State<JokePage> {
Future<String> response;
initState() {
super.initState();
response = http.read(dadJokeApi, headers: httpHeaders);
}
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new FutureBuilder<String>(
future: response,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return const Icon(Icons.sync_problem);
case ConnectionState.waiting:
case ConnectionState.active:
return const CircularProgressIndicator();
case ConnectionState.done:
final decoded = json.decode(snapshot.data);
if (decoded['status'] == 200) {
return new Text(decoded['joke']);
} else {
return const Icon(Icons.error);
}
}
},
),
),
);
}
}