每 5 分钟或定期刷新 Flutter Text 小部件内容
Posted
技术标签:
【中文标题】每 5 分钟或定期刷新 Flutter Text 小部件内容【英文标题】:Refresh Flutter Text widget content every 5 minutes or periodically 【发布时间】:2019-05-23 23:15:02 【问题描述】:我有一个 Flutter Text
小部件,其内容是通过外部 REST 调用填充的。我想通过调用 REST 端点每 5 分钟定期刷新小部件内容。
到目前为止,我设法每 5 分钟调用一次端点,但无法使用来自网络的新数据更新/刷新小部件内容。
class PatientCount
int count;
double amount;
PatientCount(this.count, this.amount);
PatientCount.fromJson(Map<String, dynamic> map)
: count = map['count'],
amount = map['amount'];
Future<PatientCount> fetchPatientCount() async
var url = "http://localhost:9092/hms/patients-count-on-day";
Map<String, String> requestHeaders = new Map<String, String>();
requestHeaders["Accept"] = "application/json";
requestHeaders["Content-type"] = "application/json";
String requestBody = '"consultedOn":' + '16112018' + '';
http.Response response =
await http.post(url, headers: requestHeaders, body: requestBody);
final statusCode = response.statusCode;
final Map responseBody = json.decode(response.body);
if (statusCode != 200 || responseBody == null)
throw new FetchPatientCountException(
"Error occured : [Status Code : $statusCode]");
return PatientCount.fromJson(responseBody['responseData'].
['PatientCountDTO']);
class MainPage extends StatefulWidget
@override
_MainPageState createState() => _MainPageState();
class _MainPageState extends State<MainPage>
@override
void initState()
super.initState();
setState(()
const oneSecond = const Duration(seconds: 25);
new Timer.periodic(oneSecond, (Timer t) => buildCountWidget());
);
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
elevation: 2.0,
backgroundColor: Colors.white,
title: Text('Dashboard'),
),
body: StaggeredGridView.count(
crossAxisCount: 2,
crossAxisSpacing: 12.0,
mainAxisSpacing: 12.0,
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
children: <Widget>[
_buildTile(
Padding(
padding: const EdgeInsets.all(24.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Today\'s OPD',
style: TextStyle(
color: Colors.blueAccent, fontSize: 18.0),
),
buildCountWidget(),
],
),
Material(
color: Colors.blue,
borderRadius: BorderRadius.circular(24.0),
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Icon(Icons.timeline,
color: Colors.white, size: 30.0),
)))
]),
),
),
],
staggeredTiles: [StaggeredTile.extent(2, 110.0)],
));
Widget _buildTile(Widget child, Function() onTap)
return Material(
elevation: 14.0,
borderRadius: BorderRadius.circular(12.0),
shadowColor: Color(0x802196F3),
child: InkWell(
// Do onTap() if it isn't null, otherwise do print()
onTap: onTap != null
? () => onTap()
: ()
print('Not set yet');
,
child: child));
Widget buildCountWidget()
Widget vistitCount = new Center(
child: new FutureBuilder<PatientCount>(
future: fetchPatientCount(),
builder: (context, snapshot)
if (snapshot.connectionState == ConnectionState.done)
if (snapshot.hasData)
print(snapshot.data.count);
/* below text needs to be updated every 5 mins or so */
return new Text('#' + snapshot.data.count.toString(),
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w700,
fontSize: 34.0));
else if (snapshot.hasError)
return new Text("$snapshot.error");
// By default, show a loading spinner
return new CircularProgressIndicator();
,
),
);
return vistitCount;
在buildCountWidget
方法中,Text 小部件需要使用来自网络的最新数据进行刷新。
我将实现更改为使用 setState 如下,仍然没有运气
class _MainPageState extends State<MainPage>
Future<PatientCount> _patientCount;
Timer timer;
@override
void initState()
super.initState();
callApi();
timer = Timer.periodic(Duration(seconds: 15), (Timer t) => setState(() ));
void callApi()
setState(()
_patientCount = fetchPatientCount();
);
..........................
还更改了如下逻辑,这样我可以调用 REST 端点,但小部件数据不会每 25 秒更新一次。小部件正在显示旧数据。
class _MainPageState extends State<MainPage>
Future<PatientCount> _patientCount;
Timer timer;
@override
void initState()
super.initState();
//callApi();
timer = Timer.periodic(Duration(seconds: 15), (Timer t) => callApi());
void callApi()
setState(()
_patientCount = fetchPatientCount();
);
...........................
根据显示相同计数的代码,计数在 25 秒后不会增加。但是从后端定期触发 Api 并将数据返回到 UI,但小部件的状态没有改变。
【问题讨论】:
您不需要每次都构建小部件。只需将状态变量设置为文本并更新该变量的状态,它将反映为文本。 能否请您详细说明状态变量是什么意思? 【参考方案1】:替换这个:
new Timer.periodic(oneSecond, (Timer t) => buildCountWidget());
通过这个:
new Timer.periodic(oneSecond, (Timer t) => setState(()));
它应该可以工作,每次调用 setState 时它都会刷新小部件并再次调用 Future 方法。
更新
它工作正常,如果您进行这些更改,您会注意到数据是如何刷新的(仅用于测试):
Future<String> fetchPatientCount() async
print("fetchPatientCount");
return DateTime.now().toIso8601String();
...
new FutureBuilder<String>(
future: fetchPatientCount(),
builder: (context, snapshot)
if (snapshot.connectionState == ConnectionState.done)
if (snapshot.hasData)
/* below text needs to be updated every 5 mins or so */
return new Text('#' + snapshot.data.toString(),
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w700,
fontSize:7.0));
else if (snapshot.hasError)
return new Text("$snapshot.error");
如果数据每 25 秒更改一次,则说明它有效,您必须检查您的 fetchPatientCount
方法。 (在发送requestBody
之前将数据编码为json)
【讨论】:
上面提到的解决方案不起作用,数据没有重新加载,只显示旧数据。 不,我在获取数据时没有任何错误,端点正在返回预期值 检查我更新的答案:),如果它有效,那么你在获取数据时出错,不要忘记在发送到 http.post 之前对 requestBody 进行编码 用我的代码替换你的代码,让我知道它是否有效 感谢支持,我已经解决了问题。以上是关于每 5 分钟或定期刷新 Flutter Text 小部件内容的主要内容,如果未能解决你的问题,请参考以下文章