I have a Flutter Text
widget and its content is populated from an external REST call.I would like to refresh the widget content periodically every 5 mins by calling the REST endpoint.
So far I managed to call the endpoint every 5 mins but unable to update/refresh the widget content with new data from network.
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;
}
}
Inside the buildCountWidget
method the Text widget needs to be refreshed with the latest data from the network.
I changed the implementation to use setState as below, still no luck
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();
});
}
..........................
Also changed the logic as below, with this I am able to call the REST endpoint but the widget data is not getting updated every 25 seconds.The widget is showing the old data .
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();
});
}
...........................
As per the code it is showing the same count , the count is not getting incremented after 25 seconds.However from the backend the Api is fired periodically and returning the data to UI, but the state to the widget is not changing.
Reload your development server to load your application. Your application should be as responsive to the new changes. Every time you click the icons, Flutter will refresh the keys and force the widget to rebuild.
We could use State update method to Change Text Widget Text Dynamically on Button Click in Flutter Android iOS mobile app. So let’s get started . 1. Import material.dart package in your app’s main.dart file. 2. Create void main runApp () method and call our main Root class MyApp here. 3. Create our main MyApp class extends with State less widget.
You do not need to build widget every time. Just set status variable to text and update status of that variable, it will reflect to text. Could you please elaborate what do you mean by status variable ? And it should work, every time you call setState it'll refresh the widget and will call to the Future method again.
The themeMode property will cause a full rebuild of the application to conform with the specified theme as seen above. Congratulations! You can now rebuild a widget even when Flutter fails to do so. Flutter uses setState() to reference the state object and identify any change to the state.
In this case, Flutter checks and compares the current state of a widget with other widgets within the tree. If it identifies any data change, it will rebuild its widgets, and set the new data to the current widget tree. This way, Flutter will redraw its UI and display the current state of your application.
Replace this :
new Timer.periodic(oneSecond, (Timer t) => buildCountWidget());
By this:
new Timer.periodic(oneSecond, (Timer t) => setState((){}));
And it should work, every time you call setState it'll refresh the widget and will call to the Future method again.
UPDATE
It's working fine, if you make these changes, you will notice how the data is refreshed (just for testing):
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}");
}
}
If the data changes every 25 seconds, it's working , you have to check your fetchPatientCount
method. ( encode the data to json before send requestBody
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With