Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refresh Flutter Text widget content every 5 minutes or periodically

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.

here the count is not changing every 25 seconds

like image 882
isudarsan Avatar asked Dec 25 '18 04:12

isudarsan


People also ask

How do you refresh widgets on flutter?

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.

How to change text widget text dynamically on button click in flutter?

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.

Is it possible to make a widget refresh every time?

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.

How to rebuild a flutter widget when flutter fails to set theme?

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.

How does flutter display the current state of a widget?

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.


1 Answers

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)

like image 143
diegoveloper Avatar answered Sep 29 '22 04:09

diegoveloper