One thing I found was using a periodic timer and calling it in the Widget build section, caused a new periodic timer to be created each update. This obviously led to problems with so many calls occurring after a while. What I ended up doing is creating a bool value called _initialUpdate set to false initially. On the 1st build, it calls the async funtion _doUpdate which gets the data then the page is built. After the first go at _doUpdate, the _initialUpdate variable is set to true and a regular timer is called (not periodic) with a callback of _doUpdate. At the end of _doUpdate, the timer is recreated. See code attached:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'data_item_stateful.dart';
import 'page_tag_defs.dart' as tagDefs;
import 'types.dart' as userTypes;
import 'globals.dart' as globals;
int _cnt = 0;
bool _initialUpdate = false;
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Mobile SCADA Test',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MainPage(title: 'Mobile SCADA Test'),
);
}
}
class MainPage extends StatefulWidget {
MainPage({Key key, this.title}) : super(key: key);
final String title;
@override
_MainPageState createState() => new _MainPageState();
}
class _MainPageState extends State<MainPage> {
IconData _appBarIcon;
MaterialColor _appBarColor;
String _appBarMessage = "";
TextStyle _appBarMessageStyle;
_doUpdate() async{
String url = Uri.encodeFull(globals.mainURL);
var response = await http.get(url,headers:{"Accept":"application.json"});
globals.commsStatusCode = response.statusCode;
if (response.statusCode == 200) {
// valid...
globals.commsOK = true;
Map<String, dynamic> data = json.decode(response.body);
List tl = data["tagList"];
List <userTypes.Tag> tLst = [];
tagDefs.tagsMainPage.clear();
double val;
for (int i = 0;i < tl.length;i++) {
if (tl[i]["quality"] == "Good"){
val = tl[i]["value"];
}else{
val = 0.0;
}
userTypes.Tag tTag = new userTypes.Tag(
tl[i]["tagPath"], tl[i]["label"], val, tl[i]["units"], tl[i]["inAlarm"]);
// build the tag list...
tLst.add(tTag);
}
setState(() {
tagDefs.tagsMainPage = tLst;
});
}else{
// error..
print(response.statusCode.toString());
globals.commsOK = false;
new Timer(new Duration(seconds:10),_doUpdate);
}
}
@override
Widget build(BuildContext context) {
// first pass through get data every other time set a timer to trigger the update...
if (_initialUpdate == false){
_doUpdate();
_initialUpdate = true;
}else{
new Timer(new Duration(seconds:10),_doUpdate);
}
IconData _appBarIcon;
MaterialColor _appBarColor;
String _appBarMessage = "";
TextStyle _appBarMessageStyle;
// new Timer.periodic(new Duration(seconds:1), _doUpdate);
if (globals.commsOK){
_appBarIcon = Icons.check;
_appBarColor = Colors.blue;
_appBarMessage = "";
_appBarMessageStyle = new TextStyle(fontSize: 1.0);
}else{
_appBarIcon = Icons.access_alarm;
_appBarColor = Colors.red;
_appBarMessage = "Communications error! Code: " + globals.commsStatusCode.toString();
_appBarMessageStyle = new TextStyle(fontSize: 16.0);
}
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title, style: TextStyle(fontSize: 24.0),),
backgroundColor: _appBarColor,
leading: new Icon(
_appBarIcon,
),
bottom: PreferredSize(
child: new Text(_appBarMessage, style: _appBarMessageStyle
),
)
),
body: new ListView.builder(
padding: new EdgeInsets.all(8.0),
itemExtent: 50.0,
itemCount: tagDefs.tagsMainPage.length,
itemBuilder: (BuildContext context, int index) {
return new DataItem(key: new ObjectKey(index.toString()),
tag: tagDefs.tagsMainPage[index],
color: Colors.blueAccent);
}
)
);
}
}