【发布时间】:2021-09-06 03:57:32
【问题描述】:
我已经构建了一个应用程序,我使用这些指令从互联网获取数据https://flutter.dev/docs/cookbook/networking/fetch-data
然后,我向 Web 服务发送一个 http POST 请求,其中的参数取自用户选择,它会即时更新数据。
我可以看到我的这部分工作是在服务器上立即更新 JSON 数据,当我重新启动应用程序时,最新数据会通过。但是,我正在尝试实现一个按钮,该按钮将“实时”刷新此数据,并且它似乎可以工作,但仅当我单击该按钮两次时。
我的(简化的)代码如下:
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:async';
import 'package:intl/intl.dart';
//get Current Date
DateTime now = DateTime.now();
String formattedDate = DateFormat('yyyy-MM-dd').format(now);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// Hide the debug banner
debugShowCheckedModeBanner: false,
title: '',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class Match {
final List matches;
final String date;
final String title;
Match({
required this.matches,
required this.date,
required this.title,
});
factory Match.fromJson(Map<String, dynamic> json) {
return Match(
matches: json['matches'],
date: json['date'],
title: json['title'],
);
}
}
class _HomePageState extends State<HomePage> {
var keyName = "";
var id = "";
final Map myMap = {};
late Future<Match> futureMatch;
@override
void initState() {
super.initState();
futureMatch = readJson();
}
// Fetch content from the json file
Future<Match> readJson() async {
final response =
await http.get(Uri.parse('<myServer/myFile.json>'));
if (response.statusCode == 200) {
return Match.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load data');
}
}
void _showPopup() {
Future<Match> makePostRequest() async {
final response = await http.post(Uri.parse(
'<myServer/myWebService.php?date=' +
formattedDate +
'&id=' +
id +
'&' +
keyName.toString() +
'=' +
myMap[keyName]));
if (response.statusCode == 200) {
return Match.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load data');
}
}
var list = new List<int>.generate(20, (i) => i + 1);
// set up the AlertDialog
MaterialApp gridHolder = MaterialApp(
home: new Align(
alignment: Alignment.center,
child: new Container(
width: 500.0,
height: 500.0,
child: GridView.count(crossAxisCount: 5, children: [
for (var i in list)
GestureDetector(
onTap: () {
myMap[keyName] = i.toString();
makePostRequest();
Navigator.pop(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
},
child: Card(
child: Center(
child: Text(i.toString(),
textAlign: TextAlign.center,
style: TextStyle(fontSize: 40, color: Colors.blue))),
),
),
]),
),
));
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return gridHolder;
},
);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'Matches',
),
),
body: Padding(
padding: const EdgeInsets.all(25),
child: Column(children: [
ElevatedButton(
onPressed: () {
setState(() {
futureMatch = readJson();
});
},
child: Text('Refresh Data'),
),
Padding(
padding: EdgeInsets.only(top: 5),
),
FutureBuilder<Match>(
future: futureMatch,
builder: (context, snapshot) {
if (snapshot.hasData) {
return snapshot.data!.matches.length > 0
? Expanded(
child: ListView.builder(
itemCount: snapshot.data!.matches.length,
itemBuilder: (context, index) {
return Card(
...
);
}),
)
: Container();
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
]),
));
}
}
尤其是这部分似乎不起作用:
ElevatedButton(
onPressed: () {
setState(() {
futureMatch = readJson();
});
},
child: Text('Refresh Data'),
),
请谁能帮我弄清楚为什么我需要按两次按钮才能获取最新数据?
谢谢!
【问题讨论】:
-
setState 立即重建,但 readJson 返回一个 Future,因此它需要一些时间来获取数据。将您的函数切换为异步,然后在 setState() 之前等待 readJson。你可以试试这个: ElevatedButton( onPressed: () async { futureMatch = await readJson(); setState(() { }); }, child: Text('Refresh Data'), ),
-
@SuatÖzkaya 感谢您的回复!我已经尝试过了,但得到错误“无法将“匹配”类型的值分配给“未来”类型的变量。一旦我删除“等待”,就再也没有错误了,你知道这是为什么吗?谢谢
标签: flutter dart setstate http-get