基本上我正在尝试创建一个应用程序,其内容将使用从网站获取信息的异步函数进行更新,但是当我尝试设置新状态时,它不会重新加载新内容。如果我调试应用程序,它会显示当前内容是新内容,但在“重建”整个窗口小部件后,它不会显示新信息。
编辑:loadData()方法,基本上是用http包读取一个URL,该URL包含一个JSON文件,其内容每5分钟就会有新消息发生变化。例如,带有体育实时记分牌的.json文件,其得分总是在变化,所以内容应该随新结果而变化。
class mainWidget extends StatefulWidget
{
State<StatefulWidget> createState() => new mainWidgetState();
}
class mainWidgetState extends State<mainWidget>
{
List<Widget> _data;
Timer timer;
Widget build(BuildContext context) {
return new ListView(
children: _data);
}
@override
void initState() {
super.initState();
timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) async {
String s = await loadData();
this.setState(() {
_data = <Widget> [new childWidget(s)];
});
});
}
}
class childWidget extends StatefulWidget {
childWidget(String s){
_title = s;
}
Widget _title;
createState() => new childState();
}
class childState extends State<gameCardS> {
Widget _title;
@override
Widget build(BuildContext context) {
return new GestureDetector(onTap: foo(),
child: new Card(child: new Text(_title));
}
initState()
{
super.initState();
_title = widget._title;
}
}
答案 0 :(得分:14)
这应该排除你的问题。基本上,您总是希望在build
方法层次结构中创建小部件。
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MaterialApp(home: new Scaffold(body: new MainWidget())));
class MainWidget extends StatefulWidget {
@override
State createState() => new MainWidgetState();
}
class MainWidgetState extends State<MainWidget> {
List<ItemData> _data = new List();
Timer timer;
Widget build(BuildContext context) {
return new ListView(children: _data.map((item) => new ChildWidget(item)).toList());
}
@override
void initState() {
super.initState();
timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) async {
ItemData data = await loadData();
this.setState(() {
_data = <ItemData>[data];
});
});
}
@override
void dispose() {
super.dispose();
timer.cancel();
}
static int testCount = 0;
Future<ItemData> loadData() async {
testCount++;
return new ItemData("Testing #$testCount");
}
}
class ChildWidget extends StatefulWidget {
ItemData _data;
ChildWidget(ItemData data) {
_data = data;
}
@override
State<ChildWidget> createState() => new ChildState();
}
class ChildState extends State<ChildWidget> {
@override
Widget build(BuildContext context) {
return new GestureDetector(onTap: () => foo(),
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
child: new Card(
child: new Container(
padding: const EdgeInsets.all(8.0),
child: new Text(widget._data.title),
),
),
)
);
}
foo() {
print("Card Tapped: " + widget._data.toString());
}
}
class ItemData {
final String title;
ItemData(this.title);
@override
String toString() {
return 'ItemData{title: $title}';
}
}
答案 1 :(得分:9)
这确实让我头疼,并且没有Google结果在起作用。终于奏效的是如此简单。在您的子代中,build()在返回之前将值分配给局部变量。一旦完成此操作,所有工作便可以处理后续的数据加载。我什至取出了initState()代码。
非常感谢@Simon。您的回答以某种方式启发了我尝试这一点。
在您的childState中:
@override
Widget build(BuildContext context) {
_title = widget._title; // <<< ADDING THIS HERE IS THE FIX
return new GestureDetector(onTap: foo(),
child: new Card(child: new Text(_title));
}
希望这在您的代码中有效。对我来说,我将Map用于传入的整个JSON记录,而不是单个String,但这仍然可以工作。
答案 2 :(得分:0)
不要在未来中使用未来;使用不同的函数将像这样分别返回每个未来
List<Requests> requestsData;
List<DocumentSnapshot> requestsDocumentData;
var docId;
@override
void initState() {
super.initState();
getRequestDocs();
}
Future<FirebaseUser> getData() {
var _auth = FirebaseAuth.instance;
return _auth.currentUser();
}
getRequestDocs() {
getData().then((FirebaseUser user) {
this.setState(() {
docId = user.uid;
});
});
FireDb()
.getDocuments("vendorsrequests")
.then((List<DocumentSnapshot> documentSnapshots) {
this.setState(() {
requestsDocumentData = documentSnapshots;
});
});
for (DocumentSnapshot request in requestsDocumentData) {
this.setState(() {
requestsData.add(Requests(
request.documentID,
request.data['requests'],
Icons.data_usage,
request.data['requests'][0],
"location",
"payMessage",
"budget",
"tokensRequired",
"date"));
});
}
}
您可以为
创建单独的功能 FireDb().getDocuments("vendorsrequests")
.then((List<DocumentSnapshot> documentSnapshots) {
this.setState(() {
requestsDocumentData = documentSnapshots;
});
});
和
for (DocumentSnapshot request in requestsDocumentData) {
this.setState(() {
requestsData.add(Requests(
request.documentID,
request.data['requests'],
Icons.data_usage,
request.data['requests'][0],
"location",
"payMessage",
"budget",
"tokensRequired",
"date"));
});
}
我发现使用
this
必须具有setState
答案 3 :(得分:0)
我不确定为什么在异步函数中调用setState(...)
时会发生这种情况,但是一种简单的解决方案是使用:
WidgetsBinding.instance.addPostFrameCallback((_) => setState(...));
不仅仅是setState(...)
答案 4 :(得分:0)
这解决了我的问题...如果您要为变量分配初始值,请在initState()中使用它
注意:当我尝试在构建函数中设置初始值时遇到此问题。
@override
void initState() {
count = widget.initialValue.length; // Initial value
super.initState();
}